kmail

kmfolderseldlg.cpp

Go to the documentation of this file.
00001 // kmfolderseldlg.cpp
00002 
00003 #include <config.h>
00004 #include "kmfolderseldlg.h"
00005 #include "kmfoldertree.h"
00006 #include "kmfolder.h"
00007 #include "kmmainwidget.h"
00008 #include "globalsettings.h"
00009 
00010 #include <kdebug.h>
00011 #include <klineedit.h>
00012 #include <kpopupmenu.h>
00013 #include <kiconloader.h>
00014 
00015 #include <qlayout.h>
00016 #include <qtoolbutton.h>
00017 
00018 namespace KMail {
00019 
00020 class FolderItem : public KFolderTreeItem
00021 {
00022   public:
00023     FolderItem( KFolderTree * listView );
00024     FolderItem( KFolderTreeItem * listViewItem );
00025 
00026     void setFolder( KMFolder * folder ) { mFolder = folder; };
00027     const KMFolder * folder() { return mFolder; };
00028 
00029     // Redefine isAlternate() for proper row coloring behavior.
00030     // KListViewItem::isAlternate() is not virtual!  Therefore,
00031     // it is necessary to overload paintCell() below.  If it were
00032     // made virtual, paintCell() would no longer be necessary.
00033     bool isAlternate () {
00034       return mAlternate;
00035     }
00036 
00037     // Set the flag which determines if this is an alternate row
00038     void setAlternate ( bool alternate ) {
00039       mAlternate = alternate;
00040     }
00041 
00042     // Must overload paintCell because neither KListViewItem::isAlternate()
00043     // or KListViewItem::backgroundColor() are virtual!
00044     virtual void paintCell( QPainter *p, const QColorGroup &cg,
00045                              int column, int width, int alignment )
00046     {
00047       KListView* view = static_cast< KListView* >( listView() );
00048 
00049       // Set alternate background to invalid
00050       QColor nocolor;
00051       QColor alt = view->alternateBackground();
00052       view->setAlternateBackground( nocolor );
00053 
00054       // Set the base and text to the appropriate colors
00055       QColorGroup *cgroup = (QColorGroup *)&view->viewport()->colorGroup();
00056       QColor base = cgroup->base();
00057       QColor text = cgroup->text();
00058       cgroup->setColor( QColorGroup::Base, isAlternate() ? alt : base );
00059       cgroup->setColor( QColorGroup::Text, isEnabled() ? text : Qt::lightGray );
00060 
00061       // Call the parent paint routine
00062       KListViewItem::paintCell( p, cg, column, width, alignment );
00063 
00064       // Restore the base and alternate background
00065       cgroup->setColor( QColorGroup::Base, base );
00066       cgroup->setColor( QColorGroup::Text, text );
00067       view->setAlternateBackground( alt );
00068     }
00069 
00070   private:
00071     KMFolder * mFolder;
00072     bool mAlternate;
00073 };
00074 
00075 //-----------------------------------------------------------------------------
00076 FolderItem::FolderItem( KFolderTree * listView )
00077   : KFolderTreeItem( listView ),
00078     mFolder( 0 )
00079 {}
00080 
00081 //-----------------------------------------------------------------------------
00082 FolderItem::FolderItem( KFolderTreeItem * listViewItem )
00083   : KFolderTreeItem( listViewItem ),
00084     mFolder( 0 )
00085 {}
00086 
00087 //-----------------------------------------------------------------------------
00088 SimpleFolderTree::SimpleFolderTree( QWidget * parent,
00089                                     KMFolderTree * folderTree,
00090                                     const QString & preSelection,
00091                                     bool mustBeReadWrite )
00092   : KFolderTree( parent ), mFolderTree( folderTree )
00093 {
00094   setSelectionModeExt( Single );
00095   mFolderColumn = addColumn( i18n( "Folder" ), 0 );
00096   mPathColumn = addColumn( i18n( "Path" ), 0 );
00097   setAllColumnsShowFocus( true );
00098   setAlternateBackground( QColor( 0xf0, 0xf0, 0xf0 ) );
00099 
00100   reload( mustBeReadWrite, true, true, preSelection );
00101   readColorConfig();
00102 
00103   applyFilter( "" );
00104 
00105   connect(this, SIGNAL(collapsed(QListViewItem*)), SLOT(recolorRows()));
00106   connect(this, SIGNAL(expanded(QListViewItem*)),  SLOT(recolorRows()));
00107 
00108   connect( this, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint &, int ) ),
00109            this, SLOT( slotContextMenuRequested( QListViewItem*, const QPoint & ) ) );
00110 }
00111 
00112 //-----------------------------------------------------------------------------
00113 void SimpleFolderTree::reload( bool mustBeReadWrite, bool showOutbox,
00114                                bool showImapFolders, const QString& preSelection )
00115 {
00116   mLastMustBeReadWrite = mustBeReadWrite;
00117   mLastShowOutbox = showOutbox;
00118   mLastShowImapFolders = showImapFolders;
00119 
00120   clear();
00121   FolderItem * lastItem = 0;
00122   FolderItem * lastTopItem = 0;
00123   FolderItem * selectedItem = 0;
00124   int lastDepth = 0;
00125 
00126   QString selected = preSelection;
00127   if ( selected.isEmpty() && folder() )
00128     selected = folder()->idString();
00129 
00130   mFilter = "";
00131   QString path;
00132 
00133   for ( QListViewItemIterator it( mFolderTree ) ; it.current() ; ++it )
00134   {
00135     KMFolderTreeItem * fti = static_cast<KMFolderTreeItem *>( it.current() );
00136 
00137     // search folders are never shown
00138     if ( !fti || fti->protocol() == KFolderTreeItem::Search )
00139       continue;
00140 
00141     // imap folders?
00142     if ( fti->protocol() == KFolderTreeItem::Imap && !showImapFolders )
00143       continue;
00144 
00145     // the outbox?
00146     if ( fti->type() == KFolderTreeItem::Outbox && !showOutbox )
00147       continue;
00148 
00149     int depth = fti->depth();// - 1;
00150     FolderItem * item = 0;
00151     if ( depth <= 0 ) {
00152       // top level - first top level item or after last existing top level item
00153       item = new FolderItem( this );
00154       if ( lastTopItem )
00155         item->moveItem( lastTopItem );
00156       lastTopItem = item;
00157       depth = 0;
00158       path  = "";
00159     }
00160     else {
00161       if ( depth > lastDepth ) {
00162         // next lower level - parent node will get opened
00163         item = new FolderItem( lastItem );
00164         lastItem->setOpen(true);
00165       }
00166       else {
00167         path = path.section( '/', 0, -2 - (lastDepth-depth) );
00168 
00169         if ( depth == lastDepth ) {
00170           // same level - behind previous item
00171           item = new FolderItem( static_cast<FolderItem*>(lastItem->parent()) );
00172           item->moveItem( lastItem );
00173         } else if ( depth < lastDepth ) {
00174           // above previous level - might be more than one level difference
00175           // but highest possibility is top level
00176           while ( ( depth <= --lastDepth ) && lastItem->parent() ) {
00177             lastItem = static_cast<FolderItem *>( lastItem->parent() );
00178           }
00179           if ( lastItem->parent() ) {
00180             item = new FolderItem( static_cast<FolderItem*>(lastItem->parent()) );
00181             item->moveItem( lastItem );
00182           } else {
00183             // chain somehow broken - what does cause this ???
00184             kdDebug( 5006 ) << "You shouldn't get here: depth=" << depth
00185                             << "folder name=" << fti->text( 0 ) << endl;
00186             item = new FolderItem( this );
00187             lastTopItem = item;
00188           }
00189         }
00190       }
00191     }
00192 
00193     if ( depth > 0 )
00194       path += "/";
00195     path += fti->text( 0 );
00196 
00197     item->setText( mFolderColumn, fti->text( 0 ) );
00198     item->setText( mPathColumn, path );
00199 
00200     item->setProtocol( fti->protocol() );
00201     item->setType( fti->type() );
00202 
00203     // Make items without folders and readonly items unselectable
00204     // if we're told so
00205     if ( mustBeReadWrite && ( !fti->folder() || fti->folder()->isReadOnly() ) ) {
00206       item->setSelectable( false );
00207     } else {
00208       if ( fti->folder() ) {
00209         item->setFolder( fti->folder() );
00210         if ( selected == item->folder()->idString() )
00211           selectedItem = item;
00212       }
00213     }
00214     lastItem = item;
00215     lastDepth = depth;
00216   }
00217 
00218   if ( selectedItem ) {
00219     setSelected( selectedItem, true );
00220     ensureItemVisible( selectedItem );
00221   }
00222 }
00223 
00224 //-----------------------------------------------------------------------------
00225 const KMFolder * SimpleFolderTree::folder() const
00226 {
00227   QListViewItem * item = currentItem();
00228   if ( item ) {
00229     const KMFolder * folder = static_cast<FolderItem *>( item )->folder();
00230     if( folder ) return folder;
00231   }
00232   return 0;
00233 }
00234 
00235 //-----------------------------------------------------------------------------
00236 void SimpleFolderTree::setFolder( KMFolder *folder )
00237 {
00238   for ( QListViewItemIterator it( this ) ; it.current() ; ++it )
00239   {
00240     const KMFolder *fld = static_cast<FolderItem *>( it.current() )->folder();
00241     if ( fld == folder )
00242     {
00243       setSelected( it.current(), true );
00244       ensureItemVisible( it.current() );
00245     }
00246   }
00247 }
00248 
00249 //-----------------------------------------------------------------------------
00250 void SimpleFolderTree::setFolder( const QString& idString )
00251 {
00252   setFolder( kmkernel->findFolderById( idString ) );
00253 }
00254 
00255 //-----------------------------------------------------------------------------
00256 void SimpleFolderTree::addChildFolder()
00257 {
00258   const KMFolder *fld = folder();
00259   if ( fld ) {
00260     mFolderTree->addChildFolder( (KMFolder *) fld, parentWidget() );
00261     reload( mLastMustBeReadWrite, mLastShowOutbox, mLastShowImapFolders );
00262     setFolder( (KMFolder *) fld );
00263   }
00264 }
00265 
00266 //-----------------------------------------------------------------------------
00267 void SimpleFolderTree::slotContextMenuRequested( QListViewItem *lvi,
00268                                                  const QPoint &p )
00269 {
00270   if (!lvi)
00271     return;
00272   setCurrentItem( lvi );
00273   setSelected( lvi, TRUE );
00274 
00275   const KMFolder * folder = static_cast<FolderItem *>( lvi )->folder();
00276   if ( !folder || folder->noContent() || folder->noChildren() )
00277     return;
00278 
00279   KPopupMenu *folderMenu = new KPopupMenu;
00280   folderMenu->insertTitle( folder->label() );
00281   folderMenu->insertSeparator();
00282   folderMenu->insertItem(SmallIconSet("folder_new"),
00283                           i18n("&New Subfolder..."), this,
00284                           SLOT(addChildFolder()));
00285   kmkernel->setContextMenuShown( true );
00286   folderMenu->exec (p, 0);
00287   kmkernel->setContextMenuShown( false );
00288   delete folderMenu;
00289   folderMenu = 0;
00290 }
00291 
00292 //-----------------------------------------------------------------------------
00293 void SimpleFolderTree::readColorConfig (void)
00294 {
00295   QColor c1=QColor(kapp->palette().active().text());
00296   QColor c2=QColor(kapp->palette().active().base());
00297 
00298   mPaintInfo.colFore = c1;
00299   mPaintInfo.colBack = c2;
00300 
00301   QPalette newPal = kapp->palette();
00302   newPal.setColor( QColorGroup::Base, mPaintInfo.colBack );
00303   newPal.setColor( QColorGroup::Text, mPaintInfo.colFore );
00304   setPalette( newPal );
00305 }
00306 
00307 
00308 //-----------------------------------------------------------------------------
00309 static int recurseFilter( QListViewItem * item, const QString& filter, int column )
00310 {
00311   if ( item == 0 )
00312     return 0;
00313 
00314   QListViewItem * child;
00315   child = item->firstChild();
00316 
00317   int enabled = 0;
00318   while ( child ) {
00319     enabled += recurseFilter( child, filter, column );
00320     child = child->nextSibling();
00321   }
00322 
00323   if ( filter.length() == 0 ||
00324        item->text( column ).find( filter, 0, false ) >= 0 ) {
00325     item->setVisible( true );
00326     ++enabled;
00327   }
00328   else {
00329     item->setVisible( !!enabled );
00330     item->setEnabled( false );
00331   }
00332 
00333   return enabled;
00334 }
00335 
00336 void SimpleFolderTree::recolorRows()
00337 {
00338   // Iterate through the list to set the alternate row flags.
00339   int alt = 0;
00340   QListViewItemIterator it ( this );
00341   while ( it.current() ) {
00342     FolderItem * item = static_cast< FolderItem* >( it.current() );
00343 
00344     if ( item->isVisible() ) {
00345       bool visible = true;
00346       QListViewItem * parent = item->parent();
00347       while ( parent ) {
00348         if (!parent->isOpen()) {
00349           visible = false;
00350           break;
00351         }
00352         parent = parent->parent();
00353       }
00354 
00355       if ( visible ) {
00356         item->setAlternate( alt );
00357         alt = !alt;
00358       }
00359     }
00360 
00361     ++it;
00362   }
00363 }
00364     
00365 void SimpleFolderTree::applyFilter( const QString& filter )
00366 {
00367   // Reset all items to visible, enabled, and open
00368   QListViewItemIterator clean( this );
00369   while ( clean.current() ) {
00370     QListViewItem * item = clean.current();
00371     item->setEnabled( true );
00372     item->setVisible( true );
00373     item->setOpen( true );
00374     ++clean;
00375   }
00376 
00377   mFilter = filter;
00378 
00379   if ( filter.isEmpty() ) {
00380     setColumnText( mPathColumn, i18n("Path") );
00381     return;
00382   }
00383 
00384   // Set the visibility and enabled status of each list item.
00385   // The recursive algorithm is necessary because visiblity
00386   // changes are automatically applied to child nodes by Qt.
00387   QListViewItemIterator it( this );
00388   while ( it.current() ) {
00389     QListViewItem * item = it.current();
00390     if ( item->depth() <= 0 )
00391       recurseFilter( item, filter, mPathColumn );
00392     ++it;
00393   }
00394 
00395   // Recolor the rows appropriately
00396   recolorRows();
00397 
00398   // Iterate through the list to find the first selectable item
00399   QListViewItemIterator first ( this );
00400   while ( first.current() ) {
00401     FolderItem * item = static_cast< FolderItem* >( first.current() );
00402 
00403     if ( item->isVisible() && item->isSelectable() ) {
00404       setSelected( item, true );
00405       ensureItemVisible( item );
00406       break;
00407     }
00408 
00409     ++first;
00410   }
00411 
00412   // Display and save the current filter
00413   if ( filter.length() > 0 )
00414     setColumnText( mPathColumn, i18n("Path") + "  ( " + filter + " )" );
00415   else
00416     setColumnText( mPathColumn, i18n("Path") );
00417 
00418   mFilter = filter;
00419 }
00420 
00421 //-----------------------------------------------------------------------------
00422 void SimpleFolderTree::keyPressEvent( QKeyEvent *e ) {
00423   int ch = e->ascii();
00424 
00425   if ( ch >= 32 && ch <= 126 )
00426     applyFilter( mFilter + ch );
00427 
00428   else if ( ch == 8 || ch == 127 ) {
00429     if ( mFilter.length() > 0 ) {
00430       mFilter.truncate( mFilter.length()-1 );
00431       applyFilter( mFilter );
00432     }
00433   }
00434 
00435   else
00436     KListView::keyPressEvent( e );
00437 }
00438 
00439 
00440 //-----------------------------------------------------------------------------
00441 KMFolderSelDlg::KMFolderSelDlg( KMMainWidget * parent, const QString& caption,
00442     bool mustBeReadWrite, bool useGlobalSettings )
00443   : KDialogBase( parent, "folder dialog", true, caption,
00444                  Ok|Cancel|User1, Ok, true,
00445                  KGuiItem(i18n("&New Subfolder..."), "folder_new",
00446                    i18n("Create a new subfolder under the currently selected folder"))
00447                ), // mainwin as parent, modal
00448     mUseGlobalSettings( useGlobalSettings )
00449 {
00450   KMFolderTree * ft = parent->folderTree();
00451   assert( ft );
00452 
00453   QString preSelection = mUseGlobalSettings ?
00454     GlobalSettings::self()->lastSelectedFolder() : QString::null;
00455   mTreeView = new KMail::SimpleFolderTree( makeVBoxMainWidget(), ft,
00456                                            preSelection, mustBeReadWrite );
00457   init();
00458 }
00459 
00460 //----------------------------------------------------------------------------
00461 KMFolderSelDlg::KMFolderSelDlg( QWidget * parent, KMFolderTree * tree,
00462     const QString& caption, bool mustBeReadWrite, bool useGlobalSettings )
00463   : KDialogBase( parent, "folder dialog", true, caption,
00464                  Ok|Cancel|User1, Ok, true,
00465                  KGuiItem(i18n("&New Subfolder..."), "folder_new",
00466                    i18n("Create a new subfolder under the currently selected folder"))
00467                ), // mainwin as parent, modal
00468     mUseGlobalSettings( useGlobalSettings )
00469 {
00470   QString preSelection = mUseGlobalSettings ?
00471     GlobalSettings::self()->lastSelectedFolder() : QString::null;
00472   mTreeView = new KMail::SimpleFolderTree( makeVBoxMainWidget(), tree,
00473                                            preSelection, mustBeReadWrite );
00474   init();
00475 }
00476 
00477 //-----------------------------------------------------------------------------
00478 void KMFolderSelDlg::init()
00479 {
00480   mTreeView->setFocus();
00481   connect( mTreeView, SIGNAL( doubleClicked( QListViewItem*, const QPoint&, int ) ),
00482            this, SLOT( slotSelect() ) );
00483   connect( mTreeView, SIGNAL( selectionChanged() ),
00484            this, SLOT( slotUpdateBtnStatus() ) );
00485 
00486   readConfig();
00487 }
00488 
00489 //-----------------------------------------------------------------------------
00490 KMFolderSelDlg::~KMFolderSelDlg()
00491 {
00492   const KMFolder * cur = folder();
00493   if ( cur && mUseGlobalSettings ) {
00494     GlobalSettings::self()->setLastSelectedFolder( cur->idString() );
00495   }
00496 
00497   writeConfig();
00498 }
00499 
00500 
00501 //-----------------------------------------------------------------------------
00502 KMFolder * KMFolderSelDlg::folder( void )
00503 {
00504   return ( KMFolder * ) mTreeView->folder();
00505 }
00506 
00507 //-----------------------------------------------------------------------------
00508 void KMFolderSelDlg::setFolder( KMFolder* folder )
00509 {
00510   mTreeView->setFolder( folder );
00511 }
00512 
00513 //-----------------------------------------------------------------------------
00514 void KMFolderSelDlg::slotSelect()
00515 {
00516   accept();
00517 }
00518 
00519 //-----------------------------------------------------------------------------
00520 void KMFolderSelDlg::slotUser1()
00521 {
00522   mTreeView->addChildFolder();
00523 }
00524 
00525 //-----------------------------------------------------------------------------
00526 void KMFolderSelDlg::slotUpdateBtnStatus()
00527 {
00528   enableButton( User1, folder() &&
00529                 ( !folder()->noContent() && !folder()->noChildren() ) );
00530 }
00531 
00532 //-----------------------------------------------------------------------------
00533 void KMFolderSelDlg::setFlags( bool mustBeReadWrite, bool showOutbox,
00534                                bool showImapFolders )
00535 {
00536   mTreeView->reload( mustBeReadWrite, showOutbox, showImapFolders );
00537 }
00538 
00539 void KMFolderSelDlg::readConfig()
00540 {
00541   KConfig *config = KGlobal::config();
00542   config->setGroup( "FolderSelectionDialog" );
00543 
00544   QSize size = config->readSizeEntry( "Size" );
00545   if ( !size.isEmpty() ) resize( size );
00546   else resize( 500, 300 );
00547 
00548   QValueList<int> widths = config->readIntListEntry( "ColumnWidths" );
00549   if ( !widths.isEmpty() ) {
00550     mTreeView->setColumnWidth(mTreeView->mFolderColumn, widths[0]);
00551     mTreeView->setColumnWidth(mTreeView->mPathColumn,   widths[1]);
00552   }
00553   else {
00554     int colWidth = width() / 2;
00555     mTreeView->setColumnWidth(mTreeView->mFolderColumn, colWidth);
00556     mTreeView->setColumnWidth(mTreeView->mPathColumn,   colWidth);
00557   }
00558 }
00559 
00560 void KMFolderSelDlg::writeConfig()
00561 {
00562   KConfig *config = KGlobal::config();
00563   config->setGroup( "FolderSelectionDialog" );
00564   config->writeEntry( "Size", size() );
00565 
00566   QValueList<int> widths;
00567   widths.push_back(mTreeView->columnWidth(mTreeView->mFolderColumn));
00568   widths.push_back(mTreeView->columnWidth(mTreeView->mPathColumn));
00569   config->writeEntry( "ColumnWidths", widths );
00570 }
00571 
00572 } // namespace KMail
00573 
00574 #include "kmfolderseldlg.moc"