french -> French
[kdepim.git] / knode / knfoldermanager.cpp
blobe7f63fb8780f371f8598c44705b0cc78a61eab6d
1 /*
2 KNode, the KDE newsreader
3 Copyright (c) 1999-2006 the KNode authors.
4 See file AUTHORS for details
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
15 #include "knfoldermanager.h"
17 #include "knglobals.h"
18 #include "knconfigmanager.h"
19 #include "knfolder.h"
20 #include "utilities.h"
21 #include "knarticlemanager.h"
22 #include "kncleanup.h"
23 #include "knmemorymanager.h"
24 #include "knmainwidget.h"
25 #include "utils/scoped_cursor_override.h"
27 #include <KDebug>
28 #include <KMessageBox>
29 #include <KStandardDirs>
30 #include <QDir>
32 using namespace KNode::Utilities;
35 KNFolderManager::KNFolderManager(KNArticleManager *a) : a_rtManager(a)
37 //standard folders
38 QString dir( KStandardDirs::locateLocal( "data", "knode/folders/" ) );
39 if (dir.isNull()) {
40 KNHelper::displayInternalFileError();
41 return;
44 KNFolder::Ptr f;
46 f = KNFolder::Ptr( new KNFolder( 0, i18n( "Local Folders" ), "root" ) );
47 mFolderList.append( f );
48 f->readInfo();
50 f = KNFolder::Ptr( new KNFolder( 1, i18n( "Drafts" ), "drafts", root() ) );
51 mFolderList.append( f );
52 f->readInfo();
54 f = KNFolder::Ptr( new KNFolder( 2, i18n( "Outbox" ), "outbox", root() ) );
55 mFolderList.append( f );
56 f->readInfo();
58 f = KNFolder::Ptr( new KNFolder( 3, i18n( "Sent" ), "sent", root() ) );
59 mFolderList.append( f );
60 f->readInfo();
62 l_astId=3;
64 //custom folders
65 loadCustomFolders();
67 setCurrentFolder( KNFolder::Ptr() );
71 KNFolderManager::~KNFolderManager()
73 mFolderList.clear();
77 void KNFolderManager::setCurrentFolder( KNFolder::Ptr f )
79 c_urrentFolder=f;
80 a_rtManager->setFolder(f);
82 kDebug(5003) <<"KNFolderManager::setCurrentFolder() : folder changed";
84 if(f && !f->isRootFolder()) {
85 if( loadHeaders(f) )
86 a_rtManager->showHdrs();
87 else
88 KMessageBox::error(knGlobals.topWidget, i18n("Cannot load index-file."));
93 bool KNFolderManager::loadHeaders( KNFolder::Ptr f )
95 if( !f || f->isRootFolder() )
96 return false;
98 if (f->isLoaded())
99 return true;
101 // we want to delete old stuff first => reduce vm fragmentation
102 knGlobals.memoryManager()->prepareLoad(f);
104 if (f->loadHdrs()) {
105 knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
106 return true;
109 return false;
113 bool KNFolderManager::unloadHeaders( KNFolder::Ptr f, bool force )
115 if(!f || !f->isLoaded())
116 return false;
118 if (!force && (c_urrentFolder == f))
119 return false;
121 if (f->unloadHdrs(force))
122 knGlobals.memoryManager()->removeCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
123 else
124 return false;
126 return true;
130 KNFolder::Ptr KNFolderManager::folder( int id )
132 for ( KNFolder::List::Iterator it = mFolderList.begin(); it != mFolderList.end(); ++it )
133 if ( (*it)->id() == id )
134 return (*it);
135 return KNFolder::Ptr();
139 KNFolder::Ptr KNFolderManager::newFolder( KNFolder::Ptr p )
141 if (!p)
142 p = root();
143 KNFolder::Ptr f = KNFolder::Ptr( new KNFolder( ++l_astId, i18n( "New folder" ), p ) );
144 mFolderList.append( f );
145 emit folderAdded(f);
146 return f;
150 bool KNFolderManager::deleteFolder( KNFolder::Ptr f )
152 if(!f || f->isRootFolder() || f->isStandardFolder() || f->lockedArticles()>0)
153 return false;
155 KNFolder::List del;
156 KNCollection::Ptr p;
158 // find all subfolders of the folder we want to delete
159 for ( KNFolder::List::Iterator it = mFolderList.begin(); it != mFolderList.end(); ++it ) {
160 p = (*it)->parent();
161 while ( p ) {
162 if ( p == f ) {
163 if ( (*it)->lockedArticles() > 0 )
164 return false;
165 del.append( (*it) );
166 break;
168 p = p->parent();
172 emit folderRemoved(f);
174 del.append(f);
175 for ( KNFolder::List::Iterator it = del.begin(); it != del.end(); ++it ) {
176 if ( c_urrentFolder == (*it) )
177 c_urrentFolder = KNFolder::Ptr();
179 if ( unloadHeaders( (*it), true ) ) {
180 (*it)->deleteFiles();
181 mFolderList.removeAll( (*it) );
182 } else
183 return false;
186 return true;
190 void KNFolderManager::emptyFolder( KNFolder::Ptr f )
192 if(!f || f->isRootFolder())
193 return;
194 knGlobals.memoryManager()->removeCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
195 f->deleteAll();
199 bool KNFolderManager::canMoveFolder( KNFolder::Ptr f, KNFolder::Ptr p )
201 if(!f || p==f->parent()) // nothing to be done
202 return true;
204 // Moving a folder on itself
205 if ( f == p ) {
206 return false;
209 // is "p" a child of "f" ?
210 KNCollection::Ptr p2 = p ? p->parent() : KNCollection::Ptr();
211 while(p2) {
212 if(p2==f)
213 break;
214 p2=p2->parent();
217 if( (p2 && p2==f) || f==p || f->isStandardFolder() || f->isRootFolder()) // no way ;-)
218 return false;
220 return true;
223 bool KNFolderManager::moveFolder( KNFolder::Ptr f, KNFolder::Ptr p )
225 if ( !f || p==f->parent() ) { // nothing to be done
226 return true;
229 if ( !canMoveFolder( f, p ) ) {
230 return false;
233 emit folderRemoved(f);
235 // reparent
236 f->setParent(p);
237 f->writeConfig();
239 emit folderAdded(f);
241 if(c_urrentFolder==f)
242 emit folderActivated(f);
244 return true;
248 int KNFolderManager::unsentForAccount(int accId)
250 int cnt=0;
252 for ( KNFolder::List::Iterator it = mFolderList.begin(); it != mFolderList.end(); ++it ) {
253 for ( int idx = 0; idx < (*it)->length(); ++idx ) {
254 KNLocalArticle::Ptr a = (*it)->at( idx );
255 if ( a->serverId() == accId && a->doPost() && !a->posted() )
256 cnt++;
260 return cnt;
264 void KNFolderManager::compactFolder( KNFolder::Ptr f )
266 if(!f || f->isRootFolder())
267 return;
269 KNCleanUp cup;
270 cup.compactFolder(f);
274 void KNFolderManager::compactAll(KNCleanUp *cup)
276 for ( KNFolder::List::Iterator it = mFolderList.begin(); it != mFolderList.end(); ++it )
277 if ( !(*it)->isRootFolder() && (*it)->lockedArticles() == 0 )
278 cup->appendCollection( (*it) );
282 void KNFolderManager::compactAll()
284 KNCleanUp *cup = new KNCleanUp();
285 compactAll( cup );
286 cup->start();
288 knGlobals.configManager()->cleanup()->setLastCompactDate();
289 delete cup;
293 void KNFolderManager::importFromMBox( KNFolder::Ptr f )
295 if(!f || f->isRootFolder())
296 return;
298 f->setNotUnloadable(true);
300 if (!f->isLoaded() && !loadHeaders(f)) {
301 f->setNotUnloadable(false);
302 return;
305 KNLoadHelper helper(knGlobals.topWidget);
306 QFile *file = helper.getFile(i18n("Import MBox Folder"));
307 KNLocalArticle::List list;
308 KNLocalArticle::Ptr art;
309 QByteArray str;
310 int artStart=0, artEnd=0;
311 bool done=true;
313 if (file) {
314 ScopedCursorOverride cursor( Qt::WaitCursor );
315 knGlobals.setStatusMsg(i18n(" Importing articles..."));
316 knGlobals.top->secureProcessEvents();
318 if (!file->atEnd()) { // search for the first article...
319 str = file->readLine();
320 if ( str.left( 5 ) == "From " ) {
321 artStart = file->pos();
322 done = false;
323 } else {
324 artStart = KNHelper::findStringInFile( file, "\n\nFrom " );
325 if (artStart != -1) {
326 file->seek( artStart + 1 );
327 str = file->readLine();
328 artStart = file->pos();
329 done = false;
334 knGlobals.top->secureProcessEvents();
336 if (!done) {
337 while (!file->atEnd()) {
338 artEnd = KNHelper::findStringInFile( file, "\n\nFrom " );
340 if (artEnd != -1) {
341 file->seek( artStart ); // seek the first character of the article
342 int size=artEnd-artStart;
343 QByteArray buffer;
344 buffer = file->read( size);
346 if ( !buffer.isEmpty() ) {
347 art = KNLocalArticle::Ptr( new KNLocalArticle( KNArticleCollection::Ptr() ) );
348 art->setEditDisabled(true);
349 art->setContent( buffer );
350 art->parse();
351 list.append(art);
354 file->seek( artEnd + 1 );
355 str = file->readLine();
356 artStart = file->pos();
357 } else {
358 if ((int)file->size() > artStart) {
359 file->seek( artStart ); // seek the first character of the article
360 int size=file->size()-artStart;
361 QByteArray buffer;
362 buffer = file->read( size );
364 if ( !buffer.isEmpty() ) {
365 art = KNLocalArticle::Ptr( new KNLocalArticle( KNArticleCollection::Ptr() ) );
366 art->setEditDisabled(true);
367 art->setContent( buffer );
368 art->parse();
369 list.append(art);
374 if (list.count()%75 == 0)
375 knGlobals.top->secureProcessEvents();
379 knGlobals.setStatusMsg(i18n(" Storing articles..."));
380 knGlobals.top->secureProcessEvents();
382 if (!list.isEmpty())
383 knGlobals.articleManager()->moveIntoFolder(list, f);
385 knGlobals.setStatusMsg( QString() );
386 cursor.restore();
389 f->setNotUnloadable(false);
393 void KNFolderManager::exportToMBox( KNFolder::Ptr f )
395 if(!f || f->isRootFolder())
396 return;
398 f->setNotUnloadable(true);
400 if (!f->isLoaded() && !loadHeaders(f)) {
401 f->setNotUnloadable(false);
402 return;
405 KNSaveHelper helper(f->name()+".mbox", knGlobals.topWidget);
406 QFile *file = helper.getFile(i18n("Export Folder"));
408 if (file) {
409 ScopedCursorOverride cursor( Qt::WaitCursor );
410 knGlobals.setStatusMsg(i18n(" Exporting articles..."));
411 knGlobals.top->secureProcessEvents();
413 QTextStream ts(file);
414 ts.setCodec( "ISO 8859-1" );
415 KNLocalArticle::Ptr a;
417 for(int idx=0; idx<f->length(); idx++) {
418 a=f->at(idx);
420 a->setNotUnloadable(true);
422 if (a->hasContent() || knGlobals.articleManager()->loadArticle(a)) {
423 ts << "From aaa@aaa Mon Jan 01 00:00:00 1997\n";
424 a->toStream(ts, true);
425 ts << "\n";
428 a->setNotUnloadable(false);
430 if (idx%75 == 0)
431 knGlobals.top->secureProcessEvents();
434 knGlobals.setStatusMsg( QString() );
439 void KNFolderManager::syncFolders()
441 QString dir( KStandardDirs::locateLocal( "data", "knode/folders/" ) );
442 if (dir.isNull()) {
443 KNHelper::displayInternalFileError();
444 return;
447 //sync
448 for ( KNFolder::List::Iterator it = mFolderList.begin(); it != mFolderList.end(); ++it ) {
449 if ( !(*it)->isRootFolder() )
450 (*it)->syncIndex();
451 (*it)->writeConfig();
456 int KNFolderManager::loadCustomFolders()
458 int cnt=0;
459 QString dir( KStandardDirs::locateLocal( "data", "knode/folders/" ) );
460 KNFolder::Ptr f;
462 if (dir.isNull()) {
463 KNHelper::displayInternalFileError();
464 return 0;
467 QDir d(dir);
468 QStringList entries(d.entryList(QStringList("custom_*.info"))); // ignore info files of standard folders
469 for(QStringList::Iterator it=entries.begin(); it != entries.end(); ++it) {
470 f = KNFolder::Ptr( new KNFolder() );
471 if(f->readInfo(d.absoluteFilePath(*it))) {
472 if(f->id()>l_astId)
473 l_astId=f->id();
474 mFolderList.append( f );
475 cnt++;
479 // set parents
480 if(cnt>0) {
481 for ( KNFolder::List::Iterator it = mFolderList.begin(); it != mFolderList.end(); ++it ) {
482 if ( !(*it)->isRootFolder() ) { // the root folder has no parent
483 KNFolder::Ptr par = folder( (*it)->parentId() );
484 if ( !par )
485 par = root();
486 (*it)->setParent( par );
491 return cnt;