kmail

subscriptiondialog.cpp

Go to the documentation of this file.
00001 /*  -*- c++ -*-
00002     subscriptiondialog.cpp
00003 
00004     This file is part of KMail, the KDE mail client.
00005     Copyright (C) 2002 Carsten Burghardt <burghardt@kde.org>
00006 
00007     KMail is free software; you can redistribute it and/or modify it
00008     under the terms of the GNU General Public License, version 2, as
00009     published by the Free Software Foundation.
00010 
00011     KMail is distributed in the hope that it will be useful, but
00012     WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020     In addition, as a special exception, the copyright holders give
00021     permission to link the code of this program with any edition of
00022     the Qt library by Trolltech AS, Norway (or with modified versions
00023     of Qt that use the same license as Qt), and distribute linked
00024     combinations including the two.  You must obey the GNU General
00025     Public License in all respects for all of the code used other than
00026     Qt.  If you modify this file, you may extend this exception to
00027     your version of the file, but you are not obligated to do so.  If
00028     you do not wish to do so, delete this exception statement from
00029     your version.
00030 */
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035 
00036 #include "subscriptiondialog.h"
00037 #include "folderstorage.h"
00038 #include "listjob.h"
00039 #include "imapaccountbase.h"
00040 
00041 #include <klocale.h>
00042 #include <kdebug.h>
00043 #include <kmessagebox.h>
00044 
00045 
00046 namespace KMail {
00047 
00048 SubscriptionDialogBase::SubscriptionDialogBase( QWidget *parent, const QString &caption,
00049     KAccount *acct, QString startPath )
00050   : KSubscription( parent, caption, acct, User1, QString::null, false ),
00051     mStartPath( startPath ), mSubscribed( false ), mForceSubscriptionEnable( false)
00052 {
00053   // hide unneeded checkboxes
00054   hideTreeCheckbox();
00055   hideNewOnlyCheckbox();
00056 
00057   // ok-button
00058   connect(this, SIGNAL(okClicked()), SLOT(slotSave()));
00059 
00060   // reload-list button
00061   connect(this, SIGNAL(user1Clicked()), SLOT(slotLoadFolders()));
00062 
00063   // get the folders, delayed execution style, otherwise there's bother
00064   // with virtuals from ctors and whatnot
00065   QTimer::singleShot(0, this, SLOT(slotLoadFolders()));
00066 }
00067 
00068 //------------------------------------------------------------------------------
00069 void SubscriptionDialogBase::slotListDirectory( const QStringList& subfolderNames,
00070                                             const QStringList& subfolderPaths,
00071                                             const QStringList& subfolderMimeTypes,
00072                                             const QStringList& subfolderAttributes,
00073                                             const ImapAccountBase::jobData& jobData )
00074 {
00075   mFolderNames = subfolderNames;
00076   mFolderPaths = subfolderPaths;
00077   mFolderMimeTypes = subfolderMimeTypes;
00078   mFolderAttributes = subfolderAttributes;
00079   mJobData = jobData;
00080 
00081   mCount = 0;
00082 
00083   processFolderListing();
00084 }
00085 
00086 void SubscriptionDialogBase::moveChildrenToNewParent( GroupItem *oldItem, GroupItem *item  )
00087 {
00088   if ( !oldItem || !item ) return;
00089 
00090   QPtrList<QListViewItem> itemsToMove;
00091   QListViewItem * myChild = oldItem->firstChild();
00092   while (myChild)
00093   {
00094     itemsToMove.append(myChild);
00095     myChild = myChild->nextSibling();
00096   }
00097   QPtrListIterator<QListViewItem> it( itemsToMove );
00098   QListViewItem *cur;
00099   while ((cur = it.current()))
00100   {
00101     oldItem->takeItem(cur);
00102     item->insertItem(cur);
00103     if ( cur->isSelected() ) // we have new parents so open them
00104       folderTree()->ensureItemVisible( cur );
00105     ++it;
00106   }
00107   delete oldItem;
00108   itemsToMove.clear();
00109 }
00110 
00111 void SubscriptionDialogBase::createListViewItem( int i )
00112 {
00113   GroupItem *item = 0;
00114   GroupItem *parent = 0;
00115 
00116   // get the parent
00117   GroupItem *oldItem = 0;
00118   QString parentPath;
00119   findParentItem( mFolderNames[i], mFolderPaths[i], parentPath, &parent, &oldItem );
00120 
00121   if (!parent && parentPath != "/")
00122   {
00123     // the parent is not available and it's no root-item
00124     // this happens when the folders do not arrive in hierarchical order
00125     // so we create each parent in advance
00126     QStringList folders = QStringList::split(mDelimiter, parentPath);
00127     uint i = 0;
00128     for ( QStringList::Iterator it = folders.begin(); it != folders.end(); ++it )
00129     {
00130       QString name = *it;
00131       if (name.startsWith("/"))
00132         name = name.right(name.length()-1);
00133       if (name.endsWith("/"))
00134         name.truncate(name.length()-1);
00135       KGroupInfo info(name);
00136       info.subscribed = false;
00137 
00138       QStringList tmpPath;
00139       for ( uint j = 0; j <= i; ++j )
00140         tmpPath << folders[j];
00141       QString path = tmpPath.join(mDelimiter);
00142       if (!path.startsWith("/"))
00143         path = "/" + path;
00144       if (!path.endsWith("/"))
00145         path = path + "/";
00146       info.path = path;
00147       item = 0;
00148       if (folders.count() > 1)
00149       {
00150         // we have to create more then one level, so better check if this
00151         // folder already exists somewhere
00152         item = mItemDict[path];
00153       }
00154       // as these items are "dummies" we create them non-checkable
00155       if (!item)
00156       {
00157         if (parent)
00158           item = new GroupItem(parent, info, this, false);
00159         else
00160           item = new GroupItem(folderTree(), info, this, false);
00161         mItemDict.insert(info.path, item);
00162       }
00163 
00164       parent = item;
00165       ++i;
00166     } // folders
00167   } // parent
00168 
00169   KGroupInfo info(mFolderNames[i]);
00170   if (mFolderNames[i].upper() == "INBOX" &&
00171       mFolderPaths[i] == "/INBOX/")
00172     info.name = i18n("inbox");
00173   info.subscribed = false;
00174   info.path = mFolderPaths[i];
00175   // only checkable when the folder is selectable
00176   bool checkable = ( mFolderMimeTypes[i] == "inode/directory" ) ? false : true;
00177   // create a new item
00178   if (parent)
00179     item = new GroupItem(parent, info, this, checkable);
00180   else
00181     item = new GroupItem(folderTree(), info, this, checkable);
00182 
00183   if (oldItem) // remove old item
00184     mItemDict.remove(info.path);
00185 
00186   mItemDict.insert(info.path, item);
00187   if (oldItem)
00188     moveChildrenToNewParent( oldItem, item );
00189 
00190   // select the start item
00191   if ( mFolderPaths[i] == mStartPath )
00192   {
00193     item->setSelected( true );
00194     folderTree()->ensureItemVisible( item );
00195   }
00196 }
00197 
00198 
00199 
00200 //------------------------------------------------------------------------------
00201 void SubscriptionDialogBase::findParentItem( QString &name, QString &path, QString &parentPath,
00202     GroupItem **parent, GroupItem **oldItem )
00203 {
00204   // remove the name (and the separator) from the path to get the parent path
00205   int start = path.length() - (name.length()+2);
00206   int length = name.length()+1;
00207   if (start < 0) start = 0;
00208   parentPath = path;
00209   parentPath.remove(start, length);
00210 
00211   // find the parent by it's path
00212   *parent = mItemDict[parentPath];
00213 
00214   // check if the item already exists
00215   *oldItem = mItemDict[path];
00216 }
00217 
00218 //------------------------------------------------------------------------------
00219 void SubscriptionDialogBase::slotSave()
00220 {
00221   doSave();
00222 }
00223 
00224 //------------------------------------------------------------------------------
00225 void SubscriptionDialogBase::slotLoadFolders()
00226 {
00227   ImapAccountBase* ai = static_cast<ImapAccountBase*>(account());
00228   // we need a connection
00229   if ( ai->makeConnection() == ImapAccountBase::Error )
00230   {
00231     kdWarning(5006) << "SubscriptionDialog - got no connection" << endl;
00232     return;
00233   } else if ( ai->makeConnection() == ImapAccountBase::Connecting )
00234   {
00235     // We'll wait for the connectionResult signal from the account.
00236     kdDebug(5006) << "SubscriptionDialog - waiting for connection" << endl;
00237     connect( ai, SIGNAL( connectionResult(int, const QString&) ),
00238         this, SLOT( slotConnectionResult(int, const QString&) ) );
00239     return;
00240   }
00241   // clear the views
00242   KSubscription::slotLoadFolders();
00243   mItemDict.clear();
00244   mSubscribed = false;
00245   mLoading = true;
00246 
00247   // first step is to load a list of all available folders and create listview
00248   // items for them
00249   listAllAvailableAndCreateItems();
00250 }
00251 
00252 //------------------------------------------------------------------------------
00253 void SubscriptionDialogBase::processNext()
00254 {
00255   if ( mPrefixList.isEmpty() )
00256   {
00257     if ( !mSubscribed )
00258     {
00259       mSubscribed = true;
00260       initPrefixList();
00261       if ( mPrefixList.isEmpty() )
00262       {
00263           // still empty? then we have nothing to do here as this is an error
00264           loadingComplete();
00265           return;
00266       }
00267     } else {
00268       loadingComplete();
00269       return;
00270     }
00271   }
00272   ImapAccountBase* ai = static_cast<ImapAccountBase*>(account());
00273   ImapAccountBase::ListType type = ( mSubscribed ?
00274       ImapAccountBase::ListSubscribedNoCheck : ImapAccountBase::List );
00275 
00276   bool completeListing = true;
00277   mCurrentNamespace = mPrefixList.first();
00278   mDelimiter = ai->delimiterForNamespace( mCurrentNamespace );
00279   mPrefixList.pop_front();
00280   if ( mCurrentNamespace == "/INBOX/" )
00281   {
00282     type = mSubscribed ?
00283       ImapAccountBase::ListFolderOnlySubscribed : ImapAccountBase::ListFolderOnly;
00284     completeListing = false;
00285   }
00286 
00287 //  kdDebug(5006) << "process " << mCurrentNamespace << ",subscribed=" << mSubscribed << endl;
00288   ListJob* job = new ListJob( ai, type, 0, ai->addPathToNamespace( mCurrentNamespace ), completeListing );
00289   connect( job, SIGNAL(receivedFolders(const QStringList&, const QStringList&,
00290           const QStringList&, const QStringList&, const ImapAccountBase::jobData&)),
00291       this, SLOT(slotListDirectory(const QStringList&, const QStringList&,
00292           const QStringList&, const QStringList&, const ImapAccountBase::jobData&)));
00293   job->start();
00294 }
00295 
00296 void SubscriptionDialogBase::loadingComplete()
00297 {
00298   slotLoadingComplete();
00299 }
00300 
00301 
00302 //------------------------------------------------------------------------------
00303 // implementation for server side subscription
00304 //------------------------------------------------------------------------------
00305 
00306 SubscriptionDialog::SubscriptionDialog( QWidget *parent, const QString &caption,
00307     KAccount *acct, QString startPath )
00308   : SubscriptionDialogBase( parent, caption, acct, startPath )
00309 {
00310 }
00311 
00312 /* virtual */
00313 SubscriptionDialog::~SubscriptionDialog()
00314 {
00315 
00316 }
00317 
00318 /* virtual */
00319 void SubscriptionDialog::listAllAvailableAndCreateItems()
00320 {
00321   initPrefixList();
00322   processNext();
00323 }
00324 
00325 //------------------------------------------------------------------------------
00326 void SubscriptionDialogBase::initPrefixList()
00327 {
00328   ImapAccountBase* ai = static_cast<ImapAccountBase*>(account());
00329   ImapAccountBase::nsMap map = ai->namespaces();
00330   mPrefixList.clear();
00331 
00332   bool hasInbox = false;
00333   const QStringList ns = map[ImapAccountBase::PersonalNS];
00334   for ( QStringList::ConstIterator it = ns.begin(); it != ns.end(); ++it )
00335   {
00336     if ( (*it).isEmpty() )
00337       hasInbox = true;
00338   }
00339   if ( !hasInbox && !ns.isEmpty() )
00340   {
00341     // the namespaces includes no listing for the root so start a special
00342     // listing for the INBOX to make sure we get it
00343     mPrefixList += "/INBOX/";
00344   }
00345 
00346   mPrefixList += map[ImapAccountBase::PersonalNS];
00347   mPrefixList += map[ImapAccountBase::OtherUsersNS];
00348   mPrefixList += map[ImapAccountBase::SharedNS];
00349 }
00350 
00351 void SubscriptionDialogBase::slotConnectionResult( int errorCode, const QString& errorMsg )
00352 {
00353   Q_UNUSED( errorMsg );
00354   if ( !errorCode )
00355     slotLoadFolders();
00356 }
00357 
00358 void SubscriptionDialogBase::show()
00359 {
00360   KDialogBase::show();
00361 }
00362 
00363 // =======
00364 /* virtual */
00365 void SubscriptionDialog::processFolderListing()
00366 {
00367     processItems();
00368 }
00369 
00370 /* virtual */
00371 void SubscriptionDialog::doSave()
00372 {
00373   KMail::ImapAccountBase *a = static_cast<KMail::ImapAccountBase*>(mAcct);
00374   if( !a->onlySubscribedFolders() ) {
00375       int result = KMessageBox::questionYesNoCancel( this,
00376               i18n("Currently subscriptions are not used for server %1\ndo you want to enable subscriptions?")
00377               .arg( a->name() ),
00378               i18n("Enable Subscriptions?"), i18n("Enable"), i18n("Do Not Enable"));
00379       switch(result) {
00380           case KMessageBox::Yes:
00381               mForceSubscriptionEnable = true;
00382               break;
00383           case KMessageBox::No:
00384               break;
00385           case KMessageBox::Cancel:
00386               cancel();
00387       }
00388   }
00389 
00390   // subscribe
00391   QListViewItemIterator it(subView);
00392   for ( ; it.current(); ++it)
00393   {
00394     static_cast<ImapAccountBase*>(account())->changeSubscription(true,
00395         static_cast<GroupItem*>(it.current())->info().path);
00396   }
00397 
00398   // unsubscribe
00399   QListViewItemIterator it2(unsubView);
00400   for ( ; it2.current(); ++it2)
00401   {
00402     static_cast<ImapAccountBase*>(account())->changeSubscription(false,
00403         static_cast<GroupItem*>(it2.current())->info().path);
00404   }
00405 
00406   if ( mForceSubscriptionEnable ) {
00407     a->setOnlySubscribedFolders(true);
00408   }
00409 }
00410 
00411 void SubscriptionDialog::processItems()
00412 {
00413   bool onlySubscribed = mJobData.onlySubscribed;
00414   uint done = 0;
00415   for (uint i = mCount; i < mFolderNames.count(); ++i)
00416   {
00417     // give the dialog a chance to repaint
00418     if (done == 1000)
00419     {
00420       emit listChanged();
00421       QTimer::singleShot(0, this, SLOT(processItems()));
00422       return;
00423     }
00424     ++mCount;
00425     ++done;
00426     if (!onlySubscribed && mFolderPaths.size() > 0)
00427     {
00428       createListViewItem( i );
00429     } else if (onlySubscribed)
00430     {
00431       // find the item
00432       if ( mItemDict[mFolderPaths[i]] )
00433       {
00434         GroupItem* item = mItemDict[mFolderPaths[i]];
00435         item->setOn( true );
00436       }
00437     }
00438   }
00439 
00440   processNext();
00441 }
00442 } // namespace
00443 
00444 #include "subscriptiondialog.moc"