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
18 #include <kmessagebox.h>
19 #include <kmimetypetrader.h>
22 #include <kwindowsystem.h>
23 #include <ktemporaryfile.h>
25 #include "articlewidget.h"
26 #include "knmainwidget.h"
27 #include "knglobals.h"
28 #include "utilities.h"
29 #include "knarticlemanager.h"
30 #include "kngroupmanager.h"
31 #include "knsearchdialog.h"
32 #include "knfiltermanager.h"
34 #include "knarticlefilter.h"
35 #include "knhdrviewitem.h"
36 #include "scheduler.h"
37 #include "knnntpaccount.h"
38 #include "knscoring.h"
39 #include "knmemorymanager.h"
40 #include "knarticlefactory.h"
41 #include "knarticlewindow.h"
42 #include "knfoldermanager.h"
43 #include "headerview.h"
47 using namespace KNode
;
50 KNArticleManager::KNArticleManager() : QObject(0)
54 f_ilterMgr
= knGlobals
.filterManager();
55 f_ilter
= f_ilterMgr
->currentFilter();
57 d_isableExpander
=false;
59 connect(f_ilterMgr
, SIGNAL(filterChanged(KNArticleFilter
*)), this,
60 SLOT(slotFilterChanged(KNArticleFilter
*)));
64 KNArticleManager::~KNArticleManager()
70 void KNArticleManager::deleteTempFiles()
72 for ( QList
<KTemporaryFile
*>::Iterator it
= mTempFiles
.begin(); it
!= mTempFiles
.end(); ++it
) {
79 void KNArticleManager::saveContentToFile(KMime::Content
*c
, QWidget
*parent
)
81 KNSaveHelper
helper(c
->contentType()->name(),parent
);
83 QFile
*file
= helper
.getFile(i18n("Save Attachment"));
86 QByteArray data
=c
->decodedContent();
87 if (file
->write(data
.data(), data
.size()) == -1 )
88 KNHelper::displayExternalFileError( parent
);
93 void KNArticleManager::saveArticleToFile(KNArticle
*a
, QWidget
*parent
)
95 QString fName
= a
->subject()->asUnicodeString();
98 for ( int i
= 0; i
< fName
.length(); ++i
)
99 if (fName
[i
].isLetterOrNumber())
103 fName
= s
.simplified();
104 fName
.replace(QRegExp("[\\s]"),"_");
106 KNSaveHelper
helper(fName
,parent
);
107 QFile
*file
= helper
.getFile(i18n("Save Article"));
110 QByteArray tmp
=a
->encodedContent(false);
111 if ( file
->write(tmp
.data(), tmp
.size()) == -1 )
112 KNHelper::displayExternalFileError( parent
);
117 QString
KNArticleManager::saveContentToTemp(KMime::Content
*c
)
120 KTemporaryFile
* tmpFile
;
121 KMime::Headers::Base
*pathHdr
=c
->headerByType("X-KNode-Tempfile"); // check for existing temp file
124 path
= pathHdr
->asUnicodeString();
127 // lets see if the tempfile-path is still valid...
128 for ( QList
<KTemporaryFile
*>::Iterator it
= mTempFiles
.begin(); it
!= mTempFiles
.end(); ++it
) {
129 if ( (*it
)->fileName() == path
) {
138 c
->removeHeader("X-KNode-Tempfile");
141 tmpFile
=new KTemporaryFile();
142 if (!tmpFile
->open()) {
143 KNHelper::displayTempFileError();
148 mTempFiles
.append(tmpFile
);
149 QByteArray data
=c
->decodedContent();
150 tmpFile
->write(data
.data(), data
.size());
152 path
=tmpFile
->fileName();
153 pathHdr
=new KMime::Headers::Generic("X-KNode-Tempfile", c
, path
, "UTF-8");
154 c
->setHeader(pathHdr
);
160 void KNArticleManager::openContent(KMime::Content
*c
)
162 QString path
=saveContentToTemp(c
);
163 if(path
.isNull()) return;
165 KService::Ptr offer
= KMimeTypeTrader::self()->preferredService(c
->contentType()->mimeType(), "Application");
172 KRun::run(*offer
, lst
, knGlobals
.top
);
174 KRun::displayOpenWithDialog(lst
, knGlobals
.top
);
178 void KNArticleManager::showHdrs(bool clear
)
180 if(!g_roup
&& !f_older
) return;
182 bool setFirstChild
=true;
183 bool showThreads
=knGlobals
.settings()->showThreads();
184 bool expandThreads
=knGlobals
.settings()->defaultToExpandedThreads();
189 knGlobals
.top
->setCursorBusy(true);
190 knGlobals
.setStatusMsg(i18n(" Creating list..."));
191 knGlobals
.top
->secureProcessEvents();
194 KNRemoteArticle
*art
, *ref
, *current
;
196 current
= static_cast<KNRemoteArticle
*>( knGlobals
.top
->articleViewer()->article() );
198 if(current
&& (current
->collection() != g_roup
)) {
200 knGlobals
.top
->articleViewer()->setArticle( 0 );
203 if(g_roup
->isLocked())
204 knGlobals
.scheduler()->nntpMutex().lock();
207 f_ilter
->doFilter(g_roup
);
209 for(int i
=0; i
<g_roup
->length(); i
++) {
211 art
->setFilterResult(true);
212 art
->setFiltered(true);
213 ref
=(art
->idRef()!=0) ? g_roup
->byId(art
->idRef()) : 0;
214 art
->setDisplayedReference(ref
);
216 ref
->setVisibleFollowUps(true);
219 d_isableExpander
=true;
221 for(int i
=0; i
<g_roup
->length(); i
++) {
224 art
->setThreadMode(showThreads
);
227 art
->propagateThreadChangedDate();
229 if( !art
->listItem() && art
->filterResult() ) {
231 // ### disable delayed header view item creation for now, it breaks
233 // since it doesn't seem to improve performance at all, it probably
234 // could be removed entirely (see also slotItemExpanded(), etc.)
235 /*if (!expandThreads) {
237 if( (ref=art->displayedReference()) ) {
239 if( ref->listItem() && ( ref->listItem()->isOpen() || ref->listItem()->childCount()>0 ) ) {
240 art->setListItem(new KNHdrViewItem(ref->listItem()));
246 art->setListItem(new KNHdrViewItem(v_iew));
250 } else { // expandThreads == true */
253 art
->listItem()->setOpen(true);
257 else if(art
->listItem()) {
258 art
->updateListItem();
260 art
->listItem()->setOpen(true);
266 if(!art
->listItem() && art
->filterResult()) {
267 art
->setListItem(new KNHdrViewItem(v_iew
));
269 } else if(art
->listItem())
270 art
->updateListItem();
276 if (current
&& !current
->filterResult()) { // try to find a parent that is visible
278 while (current
&& !current
->filterResult()) {
279 idRef
=current
->idRef();
282 current
= g_roup
->byId(idRef
);
286 if(current
&& current
->filterResult()) {
287 if(!current
->listItem())
288 createCompleteThread(current
);
289 v_iew
->setActive( current
->listItem() );
293 d_isableExpander
=false;
295 if (g_roup
->isLocked())
296 knGlobals
.scheduler()->nntpMutex().unlock();
303 f_ilter
->doFilter(f_older
);
305 for(int i
=0; i
<f_older
->length(); i
++) {
307 art
->setFilterResult(true);
311 for(int idx
=0; idx
<f_older
->length(); idx
++) {
312 art
=f_older
->at(idx
);
314 if(!art
->listItem() && art
->filterResult()) {
315 art
->setListItem( new KNHdrViewItem(v_iew
, art
) );
316 art
->updateListItem();
317 } else if(art
->listItem())
318 art
->updateListItem();
323 if(setFirstChild
&& v_iew
->firstChild()) {
324 v_iew
->setCurrentItem(v_iew
->firstChild());
325 knGlobals
.top
->articleViewer()->setArticle( 0 );
328 knGlobals
.setStatusMsg( QString() );
329 updateStatusString();
330 knGlobals
.top
->setCursorBusy(false);
334 void KNArticleManager::updateViewForCollection(KNArticleCollection
*c
)
336 if(g_roup
==c
|| f_older
==c
)
341 void KNArticleManager::updateListViewItems()
343 if(!g_roup
&& !f_older
) return;
346 KNRemoteArticle
*art
;
348 for(int i
=0; i
<g_roup
->length(); i
++) {
351 art
->updateListItem();
356 for(int idx
=0; idx
<f_older
->length(); idx
++) {
357 art
=f_older
->at(idx
);
359 art
->updateListItem();
365 void KNArticleManager::setAllThreadsOpen(bool b
)
367 KNRemoteArticle
*art
;
369 knGlobals
.top
->setCursorBusy(true);
370 d_isableExpander
= true;
371 for(int idx
=0; idx
<g_roup
->length(); idx
++) {
372 art
= g_roup
->at(idx
);
374 art
->listItem()->setOpen(b
);
376 if (b
&& art
->filterResult()) {
378 art
->listItem()->setOpen(true);
381 d_isableExpander
= false;
382 knGlobals
.top
->setCursorBusy(false);
387 void KNArticleManager::search()
392 KWindowSystem::activateWindow(s_earchDlg
->winId());
395 s_earchDlg
= new SearchDialog( SearchDialog::STgroupSearch
, 0 );
396 connect(s_earchDlg
, SIGNAL(doSearch(KNArticleFilter
*)), this,
397 SLOT(slotFilterChanged(KNArticleFilter
*)));
398 connect(s_earchDlg
, SIGNAL(dialogDone()), this,
399 SLOT(slotSearchDialogDone()));
405 void KNArticleManager::setGroup(KNGroup
*g
)
409 emit
aboutToShowGroup();
413 void KNArticleManager::setFolder(KNFolder
*f
)
417 emit
aboutToShowFolder();
421 KNArticleCollection
* KNArticleManager::collection()
432 bool KNArticleManager::loadArticle(KNArticle
*a
)
441 if ( a
->type() == KNArticle::ATremote
)
442 return true; // locked == we are already loading this article...
447 if ( a
->type() == KNArticle::ATremote
) {
448 KNGroup
*g
=static_cast<KNGroup
*>(a
->collection());
450 emitJob( new ArticleFetchJob( this, g
->account(), a
) );
454 else { // local article
455 KNFolder
*f
=static_cast<KNFolder
*>(a
->collection());
456 if( f
&& f
->loadArticle( static_cast<KNLocalArticle
*>(a
) ) )
457 knGlobals
.memoryManager()->updateCacheEntry(a
);
465 bool KNArticleManager::unloadArticle(KNArticle
*a
, bool force
)
467 if(!a
|| a
->isLocked() )
472 if (!force
&& a
->isNotUnloadable())
475 if ( !force
&& ( ArticleWidget::articleVisible( a
) ) )
478 if (!force
&& ( a
->type()== KNArticle::ATlocal
) &&
479 (knGlobals
.artFactory
->findComposer(static_cast<KNLocalArticle
*>(a
))!=0))
482 if ( !ArticleWindow::closeAllWindowsForArticle( a
, force
) )
486 ArticleWidget::articleRemoved( a
);
487 if ( a
->type() != KNArticle::ATlocal
)
488 knGlobals
.artFactory
->deleteComposerForArticle(static_cast<KNLocalArticle
*>(a
));
491 knGlobals
.memoryManager()->removeCacheEntry(a
);
497 void KNArticleManager::copyIntoFolder(KNArticle::List
&l
, KNFolder
*f
)
502 KNLocalArticle::List l2
;
504 for ( KNArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
505 if ( !(*it
)->hasContent() )
507 loc
=new KNLocalArticle(0);
508 loc
->setEditDisabled(true);
509 loc
->setContent( (*it
)->encodedContent() );
514 if ( !l2
.isEmpty() ) {
516 f
->setNotUnloadable(true);
518 if ( !f
->isLoaded() && !knGlobals
.folderManager()->loadHeaders( f
) ) {
519 for ( KNLocalArticle::List::Iterator it
= l2
.begin(); it
!= l2
.end(); ++it
)
522 f
->setNotUnloadable(false);
526 if( !f
->saveArticles( l2
) ) {
527 for ( KNLocalArticle::List::Iterator it
= l2
.begin(); it
!= l2
.end(); ++it
) {
528 if ( (*it
)->isOrphant() )
529 delete (*it
); // ok, this is ugly; we simply delete orphant articles
531 (*it
)->Content::clear(); // no need to keep them in memory
533 KNHelper::displayInternalFileError();
535 for ( KNLocalArticle::List::Iterator it
= l2
.begin(); it
!= l2
.end(); ++it
)
536 (*it
)->Content::clear(); // no need to keep them in memory
537 knGlobals
.memoryManager()->updateCacheEntry(f
);
540 f
->setNotUnloadable(false);
545 void KNArticleManager::moveIntoFolder(KNLocalArticle::List
&l
, KNFolder
*f
)
548 kDebug(5003) <<" Target folder:" << f
->name();
550 f
->setNotUnloadable(true);
552 if (!f
->isLoaded() && !knGlobals
.folderManager()->loadHeaders(f
)) {
553 f
->setNotUnloadable(false);
557 if ( f
->saveArticles( l
) ) {
558 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
)
559 knGlobals
.memoryManager()->updateCacheEntry( (*it
) );
560 knGlobals
.memoryManager()->updateCacheEntry(f
);
562 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
)
563 if ( (*it
)->isOrphant() )
564 delete (*it
); // ok, this is ugly; we simply delete orphant articles
565 KNHelper::displayInternalFileError();
568 f
->setNotUnloadable(false);
572 bool KNArticleManager::deleteArticles(KNLocalArticle::List
&l
, bool ask
)
576 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
577 if ( (*it
)->isLocked() )
579 if ( (*it
)->subject()->isEmpty() )
580 lst
<< i18n("no subject");
582 lst
<< (*it
)->subject()->asUnicodeString();
584 if( KMessageBox::Cancel
== KMessageBox::warningContinueCancelList(
585 knGlobals
.topWidget
, i18n("Do you really want to delete these articles?"), lst
,
586 i18n("Delete Articles"), KGuiItem(i18n("&Delete"),"edit-delete")) )
590 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
)
591 knGlobals
.memoryManager()->removeCacheEntry( (*it
) );
593 KNFolder
*f
=static_cast<KNFolder
*>(l
.first()->collection());
595 f
->removeArticles( l
, true );
596 knGlobals
.memoryManager()->updateCacheEntry( f
);
597 return false; // composers for those articles were already removed in removeArticles
600 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
)
608 void KNArticleManager::setAllRead( bool read
, int lastcount
)
613 int groupLength
= g_roup
->length();
614 int newCount
= g_roup
->newCount();
615 int readCount
= g_roup
->readCount();
616 int offset
= lastcount
;
618 if ( lastcount
> groupLength
|| lastcount
< 0 )
619 offset
= groupLength
;
622 for ( int i
= groupLength
- offset
; i
< groupLength
; i
++ ) {
624 if ( a
->getReadFlag() != read
&& !a
->isIgnored() ) {
626 a
->setChanged( true );
639 g_roup
->updateThreadInfo();
640 if ( lastcount
< 0 && read
) {
641 // HACK: try to hide the effects of the ignore/filter new/unread count bug
642 g_roup
->setReadCount( groupLength
);
643 g_roup
->setNewCount( 0 );
645 g_roup
->setReadCount( readCount
);
646 g_roup
->setNewCount( newCount
);
649 g_roup
->updateListItem();
654 void KNArticleManager::setRead(KNRemoteArticle::List
&l
, bool r
, bool handleXPosts
)
659 KNRemoteArticle
*ref
= 0;
660 KNGroup
*g
=static_cast<KNGroup
*>( l
.first()->collection() );
661 int changeCnt
=0, idRef
=0;
663 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
664 if( r
&& knGlobals
.settings()->markCrossposts() &&
665 handleXPosts
&& (*it
)->newsgroups()->isCrossposted() ) {
667 QList
<QByteArray
> groups
= (*it
)->newsgroups()->groups();
668 KNGroup
*targetGroup
=0;
669 KNRemoteArticle
*xp
=0;
670 KNRemoteArticle::List al
;
671 QByteArray mid
= (*it
)->messageID()->as7BitString( false );
673 for ( QList
<QByteArray
>::Iterator it2
= groups
.begin(); it2
!= groups
.end(); ++it2
) {
674 targetGroup
= knGlobals
.groupManager()->group(*it2
, g
->account());
676 if (targetGroup
->isLoaded() && (xp
=targetGroup
->byMessageId(mid
)) ) {
679 setRead(al
, r
, false);
681 targetGroup
->appendXPostID(mid
);
687 else if ( (*it
)->getReadFlag() != r
) {
689 (*it
)->setChanged( true );
690 (*it
)->updateListItem();
692 if ( !(*it
)->isIgnored() ) {
694 idRef
= (*it
)->idRef();
696 while ( idRef
!= 0 ) {
699 ref
->decUnreadFollowUps();
700 if ( (*it
)->isNew() )
701 ref
->decNewFollowUps();
704 ref
->incUnreadFollowUps();
705 if ( (*it
)->isNew() )
706 ref
->incNewFollowUps();
709 if(ref
->listItem() &&
710 ((ref
->unreadFollowUps()==0 || ref
->unreadFollowUps()==1) ||
711 (ref
->newFollowUps()==0 || ref
->newFollowUps()==1)))
712 ref
->updateListItem();
719 if ( (*it
)->isNew() )
724 if ( (*it
)->isNew() )
734 updateStatusString();
739 void KNArticleManager::setAllNotNew()
744 for ( int i
= 0; i
< g_roup
->length(); ++i
) {
748 a
->setChanged( true );
751 g_roup
->setFirstNewIndex( -1 );
752 g_roup
->setNewCount( 0 );
753 g_roup
->updateThreadInfo();
757 bool KNArticleManager::toggleWatched(KNRemoteArticle::List
&l
)
762 KNRemoteArticle
*a
=l
.first(), *ref
=0;
763 bool watch
= (!a
->isWatched());
764 KNGroup
*g
=static_cast<KNGroup
*>(a
->collection() );
765 int changeCnt
=0, idRef
=0;
767 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
768 if ( (*it
)->isIgnored() ) {
769 (*it
)->setIgnored(false);
771 if ( !(*it
)->getReadFlag() ) {
773 idRef
= (*it
)->idRef();
775 while ( idRef
!= 0 ) {
778 ref
->incUnreadFollowUps();
779 if ( (*it
)->isNew() )
780 ref
->incNewFollowUps();
782 if(ref
->listItem() &&
783 ((ref
->unreadFollowUps()==0 || ref
->unreadFollowUps()==1) ||
784 (ref
->newFollowUps()==0 || ref
->newFollowUps()==1)))
785 ref
->updateListItem();
790 if ( (*it
)->isNew() )
795 (*it
)->setWatched( watch
);
796 (*it
)->updateListItem();
797 (*it
)->setChanged( true );
803 updateStatusString();
810 bool KNArticleManager::toggleIgnored(KNRemoteArticle::List
&l
)
815 KNRemoteArticle
*ref
= 0;
816 bool ignore
= !l
.first()->isIgnored();
817 KNGroup
*g
= static_cast<KNGroup
*>( l
.first()->collection() );
818 int changeCnt
= 0, idRef
= 0;
820 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
821 (*it
)->setWatched(false);
822 if ( (*it
)->isIgnored() != ignore
) {
823 (*it
)->setIgnored( ignore
);
825 if ( !(*it
)->getReadFlag() ) {
827 idRef
= (*it
)->idRef();
829 while ( idRef
!= 0 ) {
830 ref
= g
->byId( idRef
);
833 ref
->decUnreadFollowUps();
834 if ( (*it
)->isNew() )
835 ref
->decNewFollowUps();
837 ref
->incUnreadFollowUps();
838 if ( (*it
)->isNew() )
839 ref
->incNewFollowUps();
842 if(ref
->listItem() &&
843 ((ref
->unreadFollowUps()==0 || ref
->unreadFollowUps()==1) ||
844 (ref
->newFollowUps()==0 || ref
->newFollowUps()==1)))
845 ref
->updateListItem();
852 if ( (*it
)->isNew() )
856 if ( (*it
)->isNew() )
862 (*it
)->updateListItem();
863 (*it
)->setChanged(true);
869 updateStatusString();
876 void KNArticleManager::rescoreArticles(KNRemoteArticle::List
&l
)
881 KNGroup
*g
= static_cast<KNGroup
*>( l
.first()->collection() );
882 KScoringManager
*sm
= knGlobals
.scoringManager();
883 sm
->initCache(g
->groupname());
885 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
887 if ( (*it
)->isIgnored())
888 defScore
= knGlobals
.settings()->ignoredThreshold();
889 else if ( (*it
)->isWatched() )
890 defScore
= knGlobals
.settings()->watchedThreshold();
891 (*it
)->setScore(defScore
);
893 bool read
= (*it
)->isRead();
895 KNScorableArticle
sa( (*it
) );
897 (*it
)->updateListItem();
898 (*it
)->setChanged( true );
900 if ( !read
&& (*it
)->isRead() != read
)
901 g_roup
->incReadCount();
906 void KNArticleManager::processJob(KNJobData
*j
)
908 if(j
->type()==KNJobData::JTfetchArticle
&& !j
->canceled()) {
909 KNRemoteArticle
*a
= static_cast<KNRemoteArticle
*>( j
->data() );
911 ArticleWidget::articleChanged( a
);
912 if(!a
->isOrphant()) //orphant articles are deleted by the displaying widget
913 knGlobals
.memoryManager()->updateCacheEntry(a
);
917 if ( j
->error() == KIO::ERR_DOES_NOT_EXIST
) {
918 // article is not available at the server anymore
919 QString msgId
= a
->messageID()->as7BitString( false );
920 // strip of '<' and '>'
921 msgId
= msgId
.mid( 1, msgId
.length() - 2 );
922 ArticleWidget::articleLoadError( a
,
923 i18n("The article you requested is not available on your news server."
924 "<br />You could try to get it from <a href=\"http://groups.google.com/groups?selm=%1\">groups.google.com</a>.",
926 // mark article as read
927 if ( knGlobals
.settings()->autoMark() && !a
->isOrphant() ) {
928 KNRemoteArticle::List l
;
933 ArticleWidget::articleLoadError( a
, j
->errorString() );
941 void KNArticleManager::createThread(KNRemoteArticle
*a
)
943 KNRemoteArticle
*ref
=a
->displayedReference();
948 a
->setListItem(new KNHdrViewItem(ref
->listItem()));
951 a
->setListItem(new KNHdrViewItem(v_iew
));
953 a
->setThreadMode( knGlobals
.settings()->showThreads() );
958 void KNArticleManager::createCompleteThread(KNRemoteArticle
*a
)
960 KNRemoteArticle
*ref
=a
->displayedReference(), *art
, *top
;
962 bool showThreads
= knGlobals
.settings()->showThreads();
964 while (ref
->displayedReference() != 0)
965 ref
=ref
->displayedReference();
969 if (!top
->listItem()) // shouldn't happen
972 for(int i
=0; i
<g_roup
->count(); i
++) {
974 if(art
->filterResult() && !art
->listItem()) {
976 if(art
->displayedReference()==top
) {
977 art
->setListItem(new KNHdrViewItem(top
->listItem()));
978 art
->setThreadMode(showThreads
);
982 ref
=art
->displayedReference();
984 while(ref
&& !inThread
) {
986 ref
=ref
->displayedReference();
994 if ( knGlobals
.settings()->totalExpandThreads() )
995 top
->listItem()->expandChildren();
999 void KNArticleManager::updateStatusString()
1005 displCnt
=f_ilter
->count();
1007 displCnt
=g_roup
->count();
1009 QString name
= g_roup
->name();
1010 if (g_roup
->status()==KNGroup::moderated
)
1011 name
+= i18n(" (moderated)");
1013 knGlobals
.setStatusMsg(i18n(" %1: %2 new , %3 displayed",
1014 name
, g_roup
->newCount(), displCnt
),SB_GROUP
);
1017 knGlobals
.setStatusMsg(i18n(" Filter: %1", f_ilter
->translatedName()), SB_FILTER
);
1019 knGlobals
.setStatusMsg( QString(), SB_FILTER
);
1023 displCnt
=f_ilter
->count();
1025 displCnt
=f_older
->count();
1026 knGlobals
.setStatusMsg(i18n(" %1: %2 displayed",
1027 f_older
->name(), displCnt
), SB_GROUP
);
1028 knGlobals
.setStatusMsg( QString(), SB_FILTER
);
1030 knGlobals
.setStatusMsg( QString(), SB_GROUP
);
1031 knGlobals
.setStatusMsg( QString(), SB_FILTER
);
1036 void KNArticleManager::slotFilterChanged(KNArticleFilter
*f
)
1043 void KNArticleManager::slotSearchDialogDone()
1046 slotFilterChanged(f_ilterMgr
->currentFilter());
1050 void KNArticleManager::slotItemExpanded(Q3ListViewItem
*p
)
1052 if (d_isableExpander
) // we don't want to call this method recursively
1054 d_isableExpander
= true;
1056 KNRemoteArticle
*top
, *art
, *ref
;
1057 KNHdrViewItem
*hdrItem
;
1058 bool inThread
=false;
1059 bool showThreads
= knGlobals
.settings()->showThreads();
1060 hdrItem
=static_cast<KNHdrViewItem
*>(p
);
1061 top
=static_cast<KNRemoteArticle
*>(hdrItem
->art
);
1063 if (p
->childCount() == 0) {
1065 knGlobals
.top
->setCursorBusy(true);
1067 for(int i
=0; i
<g_roup
->count(); i
++) {
1069 if(art
->filterResult() && !art
->listItem()) {
1071 if(art
->displayedReference()==top
) {
1072 art
->setListItem(new KNHdrViewItem(hdrItem
));
1073 art
->setThreadMode(showThreads
);
1074 art
->initListItem();
1076 else if( knGlobals
.settings()->totalExpandThreads() ) { //totalExpand
1077 ref
=art
->displayedReference();
1079 while(ref
&& !inThread
) {
1080 inThread
=(ref
==top
);
1081 ref
=ref
->displayedReference();
1089 knGlobals
.top
->setCursorBusy(false);
1092 if ( knGlobals
.settings()->totalExpandThreads() )
1093 hdrItem
->expandChildren();
1095 d_isableExpander
= false;
1099 void KNArticleManager::setView(KNHeaderView
* v
) {
1102 connect(v
, SIGNAL(expanded(Q3ListViewItem
*)), this,
1103 SLOT(slotItemExpanded(Q3ListViewItem
*)));
1107 //-----------------------------
1108 #include "knarticlemanager.moc"