knarticlemanager.cpp 28.1 KB
Newer Older
1
2
/*
    KNode, the KDE newsreader
Volker Krause's avatar
Volker Krause committed
3
    Copyright (c) 1999-2006 the KNode authors.
4
5
6
7
8
9
10
11
    See file AUTHORS for details

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
12
    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
13
*/
Dirk Mueller's avatar
Dirk Mueller committed
14

15
16
17
18
#include "knarticlemanager.h"

#include "utils/scoped_cursor_override.h"

19
20
#include <QByteArray>
#include <QList>
Laurent Montel's avatar
Laurent Montel committed
21
#include <krun.h>
Dirk Mueller's avatar
Dirk Mueller committed
22
#include <kmessagebox.h>
23
#include <kmimetypetrader.h>
24
#include <klocale.h>
Christian Thurner's avatar
Christian Thurner committed
25
#include <kdebug.h>
Luboš Luňák's avatar
Luboš Luňák committed
26
#include <kwindowsystem.h>
Jaison Lee's avatar
Jaison Lee committed
27
#include <ktemporaryfile.h>
Dirk Mueller's avatar
Dirk Mueller committed
28

29
#include "articlewidget.h"
30
#include "knmainwidget.h"
Dirk Mueller's avatar
Dirk Mueller committed
31
32
#include "knglobals.h"
#include "utilities.h"
33
#include "knarticlemanager.h"
Christian Thurner's avatar
   
Christian Thurner committed
34
#include "kngroupmanager.h"
Christian Thurner's avatar
Christian Thurner committed
35
36
37
38
39
#include "knsearchdialog.h"
#include "knfiltermanager.h"
#include "knfolder.h"
#include "knarticlefilter.h"
#include "knhdrviewitem.h"
40
#include "scheduler.h"
Christian Thurner's avatar
   
Christian Thurner committed
41
#include "knnntpaccount.h"
42
#include "knscoring.h"
Christian Thurner's avatar
   
Christian Thurner committed
43
#include "knmemorymanager.h"
44
45
46
#include "knarticlefactory.h"
#include "knarticlewindow.h"
#include "knfoldermanager.h"
47
#include "headerview.h"
48
#include "nntpjobs.h"
Volker Krause's avatar
Volker Krause committed
49
50
#include "settings.h"

51
using namespace KNode;
52
using namespace KNode::Utilities;
53

Christian Thurner's avatar
   
Christian Thurner committed
54

55
KNArticleManager::KNArticleManager() : QObject(0)
Dirk Mueller's avatar
Dirk Mueller committed
56
{
57
58
  f_ilterMgr = knGlobals.filterManager();
  f_ilter = f_ilterMgr->currentFilter();
Christian Thurner's avatar
Christian Thurner committed
59
  s_earchDlg=0;
60
  d_isableExpander=false;
Christian Thurner's avatar
Christian Thurner committed
61

62
  connect(f_ilterMgr, SIGNAL(filterChanged(KNArticleFilter*)), this,
63
    SLOT(slotFilterChanged(KNArticleFilter*)));
Dirk Mueller's avatar
Dirk Mueller committed
64
65
66
67
68
}


KNArticleManager::~KNArticleManager()
{
Christian Thurner's avatar
Christian Thurner committed
69
  delete s_earchDlg;
Dirk Mueller's avatar
Dirk Mueller committed
70
71
72
73
74
}


void KNArticleManager::deleteTempFiles()
{
Jaison Lee's avatar
Jaison Lee committed
75
  for ( QList<KTemporaryFile*>::Iterator it = mTempFiles.begin(); it != mTempFiles.end(); ++it ) {
76
    delete (*it);
Dirk Mueller's avatar
Dirk Mueller committed
77
  }
78
  mTempFiles.clear();
Dirk Mueller's avatar
Dirk Mueller committed
79
80
81
}


82
void KNArticleManager::saveContentToFile(KMime::Content *c, QWidget *parent)
Dirk Mueller's avatar
Dirk Mueller committed
83
{
84
  KNSaveHelper helper(c->contentType()->name(),parent);
85

86
  QFile *file = helper.getFile(i18n("Save Attachment"));
87
88

  if (file) {
89
    QByteArray data=c->decodedContent();
Laurent Montel's avatar
Laurent Montel committed
90
    if (file->write(data.data(), data.size()) == -1 )
91
      KNHelper::displayExternalFileError( parent );
92
  }
Dirk Mueller's avatar
Dirk Mueller committed
93
94
95
}


96
void KNArticleManager::saveArticleToFile( KNArticle::Ptr a, QWidget *parent )
Dirk Mueller's avatar
Dirk Mueller committed
97
{
Christian Thurner's avatar
Christian Thurner committed
98
  QString fName = a->subject()->asUnicodeString();
Christian Gebauer's avatar
Christian Gebauer committed
99
100
  QString s = "";

101
  for ( int i = 0; i < fName.length(); ++i )
Christian Gebauer's avatar
Christian Gebauer committed
102
103
104
105
    if (fName[i].isLetterOrNumber())
      s.append(fName[i]);
    else
      s.append(' ');
Laurent Montel's avatar
Laurent Montel committed
106
  fName = s.simplified();
Christian Gebauer's avatar
Christian Gebauer committed
107
108
  fName.replace(QRegExp("[\\s]"),"_");

109
  KNSaveHelper helper(fName,parent);
110
  QFile *file = helper.getFile(i18n("Save Article"));
Christian Thurner's avatar
Christian Thurner committed
111

112
  if (file) {
113
    QByteArray tmp=a->encodedContent(false);
Laurent Montel's avatar
Laurent Montel committed
114
    if ( file->write(tmp.data(), tmp.size()) == -1 )
115
      KNHelper::displayExternalFileError( parent );
116
  }
Dirk Mueller's avatar
Dirk Mueller committed
117
118
119
}


120
QString KNArticleManager::saveContentToTemp(KMime::Content *c)
Dirk Mueller's avatar
Dirk Mueller committed
121
{
122
  QString path;
Jaison Lee's avatar
Jaison Lee committed
123
  KTemporaryFile* tmpFile;
David Jarvie's avatar
David Jarvie committed
124
  KMime::Headers::Base *pathHdr=c->headerByType("X-KNode-Tempfile");  // check for existing temp file
125

Christian Thurner's avatar
Christian Thurner committed
126
  if(pathHdr) {
127
128
129
130
    path = pathHdr->asUnicodeString();
    bool found=false;

    // lets see if the tempfile-path is still valid...
Jaison Lee's avatar
Jaison Lee committed
131
132
    for ( QList<KTemporaryFile*>::Iterator it = mTempFiles.begin(); it != mTempFiles.end(); ++it ) {
      if ( (*it)->fileName() == path ) {
133
134
135
        found = true;
        break;
      }
136
    }
137
138
139
140
141

    if (found)
      return path;
    else
      c->removeHeader("X-KNode-Tempfile");
142
  }
143

Jaison Lee's avatar
Jaison Lee committed
144
145
  tmpFile=new KTemporaryFile();
  if (!tmpFile->open()) {
Christian Gebauer's avatar
Christian Gebauer committed
146
    KNHelper::displayTempFileError();
147
    delete tmpFile;
Volker Krause's avatar
Volker Krause committed
148
    return QString();
149
150
  }

151
  mTempFiles.append(tmpFile);
152
  QByteArray data=c->decodedContent();
Jaison Lee's avatar
Jaison Lee committed
153
154
155
  tmpFile->write(data.data(), data.size());
  tmpFile->flush();
  path=tmpFile->fileName();
156
  pathHdr=new KMime::Headers::Generic("X-KNode-Tempfile", c, path, "UTF-8");
Christian Thurner's avatar
Christian Thurner committed
157
  c->setHeader(pathHdr);
158
159

  return path;
Dirk Mueller's avatar
Dirk Mueller committed
160
161
162
}


163
void KNArticleManager::openContent(KMime::Content *c)
Dirk Mueller's avatar
Dirk Mueller committed
164
{
165
  QString path=saveContentToTemp(c);
Dirk Mueller's avatar
Dirk Mueller committed
166
  if(path.isNull()) return;
167

168
  KService::Ptr offer = KMimeTypeTrader::self()->preferredService(c->contentType()->mimeType(), "Application");
Laurent Montel's avatar
Laurent Montel committed
169
170
  KUrl::List lst;
  KUrl url;
171
172
  url.setPath(path);
  lst.append(url);
173
174

  if (offer)
175
    KRun::run(*offer, lst, knGlobals.top);
176
  else
177
    KRun::displayOpenWithDialog(lst, knGlobals.top);
Dirk Mueller's avatar
Dirk Mueller committed
178
179
180
}


Christian Thurner's avatar
Christian Thurner committed
181
182
void KNArticleManager::showHdrs(bool clear)
{
183
184
  if(!g_roup && !f_older) return;

Christian Thurner's avatar
   
Christian Thurner committed
185
  bool setFirstChild=true;
Volker Krause's avatar
Volker Krause committed
186
187
  bool showThreads=knGlobals.settings()->showThreads();
  bool expandThreads=knGlobals.settings()->defaultToExpandedThreads();
Christian Thurner's avatar
   
Christian Thurner committed
188

Christian Thurner's avatar
Christian Thurner committed
189
  if(clear)
190
    v_iew->clear();
Christian Thurner's avatar
Christian Thurner committed
191

192
  ScopedCursorOverride cursor( Qt::WaitCursor );
193
  knGlobals.setStatusMsg(i18n(" Creating list..."));
Christian Thurner's avatar
Christian Thurner committed
194
195
196
  knGlobals.top->secureProcessEvents();

  if(g_roup) {
197
    KNRemoteArticle::Ptr art, ref, current;
Christian Thurner's avatar
Christian Thurner committed
198

199
    current = boost::static_pointer_cast<KNRemoteArticle>( knGlobals.top->articleViewer()->article() );
Christian Thurner's avatar
   
Christian Thurner committed
200

201
    if(current && (current->collection() != g_roup)) {
202
203
      current.reset();
      knGlobals.top->articleViewer()->setArticle( KNRemoteArticle::Ptr() );
Christian Thurner's avatar
   
Christian Thurner committed
204
205
    }

206
    if(g_roup->isLocked())
207
      knGlobals.scheduler()->nntpMutex().lock();
Christian Thurner's avatar
Christian Thurner committed
208
209

    if(f_ilter)
210
      f_ilter->doFilter(g_roup);
Stephan Binner's avatar
Stephan Binner committed
211
    else
Christian Thurner's avatar
Christian Thurner committed
212
      for(int i=0; i<g_roup->length(); i++) {
213
        art=g_roup->at(i);
Christian Thurner's avatar
Christian Thurner committed
214
215
        art->setFilterResult(true);
        art->setFiltered(true);
216
        ref = ( art->idRef() ? g_roup->byId( art->idRef() ) : KNRemoteArticle::Ptr() );
Christian Thurner's avatar
   
Christian Thurner committed
217
218
        art->setDisplayedReference(ref);
        if(ref)
219
          ref->setVisibleFollowUps(true);
Christian Thurner's avatar
Christian Thurner committed
220
221
      }

222
223
    d_isableExpander=true;

Christian Thurner's avatar
Christian Thurner committed
224
    for(int i=0; i<g_roup->length(); i++) {
Christian Thurner's avatar
   
Christian Thurner committed
225

Christian Thurner's avatar
Christian Thurner committed
226
      art=g_roup->at(i);
227
      art->setThreadMode(showThreads);
Christian Thurner's avatar
   
Christian Thurner committed
228

229
      if(showThreads) {
230
        art->propagateThreadChangedDate();
Christian Thurner's avatar
   
Christian Thurner committed
231

Christian Thurner's avatar
Christian Thurner committed
232
233
        if( !art->listItem() && art->filterResult() ) {

234
235
236
237
238
          // ### disable delayed header view item creation for now, it breaks
          // the quick search
          // since it doesn't seem to improve performance at all, it probably
          // could be removed entirely (see also slotItemExpanded(), etc.)
          /*if (!expandThreads) {
239
240
241
242
243
244
245
246
247
248
249

            if( (ref=art->displayedReference()) ) {

              if( ref->listItem() && ( ref->listItem()->isOpen() || ref->listItem()->childCount()>0 ) ) {
                art->setListItem(new KNHdrViewItem(ref->listItem()));
                art->initListItem();
              }

            }
            else {
              art->setListItem(new KNHdrViewItem(v_iew));
Christian Thurner's avatar
   
Christian Thurner committed
250
251
              art->initListItem();
            }
252

253
        } else {  // expandThreads == true */
254
            createThread(art);
255
256
257
            if ( expandThreads )
              art->listItem()->setOpen(true);
//           }
Christian Thurner's avatar
   
Christian Thurner committed
258

Christian Thurner's avatar
Christian Thurner committed
259
        }
260
        else if(art->listItem()) {
Christian Thurner's avatar
Christian Thurner committed
261
          art->updateListItem();
262
263
264
          if (expandThreads)
            art->listItem()->setOpen(true);
        }
Christian Thurner's avatar
   
Christian Thurner committed
265

Christian Thurner's avatar
Christian Thurner committed
266
267
      }
      else {
Christian Thurner's avatar
   
Christian Thurner committed
268

Christian Thurner's avatar
Christian Thurner committed
269
        if(!art->listItem() && art->filterResult()) {
270
          art->setListItem( new KNHdrViewItem( v_iew ), art );
Christian Thurner's avatar
Christian Thurner committed
271
          art->initListItem();
272
        } else if(art->listItem())
Christian Thurner's avatar
Christian Thurner committed
273
          art->updateListItem();
Christian Thurner's avatar
   
Christian Thurner committed
274

Christian Thurner's avatar
Christian Thurner committed
275
      }
Christian Thurner's avatar
   
Christian Thurner committed
276
277
278

    }

279
280
281
282
283
284
285
286
287
288
    if (current && !current->filterResult()) {   // try to find a parent that is visible
      int idRef;
      while (current && !current->filterResult()) {
        idRef=current->idRef();
        if (idRef == -1)
          break;
        current = g_roup->byId(idRef);
      }
    }

Christian Thurner's avatar
   
Christian Thurner committed
289
290
    if(current && current->filterResult()) {
      if(!current->listItem())
291
        createCompleteThread(current);
292
      v_iew->setActive( current->listItem() );
Christian Thurner's avatar
   
Christian Thurner committed
293
      setFirstChild=false;
Christian Thurner's avatar
Christian Thurner committed
294
295
    }

296
    d_isableExpander=false;
297

298
    if (g_roup->isLocked())
299
      knGlobals.scheduler()->nntpMutex().unlock();
Christian Thurner's avatar
Christian Thurner committed
300
  }
Christian Thurner's avatar
   
Christian Thurner committed
301

302
  else if (f_older) {
Christian Thurner's avatar
   
Christian Thurner committed
303

304
    KNLocalArticle::Ptr art;
305
306
307
308
309
310
311
312
313
    if(f_ilter) {
      f_ilter->doFilter(f_older);
    } else {
      for(int i=0; i<f_older->length(); i++) {
        art=f_older->at(i);
        art->setFilterResult(true);
      }
    }

Christian Thurner's avatar
Christian Thurner committed
314
315
    for(int idx=0; idx<f_older->length(); idx++) {
      art=f_older->at(idx);
316
317

      if(!art->listItem() &&  art->filterResult()) {
318
        art->setListItem( new KNHdrViewItem( v_iew ), art );
Christian Thurner's avatar
   
Christian Thurner committed
319
        art->updateListItem();
320
321
      } else if(art->listItem())
        art->updateListItem();
Christian Thurner's avatar
Christian Thurner committed
322
323
    }

324
  }
Christian Thurner's avatar
   
Christian Thurner committed
325
326
327

  if(setFirstChild && v_iew->firstChild()) {
    v_iew->setCurrentItem(v_iew->firstChild());
328
    knGlobals.top->articleViewer()->setArticle( KNArticle::Ptr() );
329
  }
Christian Thurner's avatar
Christian Thurner committed
330

Volker Krause's avatar
Volker Krause committed
331
  knGlobals.setStatusMsg( QString() );
Christian Thurner's avatar
Christian Thurner committed
332
333
334
335
  updateStatusString();
}


336
void KNArticleManager::updateViewForCollection( KNArticleCollection::Ptr c )
Christian Thurner's avatar
   
Christian Thurner committed
337
338
339
340
341
342
{
  if(g_roup==c || f_older==c)
    showHdrs(false);
}


343
344
345
346
347
void KNArticleManager::updateListViewItems()
{
  if(!g_roup && !f_older) return;

  if(g_roup) {
348
    KNRemoteArticle::Ptr art;
349
350
351
352
353
354
355

    for(int i=0; i<g_roup->length(); i++) {
      art=g_roup->at(i);
      if(art->listItem())
        art->updateListItem();
    }
  } else { //folder
356
    KNLocalArticle::Ptr art;
357
358
359
360
361
362
363
364
365
366

    for(int idx=0; idx<f_older->length(); idx++) {
      art=f_older->at(idx);
      if(art->listItem())
        art->updateListItem();
    }
  }
}


Christian Thurner's avatar
Christian Thurner committed
367
368
void KNArticleManager::setAllThreadsOpen(bool b)
{
369
  KNRemoteArticle::Ptr art;
Christian Thurner's avatar
Christian Thurner committed
370
  if(g_roup) {
371
    ScopedCursorOverride cursor( Qt::WaitCursor );
372
373
374
375
376
377
378
379
380
381
382
383
    d_isableExpander = true;
    for(int idx=0; idx<g_roup->length(); idx++) {
      art = g_roup->at(idx);
      if (art->listItem())
        art->listItem()->setOpen(b);
      else
        if (b && art->filterResult()) {
          createThread(art);
          art->listItem()->setOpen(true);
        }
    }
    d_isableExpander = false;
Christian Thurner's avatar
Christian Thurner committed
384
385
386
  }
}

Dirk Mueller's avatar
Dirk Mueller committed
387

Christian Thurner's avatar
Christian Thurner committed
388
void KNArticleManager::search()
Dirk Mueller's avatar
Dirk Mueller committed
389
{
Christian Thurner's avatar
Christian Thurner committed
390
391
  if(s_earchDlg) {
    s_earchDlg->show();
392
#ifdef Q_OS_UNIX
Luboš Luňák's avatar
Luboš Luňák committed
393
    KWindowSystem::activateWindow(s_earchDlg->winId());
394
#endif
Christian Thurner's avatar
Christian Thurner committed
395
  } else {
396
    s_earchDlg = new SearchDialog( SearchDialog::STgroupSearch, 0 );
Christian Thurner's avatar
Christian Thurner committed
397
398
399
400
401
    connect(s_earchDlg, SIGNAL(doSearch(KNArticleFilter*)), this,
      SLOT(slotFilterChanged(KNArticleFilter*)));
    connect(s_earchDlg, SIGNAL(dialogDone()), this,
      SLOT(slotSearchDialogDone()));
    s_earchDlg->show();
402
  }
Dirk Mueller's avatar
Dirk Mueller committed
403
404
405
}


406
void KNArticleManager::setGroup( KNGroup::Ptr g )
Christian Thurner's avatar
   
Christian Thurner committed
407
{
408
409
410
  g_roup = g;
  if ( g )
    emit aboutToShowGroup();
Christian Thurner's avatar
   
Christian Thurner committed
411
412
413
}


414
void KNArticleManager::setFolder( KNFolder::Ptr f )
Christian Thurner's avatar
   
Christian Thurner committed
415
{
416
417
418
  f_older = f;
  if ( f )
    emit aboutToShowFolder();
Christian Thurner's avatar
   
Christian Thurner committed
419
420
421
}


422
KNArticleCollection::Ptr KNArticleManager::collection()
Christian Thurner's avatar
Christian Thurner committed
423
424
425
426
427
428
{
  if(g_roup)
    return g_roup;
  if(f_older)
   return f_older;

429
  return KNArticleCollection::Ptr();
Christian Thurner's avatar
Christian Thurner committed
430
}
Dirk Mueller's avatar
Dirk Mueller committed
431

Christian Thurner's avatar
Christian Thurner committed
432

433
bool KNArticleManager::loadArticle( KNArticle::Ptr a )
Christian Thurner's avatar
   
Christian Thurner committed
434
{
435
  if (!a)
Christian Thurner's avatar
   
Christian Thurner committed
436
    return false;
437
438

  if (a->hasContent())
Christian Thurner's avatar
   
Christian Thurner committed
439
440
    return true;

441
  if (a->isLocked()) {
Volker Krause's avatar
Volker Krause committed
442
    if ( a->type() == KNArticle::ATremote )
443
      return true;   // locked == we are already loading this article...
Christian Thurner's avatar
   
Christian Thurner committed
444
445
446
447
    else
      return false;
  }

Volker Krause's avatar
Volker Krause committed
448
  if ( a->type() == KNArticle::ATremote ) {
449
    KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( a->collection() );
Christian Thurner's avatar
   
Christian Thurner committed
450
    if(g)
451
      emitJob( new ArticleFetchJob( this, g->account(), a ) );
452
453
    else
      return false;
Christian Thurner's avatar
   
Christian Thurner committed
454
455
  }
  else { // local article
456
    KNFolder::Ptr f = boost::static_pointer_cast<KNFolder>( a->collection() );
457
   if( f && f->loadArticle( boost::static_pointer_cast<KNLocalArticle>( a ) ) )
458
      knGlobals.memoryManager()->updateCacheEntry(a);
459
460
    else
      return false;
Christian Thurner's avatar
   
Christian Thurner committed
461
  }
462
463
464
465
  return true;
}


466
bool KNArticleManager::unloadArticle( KNArticle::Ptr a, bool force )
467
468
469
470
471
472
473
474
475
{
  if(!a || a->isLocked() )
    return false;
  if(!a->hasContent())
    return true;

  if (!force && a->isNotUnloadable())
    return false;

476
  if ( !force && ( ArticleWidget::articleVisible( a ) ) )
477
478
    return false;

Volker Krause's avatar
Volker Krause committed
479
  if (!force && ( a->type()== KNArticle::ATlocal ) &&
480
      ( KNGlobals::self()->articleFactory()->findComposer( boost::static_pointer_cast<KNLocalArticle>( a ) ) != 0 ) )
481
482
    return false;

483
  if ( !ArticleWindow::closeAllWindowsForArticle( a, force ) )
484
485
486
    if (!force)
      return false;

487
  ArticleWidget::articleRemoved( a );
Volker Krause's avatar
Volker Krause committed
488
  if ( a->type() != KNArticle::ATlocal )
489
    KNGlobals::self()->articleFactory()->deleteComposerForArticle( boost::static_pointer_cast<KNLocalArticle>( a ) );
490
  a->updateListItem();
491
  knGlobals.memoryManager()->removeCacheEntry(a);
492
493

  return true;
Christian Thurner's avatar
   
Christian Thurner committed
494
495
496
}


497
void KNArticleManager::copyIntoFolder( KNArticle::List &l, KNFolder::Ptr f )
Christian Thurner's avatar
   
Christian Thurner committed
498
499
500
{
  if(!f) return;

501
  KNLocalArticle::Ptr loc;
Christian Thurner's avatar
   
Christian Thurner committed
502
503
  KNLocalArticle::List l2;

504
505
  for ( KNArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
    if ( !(*it)->hasContent() )
Christian Thurner's avatar
   
Christian Thurner committed
506
      continue;
507
    loc = KNLocalArticle::Ptr( new KNLocalArticle( KNArticleCollection::Ptr() ) );
Christian Thurner's avatar
   
Christian Thurner committed
508
    loc->setEditDisabled(true);
509
    loc->setContent( (*it)->encodedContent() );
Christian Thurner's avatar
   
Christian Thurner committed
510
511
512
513
    loc->parse();
    l2.append(loc);
  }

514
  if ( !l2.isEmpty() ) {
Christian Thurner's avatar
   
Christian Thurner committed
515

516
517
    f->setNotUnloadable(true);

518
    if ( !f->isLoaded() && !knGlobals.folderManager()->loadHeaders( f ) ) {
Christian Thurner's avatar
   
Christian Thurner committed
519
      l2.clear();
520
      f->setNotUnloadable(false);
Christian Thurner's avatar
   
Christian Thurner committed
521
522
523
      return;
    }

524
525
526
    if( !f->saveArticles( l2 ) ) {
      for ( KNLocalArticle::List::Iterator it = l2.begin(); it != l2.end(); ++it ) {
        if ( (*it)->isOrphant() )
527
          (*it).reset(); // ok, this is ugly; we simply delete orphant articles
Christian Thurner's avatar
   
Christian Thurner committed
528
        else
529
          (*it)->KMime::Content::clear(); // no need to keep them in memory
Christian Thurner's avatar
   
Christian Thurner committed
530
531
      }
      KNHelper::displayInternalFileError();
532
    } else {
533
      for ( KNLocalArticle::List::Iterator it = l2.begin(); it != l2.end(); ++it )
534
        (*it)->KMime::Content::clear(); // no need to keep them in memory
535
      knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
Christian Thurner's avatar
   
Christian Thurner committed
536
    }
537
538

    f->setNotUnloadable(false);
Christian Thurner's avatar
   
Christian Thurner committed
539
540
541
542
  }
}


543
void KNArticleManager::moveIntoFolder( KNLocalArticle::List &l, KNFolder::Ptr f )
Christian Thurner's avatar
   
Christian Thurner committed
544
545
{
  if(!f) return;
Thiago Macieira's avatar
Thiago Macieira committed
546
  kDebug(5003) <<" Target folder:" << f->name();
Christian Thurner's avatar
   
Christian Thurner committed
547

548
549
  f->setNotUnloadable(true);

550
  if (!f->isLoaded() && !knGlobals.folderManager()->loadHeaders(f)) {
551
552
    f->setNotUnloadable(false);
    return;
Christian Thurner's avatar
   
Christian Thurner committed
553
554
  }

555
556
  if ( f->saveArticles( l ) ) {
    for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it )
557
558
      knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticle>(*it) );
    knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
559
  } else {
560
561
    for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it )
      if ( (*it)->isOrphant() )
562
        (*it).reset(); // ok, this is ugly; we simply delete orphant articles
Christian Thurner's avatar
   
Christian Thurner committed
563
564
    KNHelper::displayInternalFileError();
  }
565
566

  f->setNotUnloadable(false);
Christian Thurner's avatar
   
Christian Thurner committed
567
568
569
570
571
572
573
}


bool KNArticleManager::deleteArticles(KNLocalArticle::List &l, bool ask)
{
  if(ask) {
    QStringList lst;
574
575
    for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
      if ( (*it)->isLocked() )
Christian Thurner's avatar
   
Christian Thurner committed
576
        continue;
577
      if ( (*it)->subject()->isEmpty() )
Christian Thurner's avatar
   
Christian Thurner committed
578
579
        lst << i18n("no subject");
      else
580
        lst << (*it)->subject()->asUnicodeString();
Christian Thurner's avatar
   
Christian Thurner committed
581
    }
Stephan Binner's avatar
Stephan Binner committed
582
583
    if( KMessageBox::Cancel == KMessageBox::warningContinueCancelList(
      knGlobals.topWidget, i18n("Do you really want to delete these articles?"), lst,
Aaron J. Seigo's avatar
Aaron J. Seigo committed
584
        i18n("Delete Articles"), KGuiItem(i18n("&Delete"),"edit-delete")) )
Christian Thurner's avatar
   
Christian Thurner committed
585
586
587
      return false;
  }

588
  for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it )
589
    knGlobals.memoryManager()->removeCacheEntry( boost::static_pointer_cast<KNArticle>(*it) );
Christian Thurner's avatar
   
Christian Thurner committed
590

591
  KNFolder::Ptr f = boost::static_pointer_cast<KNFolder>( l.first()->collection() );
592
593
  if ( f ) {
    f->removeArticles( l, true );
594
    knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
595
    return false; // composers for those articles were already removed in removeArticles
Olivier Trichet's avatar
Olivier Trichet committed
596
597
  } else {
    l.clear();
Christian Thurner's avatar
   
Christian Thurner committed
598
599
600
601
602
603
  }

  return true;
}


604
void KNArticleManager::setAllRead( bool read, int lastcount )
Dirk Mueller's avatar
Dirk Mueller committed
605
{
606
  if ( !g_roup )
Christian Thurner's avatar
Christian Thurner committed
607
608
    return;

609
610
611
612
  int groupLength = g_roup->length();
  int newCount = g_roup->newCount();
  int readCount = g_roup->readCount();
  int offset = lastcount;
Christian Thurner's avatar
Christian Thurner committed
613

614
615
  if ( lastcount > groupLength || lastcount < 0 )
    offset = groupLength;
616

617
  KNRemoteArticle::Ptr a;
618
619
620
621
622
623
  for ( int i = groupLength - offset; i < groupLength; i++ ) {
    a = g_roup->at( i );
    if ( a->getReadFlag() != read && !a->isIgnored() ) {
      a->setRead( read );
      a->setChanged( true );
      if ( !read ) {
624
        readCount--;
625
        if ( a->isNew() )
626
          newCount++;
627
      } else {
628
        readCount++;
629
        if ( a->isNew() )
630
631
632
633
634
635
          newCount--;
      }
    }
  }

  g_roup->updateThreadInfo();
636
637
638
639
640
641
642
643
  if ( lastcount < 0 && read ) {
    // HACK: try to hide the effects of the ignore/filter new/unread count bug
    g_roup->setReadCount( groupLength );
    g_roup->setNewCount( 0 );
  } else {
    g_roup->setReadCount( readCount );
    g_roup->setNewCount( newCount );
  }
644
645

  g_roup->updateListItem();
646
  showHdrs( true );
647
648
649
}


Christian Thurner's avatar
   
Christian Thurner committed
650
void KNArticleManager::setRead(KNRemoteArticle::List &l, bool r, bool handleXPosts)
Christian Thurner's avatar
Christian Thurner committed
651
{
652
  if ( l.isEmpty() )
Christian Thurner's avatar
Christian Thurner committed
653
654
    return;

655
  KNRemoteArticle::Ptr ref;
656
  KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( l.first()->collection() );
Christian Thurner's avatar
Christian Thurner committed
657
658
  int changeCnt=0, idRef=0;

659
  for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
Volker Krause's avatar
Volker Krause committed
660
    if( r && knGlobals.settings()->markCrossposts() &&
661
        handleXPosts && (*it)->newsgroups()->isCrossposted() ) {
662

Volker Krause's avatar
Volker Krause committed
663
      QList<QByteArray> groups = (*it)->newsgroups()->groups();
664
      KNGroup::Ptr targetGroup;
665
      KNRemoteArticle::Ptr xp;
Christian Thurner's avatar
   
Christian Thurner committed
666
      KNRemoteArticle::List al;
667
      QByteArray mid = (*it)->messageID()->as7BitString( false );
668

Volker Krause's avatar
Volker Krause committed
669
      for ( QList<QByteArray>::Iterator it2 = groups.begin(); it2 != groups.end(); ++it2 ) {
670
        targetGroup = knGlobals.groupManager()->group(*it2, g->account());
671
672
673
674
675
676
677
678
        if (targetGroup) {
          if (targetGroup->isLoaded() && (xp=targetGroup->byMessageId(mid)) ) {
            al.clear();
            al.append(xp);
            setRead(al, r, false);
          } else {
            targetGroup->appendXPostID(mid);
          }
Christian Thurner's avatar
   
Christian Thurner committed
679
680
681
        }
      }
    }
Christian Thurner's avatar
Christian Thurner committed
682

683
684
685
686
    else if ( (*it)->getReadFlag() != r ) {
      (*it)->setRead( r );
      (*it)->setChanged( true );
      (*it)->updateListItem();
Christian Thurner's avatar
Christian Thurner committed
687

688
      if ( !(*it)->isIgnored() ) {
689
        changeCnt++;
690
        idRef = (*it)->idRef();
691

692
        while ( idRef != 0 ) {
693
694
695
          ref=g->byId(idRef);
          if(r) {
            ref->decUnreadFollowUps();
696
            if ( (*it)->isNew() )
697
698
699
700
              ref->decNewFollowUps();
          }
          else {
            ref->incUnreadFollowUps();
701
            if ( (*it)->isNew() )
702
703
704
705
706
707
708
709
710
711
              ref->incNewFollowUps();
          }

          if(ref->listItem() &&
             ((ref->unreadFollowUps()==0 || ref->unreadFollowUps()==1) ||
              (ref->newFollowUps()==0 || ref->newFollowUps()==1)))
            ref->updateListItem();

          idRef=ref->idRef();
        }
Christian Thurner's avatar
Christian Thurner committed
712
713

        if(r) {
714
          g->incReadCount();
715
          if ( (*it)->isNew() )
716
            g->decNewCount();
Christian Thurner's avatar
Christian Thurner committed
717
718
        }
        else {
719
          g->decReadCount();
720
          if ( (*it)->isNew() )
721
            g->incNewCount();
Christian Thurner's avatar
Christian Thurner committed
722
723
724
725
726
727
728
729
730
731
732
733
734
        }
      }
    }
  }

  if(changeCnt>0) {
    g->updateListItem();
    if(g==g_roup)
      updateStatusString();
  }
}


735
736
737
738
void KNArticleManager::setAllNotNew()
{
  if ( !g_roup )
    return;
739
  KNRemoteArticle::Ptr a;
740
741
742
743
744
745
746
747
748
749
750
751
  for ( int i = 0; i < g_roup->length(); ++i) {
    a = g_roup->at(i);
    if ( a->isNew() ) {
      a->setNew( false );
      a->setChanged( true );
    }
  }
  g_roup->setFirstNewIndex( -1 );
  g_roup->setNewCount( 0 );
  g_roup->updateThreadInfo();
}

Christian Thurner's avatar
   
Christian Thurner committed
752

753
bool KNArticleManager::toggleWatched(KNRemoteArticle::List &l)
Christian Thurner's avatar
Christian Thurner committed
754
{
755
  if(l.isEmpty())
756
    return true;
757

758
759
  KNRemoteArticle::Ptr a = l.first();
  KNRemoteArticle::Ptr ref;
760
  bool watch = (!a->isWatched());
761
  KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( a->collection() );
762
  int changeCnt=0, idRef=0;
763

764
765
766
  for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
    if ( (*it)->isIgnored() ) {
      (*it)->setIgnored(false);
767

768
      if ( !(*it)->getReadFlag() ) {
769
        changeCnt++;
770
        idRef = (*it)->idRef();
771

772
        while ( idRef != 0 ) {
773
774
775
          ref=g->byId(idRef);

          ref->incUnreadFollowUps();
776
          if ( (*it)->isNew() )
777
778
779
780
781
782
783
784
785
786
            ref->incNewFollowUps();

          if(ref->listItem() &&
             ((ref->unreadFollowUps()==0 || ref->unreadFollowUps()==1) ||
              (ref->newFollowUps()==0 || ref->newFollowUps()==1)))
            ref->updateListItem();

          idRef=ref->idRef();
        }
        g->decReadCount();
787
        if ( (*it)->isNew() )
788
789
790
791
          g->incNewCount();
      }
    }

792
793
794
    (*it)->setWatched( watch );
    (*it)->updateListItem();
    (*it)->setChanged( true );
Christian Thurner's avatar
Christian Thurner committed
795
  }
796
797
798
799
800
801

  if(changeCnt>0) {
    g->updateListItem();
    if(g==g_roup)
      updateStatusString();
  }
802
803

  return watch;
Christian Thurner's avatar
Christian Thurner committed
804
805
806
}


807
bool KNArticleManager::toggleIgnored(KNRemoteArticle::List &l)
Christian Thurner's avatar
Christian Thurner committed
808
{
809
  if(l.isEmpty())
810
    return true;
811

812
  KNRemoteArticle::Ptr ref;
813
  bool ignore = !l.first()->isIgnored();
814
  KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( l.first()->collection() );
815
  int changeCnt = 0, idRef = 0;
816

817
818
819
820
  for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
    (*it)->setWatched(false);
    if ( (*it)->isIgnored() != ignore ) {
      (*it)->setIgnored( ignore );
821

822
      if ( !(*it)->getReadFlag() ) {
823
        changeCnt++;
824
        idRef = (*it)->idRef();
825

826
827
        while ( idRef != 0 ) {
          ref = g->byId( idRef );
828

829
          if ( ignore ) {
830
            ref->decUnreadFollowUps();
831
            if ( (*it)->isNew() )
832
              ref->decNewFollowUps();
Volker Krause's avatar