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 "knarticlemanager.h"
17 #include "utils/scoped_cursor_override.h"
22 #include <kmessagebox.h>
23 #include <kmimetypetrader.h>
26 #include <kwindowsystem.h>
27 #include <ktemporaryfile.h>
29 #include "articlewidget.h"
30 #include "knmainwidget.h"
31 #include "knglobals.h"
32 #include "utilities.h"
33 #include "knarticlemanager.h"
34 #include "kngroupmanager.h"
35 #include "knsearchdialog.h"
36 #include "knfiltermanager.h"
38 #include "knarticlefilter.h"
39 #include "knhdrviewitem.h"
40 #include "scheduler.h"
41 #include "knnntpaccount.h"
42 #include "knscoring.h"
43 #include "knmemorymanager.h"
44 #include "knarticlefactory.h"
45 #include "knarticlewindow.h"
46 #include "knfoldermanager.h"
47 #include "headerview.h"
51 using namespace KNode
;
52 using namespace KNode::Utilities
;
55 KNArticleManager::KNArticleManager() : QObject(0)
57 f_ilterMgr
= knGlobals
.filterManager();
58 f_ilter
= f_ilterMgr
->currentFilter();
60 d_isableExpander
=false;
62 connect(f_ilterMgr
, SIGNAL(filterChanged(KNArticleFilter
*)), this,
63 SLOT(slotFilterChanged(KNArticleFilter
*)));
67 KNArticleManager::~KNArticleManager()
73 void KNArticleManager::deleteTempFiles()
75 for ( QList
<KTemporaryFile
*>::Iterator it
= mTempFiles
.begin(); it
!= mTempFiles
.end(); ++it
) {
82 void KNArticleManager::saveContentToFile(KMime::Content
*c
, QWidget
*parent
)
84 KNSaveHelper
helper(c
->contentType()->name(),parent
);
86 QFile
*file
= helper
.getFile(i18n("Save Attachment"));
89 QByteArray data
=c
->decodedContent();
90 if (file
->write(data
.data(), data
.size()) == -1 )
91 KNHelper::displayExternalFileError( parent
);
96 void KNArticleManager::saveArticleToFile( KNArticle::Ptr a
, QWidget
*parent
)
98 QString fName
= a
->subject()->asUnicodeString();
101 for ( int i
= 0; i
< fName
.length(); ++i
)
102 if (fName
[i
].isLetterOrNumber())
106 fName
= s
.simplified();
107 fName
.replace(QRegExp("[\\s]"),"_");
109 KNSaveHelper
helper(fName
,parent
);
110 QFile
*file
= helper
.getFile(i18n("Save Article"));
113 QByteArray tmp
=a
->encodedContent(false);
114 if ( file
->write(tmp
.data(), tmp
.size()) == -1 )
115 KNHelper::displayExternalFileError( parent
);
120 QString
KNArticleManager::saveContentToTemp(KMime::Content
*c
)
123 KTemporaryFile
* tmpFile
;
124 KMime::Headers::Base
*pathHdr
=c
->headerByType("X-KNode-Tempfile"); // check for existing temp file
127 path
= pathHdr
->asUnicodeString();
130 // lets see if the tempfile-path is still valid...
131 for ( QList
<KTemporaryFile
*>::Iterator it
= mTempFiles
.begin(); it
!= mTempFiles
.end(); ++it
) {
132 if ( (*it
)->fileName() == path
) {
141 c
->removeHeader("X-KNode-Tempfile");
144 tmpFile
=new KTemporaryFile();
145 if (!tmpFile
->open()) {
146 KNHelper::displayTempFileError();
151 mTempFiles
.append(tmpFile
);
152 QByteArray data
=c
->decodedContent();
153 tmpFile
->write(data
.data(), data
.size());
155 path
=tmpFile
->fileName();
156 pathHdr
=new KMime::Headers::Generic("X-KNode-Tempfile", c
, path
, "UTF-8");
157 c
->setHeader(pathHdr
);
163 void KNArticleManager::openContent(KMime::Content
*c
)
165 QString path
=saveContentToTemp(c
);
166 if(path
.isNull()) return;
168 KService::Ptr offer
= KMimeTypeTrader::self()->preferredService(c
->contentType()->mimeType(), "Application");
175 KRun::run(*offer
, lst
, knGlobals
.top
);
177 KRun::displayOpenWithDialog(lst
, knGlobals
.top
);
181 void KNArticleManager::showHdrs(bool clear
)
183 if(!g_roup
&& !f_older
) return;
185 bool setFirstChild
=true;
186 bool showThreads
=knGlobals
.settings()->showThreads();
187 bool expandThreads
=knGlobals
.settings()->defaultToExpandedThreads();
192 ScopedCursorOverride
cursor( Qt::WaitCursor
);
193 knGlobals
.setStatusMsg(i18n(" Creating list..."));
194 knGlobals
.top
->secureProcessEvents();
197 KNRemoteArticle::Ptr art
, ref
, current
;
199 current
= boost::static_pointer_cast
<KNRemoteArticle
>( knGlobals
.top
->articleViewer()->article() );
201 if(current
&& (current
->collection() != g_roup
)) {
203 knGlobals
.top
->articleViewer()->setArticle( KNRemoteArticle::Ptr() );
206 if(g_roup
->isLocked())
207 knGlobals
.scheduler()->nntpMutex().lock();
210 f_ilter
->doFilter(g_roup
);
212 for(int i
=0; i
<g_roup
->length(); ++i
) {
214 art
->setFilterResult(true);
215 art
->setFiltered(true);
216 ref
= ( art
->idRef() ? g_roup
->byId( art
->idRef() ) : KNRemoteArticle::Ptr() );
217 art
->setDisplayedReference(ref
);
219 ref
->setVisibleFollowUps(true);
222 d_isableExpander
=true;
224 for(int i
=0; i
<g_roup
->length(); ++i
) {
227 art
->setThreadMode(showThreads
);
230 art
->propagateThreadChangedDate();
232 if( !art
->listItem() && art
->filterResult() ) {
234 // ### disable delayed header view item creation for now, it breaks
236 // since it doesn't seem to improve performance at all, it probably
237 // could be removed entirely (see also slotItemExpanded(), etc.)
238 /*if (!expandThreads) {
240 if( (ref=art->displayedReference()) ) {
242 if( ref->listItem() && ( ref->listItem()->isOpen() || ref->listItem()->childCount()>0 ) ) {
243 art->setListItem(new KNHdrViewItem(ref->listItem()));
249 art->setListItem(new KNHdrViewItem(v_iew));
253 } else { // expandThreads == true */
256 art
->listItem()->setOpen(true);
260 else if(art
->listItem()) {
261 art
->updateListItem();
263 art
->listItem()->setOpen(true);
269 if(!art
->listItem() && art
->filterResult()) {
270 art
->setListItem( new KNHdrViewItem( v_iew
), art
);
272 } else if(art
->listItem())
273 art
->updateListItem();
279 if (current
&& !current
->filterResult()) { // try to find a parent that is visible
281 while (current
&& !current
->filterResult()) {
282 idRef
=current
->idRef();
285 current
= g_roup
->byId(idRef
);
289 if(current
&& current
->filterResult()) {
290 if(!current
->listItem())
291 createCompleteThread(current
);
292 v_iew
->setActive( current
->listItem() );
296 d_isableExpander
=false;
298 if (g_roup
->isLocked())
299 knGlobals
.scheduler()->nntpMutex().unlock();
304 KNLocalArticle::Ptr art
;
306 f_ilter
->doFilter(f_older
);
308 for(int i
=0; i
<f_older
->length(); ++i
) {
310 art
->setFilterResult(true);
314 for(int idx
=0; idx
<f_older
->length(); idx
++) {
315 art
=f_older
->at(idx
);
317 if(!art
->listItem() && art
->filterResult()) {
318 art
->setListItem( new KNHdrViewItem( v_iew
), art
);
319 art
->updateListItem();
320 } else if(art
->listItem())
321 art
->updateListItem();
326 if(setFirstChild
&& v_iew
->firstChild()) {
327 v_iew
->setCurrentItem(v_iew
->firstChild());
328 knGlobals
.top
->articleViewer()->setArticle( KNArticle::Ptr() );
331 knGlobals
.setStatusMsg( QString() );
332 updateStatusString();
336 void KNArticleManager::updateViewForCollection( KNArticleCollection::Ptr c
)
338 if(g_roup
==c
|| f_older
==c
)
343 void KNArticleManager::updateListViewItems()
345 if(!g_roup
&& !f_older
) return;
348 KNRemoteArticle::Ptr art
;
350 for(int i
=0; i
<g_roup
->length(); ++i
) {
353 art
->updateListItem();
356 KNLocalArticle::Ptr art
;
358 for(int idx
=0; idx
<f_older
->length(); idx
++) {
359 art
=f_older
->at(idx
);
361 art
->updateListItem();
367 void KNArticleManager::setAllThreadsOpen(bool b
)
369 KNRemoteArticle::Ptr art
;
371 ScopedCursorOverride
cursor( Qt::WaitCursor
);
372 d_isableExpander
= true;
373 for(int idx
=0; idx
<g_roup
->length(); idx
++) {
374 art
= g_roup
->at(idx
);
376 art
->listItem()->setOpen(b
);
378 if (b
&& art
->filterResult()) {
380 art
->listItem()->setOpen(true);
383 d_isableExpander
= false;
388 void KNArticleManager::search()
393 KWindowSystem::activateWindow(s_earchDlg
->winId());
396 s_earchDlg
= new SearchDialog( SearchDialog::STgroupSearch
, 0 );
397 connect(s_earchDlg
, SIGNAL(doSearch(KNArticleFilter
*)), this,
398 SLOT(slotFilterChanged(KNArticleFilter
*)));
399 connect(s_earchDlg
, SIGNAL(dialogDone()), this,
400 SLOT(slotSearchDialogDone()));
406 void KNArticleManager::setGroup( KNGroup::Ptr g
)
410 emit
aboutToShowGroup();
414 void KNArticleManager::setFolder( KNFolder::Ptr f
)
418 emit
aboutToShowFolder();
422 KNArticleCollection::Ptr
KNArticleManager::collection()
429 return KNArticleCollection::Ptr();
433 bool KNArticleManager::loadArticle( KNArticle::Ptr a
)
442 if ( a
->type() == KNArticle::ATremote
)
443 return true; // locked == we are already loading this article...
448 if ( a
->type() == KNArticle::ATremote
) {
449 KNGroup::Ptr g
= boost::static_pointer_cast
<KNGroup
>( a
->collection() );
451 emitJob( new ArticleFetchJob( this, g
->account(), a
) );
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
);
466 bool KNArticleManager::unloadArticle( KNArticle::Ptr a
, bool force
)
468 if(!a
|| a
->isLocked() )
473 if (!force
&& a
->isNotUnloadable())
476 if ( !force
&& ( ArticleWidget::articleVisible( a
) ) )
479 if (!force
&& ( a
->type()== KNArticle::ATlocal
) &&
480 ( KNGlobals::self()->articleFactory()->findComposer( boost::static_pointer_cast
<KNLocalArticle
>( a
) ) != 0 ) )
483 if ( !ArticleWindow::closeAllWindowsForArticle( a
, force
) )
487 ArticleWidget::articleRemoved( a
);
488 if ( a
->type() != KNArticle::ATlocal
)
489 KNGlobals::self()->articleFactory()->deleteComposerForArticle( boost::static_pointer_cast
<KNLocalArticle
>( a
) );
491 knGlobals
.memoryManager()->removeCacheEntry(a
);
497 void KNArticleManager::copyIntoFolder( KNArticle::List
&l
, KNFolder::Ptr f
)
501 KNLocalArticle::Ptr loc
;
502 KNLocalArticle::List l2
;
504 for ( KNArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
505 if ( !(*it
)->hasContent() )
507 loc
= KNLocalArticle::Ptr( new KNLocalArticle( KNArticleCollection::Ptr() ) );
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
) ) {
520 f
->setNotUnloadable(false);
524 if( !f
->saveArticles( l2
) ) {
525 for ( KNLocalArticle::List::Iterator it
= l2
.begin(); it
!= l2
.end(); ++it
) {
526 if ( (*it
)->isOrphant() )
527 (*it
).reset(); // ok, this is ugly; we simply delete orphant articles
529 (*it
)->KMime::Content::clear(); // no need to keep them in memory
531 KNHelper::displayInternalFileError();
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
) );
538 f
->setNotUnloadable(false);
543 void KNArticleManager::moveIntoFolder( KNLocalArticle::List
&l
, KNFolder::Ptr f
)
546 kDebug(5003) <<" Target folder:" << f
->name();
548 f
->setNotUnloadable(true);
550 if (!f
->isLoaded() && !knGlobals
.folderManager()->loadHeaders(f
)) {
551 f
->setNotUnloadable(false);
555 if ( f
->saveArticles( l
) ) {
556 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
)
557 knGlobals
.memoryManager()->updateCacheEntry( boost::static_pointer_cast
<KNArticle
>(*it
) );
558 knGlobals
.memoryManager()->updateCacheEntry( boost::static_pointer_cast
<KNArticleCollection
>( f
) );
560 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
)
561 if ( (*it
)->isOrphant() )
562 (*it
).reset(); // ok, this is ugly; we simply delete orphant articles
563 KNHelper::displayInternalFileError();
566 f
->setNotUnloadable(false);
570 bool KNArticleManager::deleteArticles(KNLocalArticle::List
&l
, bool ask
)
574 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
575 if ( (*it
)->isLocked() )
577 if ( (*it
)->subject()->isEmpty() )
578 lst
<< i18n("no subject");
580 lst
<< (*it
)->subject()->asUnicodeString();
582 if( KMessageBox::Cancel
== KMessageBox::warningContinueCancelList(
583 knGlobals
.topWidget
, i18n("Do you really want to delete these articles?"), lst
,
584 i18n("Delete Articles"), KGuiItem(i18n("&Delete"),"edit-delete")) )
588 for ( KNLocalArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
)
589 knGlobals
.memoryManager()->removeCacheEntry( boost::static_pointer_cast
<KNArticle
>(*it
) );
591 KNFolder::Ptr f
= boost::static_pointer_cast
<KNFolder
>( l
.first()->collection() );
593 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
604 void KNArticleManager::setAllRead( bool read
, int lastcount
)
609 int groupLength
= g_roup
->length();
610 int newCount
= g_roup
->newCount();
611 int readCount
= g_roup
->readCount();
612 int offset
= lastcount
;
614 if ( lastcount
> groupLength
|| lastcount
< 0 )
615 offset
= groupLength
;
617 KNRemoteArticle::Ptr a
;
618 for ( int i
= groupLength
- offset
; i
< groupLength
; ++i
) {
620 if ( a
->getReadFlag() != read
&& !a
->isIgnored() ) {
622 a
->setChanged( true );
635 g_roup
->updateThreadInfo();
636 if ( lastcount
< 0 && read
) {
637 // HACK: try to hide the effects of the ignore/filter new/unread count bug
638 g_roup
->setReadCount( groupLength
);
639 g_roup
->setNewCount( 0 );
641 g_roup
->setReadCount( readCount
);
642 g_roup
->setNewCount( newCount
);
645 g_roup
->updateListItem();
650 void KNArticleManager::setRead(KNRemoteArticle::List
&l
, bool r
, bool handleXPosts
)
655 KNRemoteArticle::Ptr ref
;
656 KNGroup::Ptr g
= boost::static_pointer_cast
<KNGroup
>( l
.first()->collection() );
657 int changeCnt
=0, idRef
=0;
659 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
660 if( r
&& knGlobals
.settings()->markCrossposts() &&
661 handleXPosts
&& (*it
)->newsgroups()->isCrossposted() ) {
663 QList
<QByteArray
> groups
= (*it
)->newsgroups()->groups();
664 KNGroup::Ptr targetGroup
;
665 KNRemoteArticle::Ptr xp
;
666 KNRemoteArticle::List al
;
667 QByteArray mid
= (*it
)->messageID()->as7BitString( false );
669 for ( QList
<QByteArray
>::Iterator it2
= groups
.begin(); it2
!= groups
.end(); ++it2
) {
670 targetGroup
= knGlobals
.groupManager()->group(*it2
, g
->account());
672 if (targetGroup
->isLoaded() && (xp
=targetGroup
->byMessageId(mid
)) ) {
675 setRead(al
, r
, false);
677 targetGroup
->appendXPostID(mid
);
683 else if ( (*it
)->getReadFlag() != r
) {
685 (*it
)->setChanged( true );
686 (*it
)->updateListItem();
688 if ( !(*it
)->isIgnored() ) {
690 idRef
= (*it
)->idRef();
692 while ( idRef
!= 0 ) {
695 ref
->decUnreadFollowUps();
696 if ( (*it
)->isNew() )
697 ref
->decNewFollowUps();
700 ref
->incUnreadFollowUps();
701 if ( (*it
)->isNew() )
702 ref
->incNewFollowUps();
705 if(ref
->listItem() &&
706 ((ref
->unreadFollowUps()==0 || ref
->unreadFollowUps()==1) ||
707 (ref
->newFollowUps()==0 || ref
->newFollowUps()==1)))
708 ref
->updateListItem();
715 if ( (*it
)->isNew() )
720 if ( (*it
)->isNew() )
730 updateStatusString();
735 void KNArticleManager::setAllNotNew()
739 KNRemoteArticle::Ptr a
;
740 for ( int i
= 0; i
< g_roup
->length(); ++i
) {
744 a
->setChanged( true );
747 g_roup
->setFirstNewIndex( -1 );
748 g_roup
->setNewCount( 0 );
749 g_roup
->updateThreadInfo();
753 bool KNArticleManager::toggleWatched(KNRemoteArticle::List
&l
)
758 KNRemoteArticle::Ptr a
= l
.first();
759 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;
764 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
765 if ( (*it
)->isIgnored() ) {
766 (*it
)->setIgnored(false);
768 if ( !(*it
)->getReadFlag() ) {
770 idRef
= (*it
)->idRef();
772 while ( idRef
!= 0 ) {
775 ref
->incUnreadFollowUps();
776 if ( (*it
)->isNew() )
777 ref
->incNewFollowUps();
779 if(ref
->listItem() &&
780 ((ref
->unreadFollowUps()==0 || ref
->unreadFollowUps()==1) ||
781 (ref
->newFollowUps()==0 || ref
->newFollowUps()==1)))
782 ref
->updateListItem();
787 if ( (*it
)->isNew() )
792 (*it
)->setWatched( watch
);
793 (*it
)->updateListItem();
794 (*it
)->setChanged( true );
800 updateStatusString();
807 bool KNArticleManager::toggleIgnored(KNRemoteArticle::List
&l
)
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;
817 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
818 (*it
)->setWatched(false);
819 if ( (*it
)->isIgnored() != ignore
) {
820 (*it
)->setIgnored( ignore
);
822 if ( !(*it
)->getReadFlag() ) {
824 idRef
= (*it
)->idRef();
826 while ( idRef
!= 0 ) {
827 ref
= g
->byId( idRef
);
830 ref
->decUnreadFollowUps();
831 if ( (*it
)->isNew() )
832 ref
->decNewFollowUps();
834 ref
->incUnreadFollowUps();
835 if ( (*it
)->isNew() )
836 ref
->incNewFollowUps();
839 if(ref
->listItem() &&
840 ((ref
->unreadFollowUps()==0 || ref
->unreadFollowUps()==1) ||
841 (ref
->newFollowUps()==0 || ref
->newFollowUps()==1)))
842 ref
->updateListItem();
849 if ( (*it
)->isNew() )
853 if ( (*it
)->isNew() )
859 (*it
)->updateListItem();
860 (*it
)->setChanged(true);
866 updateStatusString();
873 void KNArticleManager::rescoreArticles(KNRemoteArticle::List
&l
)
878 KNGroup::Ptr g
= boost::static_pointer_cast
<KNGroup
>( l
.first()->collection() );
879 KScoringManager
*sm
= knGlobals
.scoringManager();
880 sm
->initCache(g
->groupname());
882 for ( KNRemoteArticle::List::Iterator it
= l
.begin(); it
!= l
.end(); ++it
) {
884 if ( (*it
)->isIgnored())
885 defScore
= knGlobals
.settings()->ignoredThreshold();
886 else if ( (*it
)->isWatched() )
887 defScore
= knGlobals
.settings()->watchedThreshold();
888 (*it
)->setScore(defScore
);
890 bool read
= (*it
)->isRead();
892 KNScorableArticle
sa( (*it
) );
894 (*it
)->updateListItem();
895 (*it
)->setChanged( true );
897 if ( !read
&& (*it
)->isRead() != read
)
898 g_roup
->incReadCount();
903 void KNArticleManager::processJob(KNJobData
*j
)
905 if(j
->type()==KNJobData::JTfetchArticle
&& !j
->canceled()) {
906 KNRemoteArticle::Ptr a
= boost::static_pointer_cast
<KNRemoteArticle
>( j
->data() );
908 ArticleWidget::articleChanged( a
);
909 if(!a
->isOrphant()) //orphant articles are deleted by the displaying widget
910 knGlobals
.memoryManager()->updateCacheEntry( boost::static_pointer_cast
<KNArticle
>( a
) );
914 if ( j
->error() == KIO::ERR_DOES_NOT_EXIST
) {
915 // article is not available at the server anymore
916 QString msgId
= a
->messageID()->as7BitString( false );
917 // strip of '<' and '>'
918 msgId
= msgId
.mid( 1, msgId
.length() - 2 );
919 ArticleWidget::articleLoadError( a
,
920 i18n("The article you requested is not available on your news server."
921 "<br />You could try to get it from <a href=\"http://groups.google.com/groups?selm=%1\">groups.google.com</a>.",
923 // mark article as read
924 if ( knGlobals
.settings()->autoMark() && !a
->isOrphant() ) {
925 KNRemoteArticle::List l
;
930 ArticleWidget::articleLoadError( a
, j
->errorString() );
938 void KNArticleManager::createThread( KNRemoteArticle::Ptr a
)
940 KNRemoteArticle::Ptr ref
= a
->displayedReference();
945 a
->setListItem( new KNHdrViewItem( ref
->listItem() ), a
);
948 a
->setListItem( new KNHdrViewItem( v_iew
), a
);
950 a
->setThreadMode( knGlobals
.settings()->showThreads() );
955 void KNArticleManager::createCompleteThread( KNRemoteArticle::Ptr a
)
957 KNRemoteArticle::Ptr ref
= a
->displayedReference();
962 KNRemoteArticle::Ptr art
, top
;
964 bool showThreads
= knGlobals
.settings()->showThreads();
966 while (ref
->displayedReference() != 0)
967 ref
=ref
->displayedReference();
971 if (!top
->listItem()) // shouldn't happen
974 for(int i
=0; i
<g_roup
->count(); ++i
) {
976 if(art
->filterResult() && !art
->listItem()) {
978 if(art
->displayedReference()==top
) {
979 art
->setListItem( new KNHdrViewItem( top
->listItem() ), art
);
980 art
->setThreadMode(showThreads
);
984 ref
=art
->displayedReference();
986 while(ref
&& !inThread
) {
988 ref
=ref
->displayedReference();
996 if ( knGlobals
.settings()->totalExpandThreads() )
997 top
->listItem()->expandChildren();
1001 void KNArticleManager::updateStatusString()
1007 displCnt
=f_ilter
->count();
1009 displCnt
=g_roup
->count();
1011 QString name
= g_roup
->name();
1012 if (g_roup
->status()==KNGroup::moderated
)
1013 name
+= i18n(" (moderated)");
1015 knGlobals
.setStatusMsg(i18n(" %1: %2 new , %3 displayed",
1016 name
, g_roup
->newCount(), displCnt
),SB_GROUP
);
1019 knGlobals
.setStatusMsg(i18n(" Filter: %1", f_ilter
->translatedName()), SB_FILTER
);
1021 knGlobals
.setStatusMsg( QString(), SB_FILTER
);
1025 displCnt
=f_ilter
->count();
1027 displCnt
=f_older
->count();
1028 knGlobals
.setStatusMsg(i18n(" %1: %2 displayed",
1029 f_older
->name(), displCnt
), SB_GROUP
);
1030 knGlobals
.setStatusMsg( QString(), SB_FILTER
);
1032 knGlobals
.setStatusMsg( QString(), SB_GROUP
);
1033 knGlobals
.setStatusMsg( QString(), SB_FILTER
);
1038 void KNArticleManager::slotFilterChanged(KNArticleFilter
*f
)
1045 void KNArticleManager::slotSearchDialogDone()
1048 slotFilterChanged(f_ilterMgr
->currentFilter());
1052 void KNArticleManager::slotItemExpanded(Q3ListViewItem
*p
)
1054 if (d_isableExpander
) // we don't want to call this method recursively
1056 d_isableExpander
= true;
1058 KNRemoteArticle::Ptr top
, art
, ref
;
1059 KNHdrViewItem
*hdrItem
;
1060 bool inThread
=false;
1061 bool showThreads
= knGlobals
.settings()->showThreads();
1062 hdrItem
=static_cast<KNHdrViewItem
*>(p
);
1063 top
= boost::static_pointer_cast
<KNRemoteArticle
>( hdrItem
->art
);
1065 if (p
->childCount() == 0) {
1066 ScopedCursorOverride
cursor( Qt::WaitCursor
);
1068 for(int i
=0; i
<g_roup
->count(); ++i
) {
1070 if(art
->filterResult() && !art
->listItem()) {
1072 if(art
->displayedReference()==top
) {
1073 art
->setListItem( new KNHdrViewItem( hdrItem
), art
);
1074 art
->setThreadMode(showThreads
);
1075 art
->initListItem();
1077 else if( knGlobals
.settings()->totalExpandThreads() ) { //totalExpand
1078 ref
=art
->displayedReference();
1080 while(ref
&& !inThread
) {
1081 inThread
=(ref
==top
);
1082 ref
=ref
->displayedReference();
1093 if ( knGlobals
.settings()->totalExpandThreads() )
1094 hdrItem
->expandChildren();
1096 d_isableExpander
= false;
1100 void KNArticleManager::setView(KNHeaderView
* v
) {
1103 connect(v
, SIGNAL(expanded(Q3ListViewItem
*)), this,
1104 SLOT(slotItemExpanded(Q3ListViewItem
*)));
1108 //-----------------------------
1109 #include "knarticlemanager.moc"