subscriptiondialog.cpp
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 TQt library by Trolltech AS, Norway (or with modified versions 00023 of TQt that use the same license as TQt), 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 TQt. 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( TQWidget *parent, const TQString &caption, 00049 KAccount *acct, TQString startPath ) 00050 : KSubscription( parent, caption, acct, User1, TQString(), false ), 00051 mStartPath( startPath ), mSubscribed( false ), mForceSubscriptionEnable( false) 00052 { 00053 // hide unneeded checkboxes 00054 hideTreeCheckbox(); 00055 hideNewOnlyCheckbox(); 00056 00057 // ok-button 00058 connect(this, TQT_SIGNAL(okClicked()), TQT_SLOT(slotSave())); 00059 00060 // reload-list button 00061 connect(this, TQT_SIGNAL(user1Clicked()), TQT_SLOT(slotLoadFolders())); 00062 00063 // get the folders, delayed execution style, otherwise there's bother 00064 // with virtuals from ctors and whatnot 00065 TQTimer::singleShot(0, this, TQT_SLOT(slotLoadFolders())); 00066 } 00067 00068 //------------------------------------------------------------------------------ 00069 void SubscriptionDialogBase::slotListDirectory( const TQStringList& subfolderNames, 00070 const TQStringList& subfolderPaths, 00071 const TQStringList& subfolderMimeTypes, 00072 const TQStringList& 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 TQPtrList<TQListViewItem> itemsToMove; 00091 TQListViewItem * myChild = oldItem->firstChild(); 00092 while (myChild) 00093 { 00094 itemsToMove.append(myChild); 00095 myChild = myChild->nextSibling(); 00096 } 00097 TQPtrListIterator<TQListViewItem> it( itemsToMove ); 00098 TQListViewItem *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 TQString 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 TQStringList folders = TQStringList::split(mDelimiter, parentPath); 00127 uint i = 0; 00128 for ( TQStringList::Iterator it = folders.begin(); it != folders.end(); ++it ) 00129 { 00130 TQString 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 TQStringList tmpPath; 00139 for ( uint j = 0; j <= i; ++j ) 00140 tmpPath << folders[j]; 00141 TQString 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( TQString &name, TQString &path, TQString &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, TQT_SIGNAL( connectionResult(int, const TQString&) ), 00238 this, TQT_SLOT( slotConnectionResult(int, const TQString&) ) ); 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, TQT_SIGNAL(receivedFolders(const TQStringList&, const TQStringList&, 00290 const TQStringList&, const TQStringList&, const ImapAccountBase::jobData&)), 00291 this, TQT_SLOT(slotListDirectory(const TQStringList&, const TQStringList&, 00292 const TQStringList&, const TQStringList&, 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( TQWidget *parent, const TQString &caption, 00307 KAccount *acct, TQString 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 TQStringList ns = map[ImapAccountBase::PersonalNS]; 00334 for ( TQStringList::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 TQString& 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 TQListViewItemIterator 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 TQListViewItemIterator 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 TQTimer::singleShot(0, this, TQT_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"