/* KNode, the KDE newsreader Copyright (c) 1999-2005 the KNode authors. 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US */ #include #include #include #include #include #include #include #include "articlewidget.h" #include "knmainwidget.h" #include "knglobals.h" #include "knconfigmanager.h" #include "utilities.h" #include "knarticlemanager.h" #include "kngroupmanager.h" #include "knsearchdialog.h" #include "knfiltermanager.h" #include "knfolder.h" #include "knarticlefilter.h" #include "knhdrviewitem.h" #include "knnetaccess.h" #include "knnntpaccount.h" #include "knscoring.h" #include "knmemorymanager.h" #include "knarticlefactory.h" #include "knarticlewindow.h" #include "knfoldermanager.h" #include "headerview.h" using namespace KNode; KNArticleManager::KNArticleManager() : TQObject(0,0) { g_roup=0; f_older=0; f_ilterMgr = knGlobals.filterManager(); f_ilter = f_ilterMgr->currentFilter(); s_earchDlg=0; d_isableExpander=false; connect(f_ilterMgr, TQT_SIGNAL(filterChanged(KNArticleFilter*)), this, TQT_SLOT(slotFilterChanged(KNArticleFilter*))); } KNArticleManager::~KNArticleManager() { delete s_earchDlg; } void KNArticleManager::deleteTempFiles() { for ( TQValueList::Iterator it = mTempFiles.begin(); it != mTempFiles.end(); ++it ) { (*it)->unlink(); delete (*it); } mTempFiles.clear(); } void KNArticleManager::saveContentToFile(KMime::Content *c, TQWidget *parent) { KNSaveHelper helper(c->contentType()->name(),parent); TQFile *file = helper.getFile(i18n("Save Attachment")); if (file) { TQByteArray data=c->decodedContent(); if (file->writeBlock(data.data(), data.size()) == -1 ) KNHelper::displayExternalFileError( parent ); } } void KNArticleManager::saveArticleToFile(KNArticle *a, TQWidget *parent) { TQString fName = a->subject()->asUnicodeString(); TQString s = ""; for (unsigned int i=0; iencodedContent(false); if ( file->writeBlock(tmp.data(), tmp.size()) == -1 ) KNHelper::displayExternalFileError( parent ); } } TQString KNArticleManager::saveContentToTemp(KMime::Content *c) { TQString path; KTempFile* tmpFile; KMime::Headers::Base *pathHdr=c->getHeaderByType("X-KNode-Tempfile"); // check for existing temp file if(pathHdr) { path = pathHdr->asUnicodeString(); bool found=false; // lets see if the tempfile-path is still valid... for ( TQValueList::Iterator it = mTempFiles.begin(); it != mTempFiles.end(); ++it ) { if ( (*it)->name() == path ) { found = true; break; } } if (found) return path; else c->removeHeader("X-KNode-Tempfile"); } tmpFile=new KTempFile(); if (tmpFile->status()!=0) { KNHelper::displayTempFileError(); delete tmpFile; return TQString(); } mTempFiles.append(tmpFile); TQFile *f=tmpFile->file(); TQByteArray data=c->decodedContent(); f->writeBlock(data.data(), data.size()); tmpFile->close(); path=tmpFile->name(); pathHdr=new KMime::Headers::Generic("X-KNode-Tempfile", c, path, "UTF-8"); c->setHeader(pathHdr); return path; } void KNArticleManager::openContent(KMime::Content *c) { TQString path=saveContentToTemp(c); if(path.isNull()) return; KService::Ptr offer = KServiceTypeProfile::preferredService(c->contentType()->mimeType(), "Application"); KURL::List lst; KURL url; url.setPath(path); lst.append(url); if (offer) KRun::run(*offer, lst); else KRun::displayOpenWithDialog(lst); } void KNArticleManager::showHdrs(bool clear) { if(!g_roup && !f_older) return; bool setFirstChild=true; bool showThreads=knGlobals.configManager()->readNewsGeneral()->showThreads(); bool expandThreads=knGlobals.configManager()->readNewsGeneral()->defaultToExpandedThreads(); if(clear) v_iew->clear(); knGlobals.top->setCursorBusy(true); knGlobals.setStatusMsg(i18n(" Creating list...")); knGlobals.top->secureProcessEvents(); if(g_roup) { KNRemoteArticle *art, *ref, *current; current = static_cast( knGlobals.top->articleViewer()->article() ); if(current && (current->collection() != g_roup)) { current=0; knGlobals.top->articleViewer()->setArticle( 0 ); } if(g_roup->isLocked()) knGlobals.netAccess()->nntpMutex().lock(); if(f_ilter) f_ilter->doFilter(g_roup); else for(int i=0; ilength(); i++) { art=g_roup->at(i); art->setFilterResult(true); art->setFiltered(true); ref=(art->idRef()!=0) ? g_roup->byId(art->idRef()) : 0; art->setDisplayedReference(ref); if(ref) ref->setVisibleFollowUps(true); } d_isableExpander=true; for(int i=0; ilength(); i++) { art=g_roup->at(i); art->setThreadMode(showThreads); if(showThreads) { art->propagateThreadChangedDate(); if( !art->listItem() && art->filterResult() ) { // ### 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) { 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)); art->initListItem(); } } else { // expandThreads == true */ createThread(art); if ( expandThreads ) art->listItem()->setOpen(true); // } } else if(art->listItem()) { art->updateListItem(); if (expandThreads) art->listItem()->setOpen(true); } } else { if(!art->listItem() && art->filterResult()) { art->setListItem(new KNHdrViewItem(v_iew)); art->initListItem(); } else if(art->listItem()) art->updateListItem(); } } 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); } } if(current && current->filterResult()) { if(!current->listItem()) createCompleteThread(current); v_iew->setActive( current->listItem() ); setFirstChild=false; } d_isableExpander=false; if (g_roup->isLocked()) knGlobals.netAccess()->nntpMutex().unlock(); } else { //folder KNLocalArticle *art; if(f_ilter) { f_ilter->doFilter(f_older); } else { for(int i=0; ilength(); i++) { art=f_older->at(i); art->setFilterResult(true); } } for(int idx=0; idxlength(); idx++) { art=f_older->at(idx); if(!art->listItem() && art->filterResult()) { art->setListItem( new KNHdrViewItem(v_iew, art) ); art->updateListItem(); } else if(art->listItem()) art->updateListItem(); } } if(setFirstChild && v_iew->firstChild()) { v_iew->setCurrentItem(v_iew->firstChild()); knGlobals.top->articleViewer()->setArticle( 0 ); } knGlobals.setStatusMsg(TQString()); updateStatusString(); knGlobals.top->setCursorBusy(false); } void KNArticleManager::updateViewForCollection(KNArticleCollection *c) { if(g_roup==c || f_older==c) showHdrs(false); } void KNArticleManager::updateListViewItems() { if(!g_roup && !f_older) return; if(g_roup) { KNRemoteArticle *art; for(int i=0; ilength(); i++) { art=g_roup->at(i); if(art->listItem()) art->updateListItem(); } } else { //folder KNLocalArticle *art; for(int idx=0; idxlength(); idx++) { art=f_older->at(idx); if(art->listItem()) art->updateListItem(); } } } void KNArticleManager::setAllThreadsOpen(bool b) { KNRemoteArticle *art; if(g_roup) { knGlobals.top->setCursorBusy(true); d_isableExpander = true; for(int idx=0; idxlength(); 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; knGlobals.top->setCursorBusy(false); } } void KNArticleManager::search() { if(s_earchDlg) { s_earchDlg->show(); KWin::activateWindow(s_earchDlg->winId()); } else { s_earchDlg=new KNSearchDialog(KNSearchDialog::STgroupSearch, 0); connect(s_earchDlg, TQT_SIGNAL(doSearch(KNArticleFilter*)), this, TQT_SLOT(slotFilterChanged(KNArticleFilter*))); connect(s_earchDlg, TQT_SIGNAL(dialogDone()), this, TQT_SLOT(slotSearchDialogDone())); s_earchDlg->show(); } } void KNArticleManager::setGroup(KNGroup *g) { g_roup = g; if ( g ) emit aboutToShowGroup(); } void KNArticleManager::setFolder(KNFolder *f) { f_older = f; if ( f ) emit aboutToShowFolder(); } KNArticleCollection* KNArticleManager::collection() { if(g_roup) return g_roup; if(f_older) return f_older; return 0; } bool KNArticleManager::loadArticle(KNArticle *a) { if (!a) return false; if (a->hasContent()) return true; if (a->isLocked()) { if (a->type()==KMime::Base::ATremote) return true; // locked == we are already loading this article... else return false; } if(a->type()==KMime::Base::ATremote) { KNGroup *g=static_cast(a->collection()); if(g) emitJob( new KNJobData(KNJobData::JTfetchArticle, this, g->account(), a) ); else return false; } else { // local article KNFolder *f=static_cast(a->collection()); if( f && f->loadArticle( static_cast(a) ) ) knGlobals.memoryManager()->updateCacheEntry(a); else return false; } return true; } bool KNArticleManager::unloadArticle(KNArticle *a, bool force) { if(!a || a->isLocked() ) return false; if(!a->hasContent()) return true; if (!force && a->isNotUnloadable()) return false; if ( !force && ( ArticleWidget::articleVisible( a ) ) ) return false; if (!force && (a->type()==KMime::Base::ATlocal) && (knGlobals.artFactory->findComposer(static_cast(a))!=0)) return false; if (!KNArticleWindow::closeAllWindowsForArticle(a, force)) if (!force) return false; ArticleWidget::articleRemoved( a ); if ( a->type() != KMime::Base::ATlocal ) knGlobals.artFactory->deleteComposerForArticle(static_cast(a)); a->KMime::Content::clear(); a->updateListItem(); knGlobals.memoryManager()->removeCacheEntry(a); return true; } void KNArticleManager::copyIntoFolder(KNArticle::List &l, KNFolder *f) { if(!f) return; KNLocalArticle *loc; KNLocalArticle::List l2; for ( KNArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) { if ( !(*it)->hasContent() ) continue; loc=new KNLocalArticle(0); loc->setEditDisabled(true); loc->setContent( (*it)->encodedContent() ); loc->parse(); l2.append(loc); } if ( !l2.isEmpty() ) { f->setNotUnloadable(true); if ( !f->isLoaded() && !knGlobals.folderManager()->loadHeaders( f ) ) { for ( KNLocalArticle::List::Iterator it = l2.begin(); it != l2.end(); ++it ) delete (*it); l2.clear(); f->setNotUnloadable(false); return; } if( !f->saveArticles( l2 ) ) { for ( KNLocalArticle::List::Iterator it = l2.begin(); it != l2.end(); ++it ) { if ( (*it)->isOrphant() ) delete (*it); // ok, this is ugly; we simply delete orphant articles else (*it)->KMime::Content::clear(); // no need to keep them in memory } KNHelper::displayInternalFileError(); } else { for ( KNLocalArticle::List::Iterator it = l2.begin(); it != l2.end(); ++it ) (*it)->KMime::Content::clear(); // no need to keep them in memory knGlobals.memoryManager()->updateCacheEntry(f); } f->setNotUnloadable(false); } } void KNArticleManager::moveIntoFolder(KNLocalArticle::List &l, KNFolder *f) { if(!f) return; kdDebug(5003) << k_funcinfo << " Target folder: " << f->name() << endl; f->setNotUnloadable(true); if (!f->isLoaded() && !knGlobals.folderManager()->loadHeaders(f)) { f->setNotUnloadable(false); return; } if ( f->saveArticles( l ) ) { for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) knGlobals.memoryManager()->updateCacheEntry( (*it) ); knGlobals.memoryManager()->updateCacheEntry(f); } else { for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) if ( (*it)->isOrphant() ) delete (*it); // ok, this is ugly; we simply delete orphant articles KNHelper::displayInternalFileError(); } f->setNotUnloadable(false); } bool KNArticleManager::deleteArticles(KNLocalArticle::List &l, bool ask) { if(ask) { TQStringList lst; for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) { if ( (*it)->isLocked() ) continue; if ( (*it)->subject()->isEmpty() ) lst << i18n("no subject"); else lst << (*it)->subject()->asUnicodeString(); } if( KMessageBox::Cancel == KMessageBox::warningContinueCancelList( knGlobals.topWidget, i18n("Do you really want to delete these articles?"), lst, i18n("Delete Articles"), KGuiItem(i18n("&Delete"),"edit-delete")) ) return false; } for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) knGlobals.memoryManager()->removeCacheEntry( (*it) ); KNFolder *f=static_cast(l.first()->collection()); if ( f ) { f->removeArticles( l, true ); knGlobals.memoryManager()->updateCacheEntry( f ); } else { for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) delete (*it); } return true; } void KNArticleManager::setAllRead( bool read, int lastcount ) { if ( !g_roup ) return; int groupLength = g_roup->length(); int newCount = g_roup->newCount(); int readCount = g_roup->readCount(); int offset = lastcount; if ( lastcount > groupLength || lastcount < 0 ) offset = groupLength; KNRemoteArticle *a; 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 ) { readCount--; if ( a->isNew() ) newCount++; } else { readCount++; if ( a->isNew() ) newCount--; } } } g_roup->updateThreadInfo(); 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 ); } g_roup->updateListItem(); showHdrs( true ); } void KNArticleManager::setRead(KNRemoteArticle::List &l, bool r, bool handleXPosts) { if ( l.isEmpty() ) return; KNRemoteArticle *ref = 0; KNGroup *g=static_cast( l.first()->collection() ); int changeCnt=0, idRef=0; for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) { if( r && knGlobals.configManager()->readNewsGeneral()->markCrossposts() && handleXPosts && (*it)->newsgroups()->isCrossposted() ) { TQStringList groups = (*it)->newsgroups()->getGroups(); KNGroup *targetGroup=0; KNRemoteArticle *xp=0; KNRemoteArticle::List al; TQCString mid = (*it)->messageID()->as7BitString( false ); for ( TQStringList::Iterator it2 = groups.begin(); it2 != groups.end(); ++it2 ) { targetGroup = knGlobals.groupManager()->group(*it2, g->account()); if (targetGroup) { if (targetGroup->isLoaded() && (xp=targetGroup->byMessageId(mid)) ) { al.clear(); al.append(xp); setRead(al, r, false); } else { targetGroup->appendXPostID(mid); } } } } else if ( (*it)->getReadFlag() != r ) { (*it)->setRead( r ); (*it)->setChanged( true ); (*it)->updateListItem(); if ( !(*it)->isIgnored() ) { changeCnt++; idRef = (*it)->idRef(); while ( idRef != 0 ) { ref=g->byId(idRef); if(r) { ref->decUnreadFollowUps(); if ( (*it)->isNew() ) ref->decNewFollowUps(); } else { ref->incUnreadFollowUps(); if ( (*it)->isNew() ) ref->incNewFollowUps(); } if(ref->listItem() && ((ref->unreadFollowUps()==0 || ref->unreadFollowUps()==1) || (ref->newFollowUps()==0 || ref->newFollowUps()==1))) ref->updateListItem(); idRef=ref->idRef(); } if(r) { g->incReadCount(); if ( (*it)->isNew() ) g->decNewCount(); } else { g->decReadCount(); if ( (*it)->isNew() ) g->incNewCount(); } } } } if(changeCnt>0) { g->updateListItem(); if(g==g_roup) updateStatusString(); } } void KNArticleManager::setAllNotNew() { if ( !g_roup ) return; KNRemoteArticle *a; 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(); } bool KNArticleManager::toggleWatched(KNRemoteArticle::List &l) { if(l.isEmpty()) return true; KNRemoteArticle *a=l.first(), *ref=0; bool watch = (!a->isWatched()); KNGroup *g=static_cast(a->collection() ); int changeCnt=0, idRef=0; for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) { if ( (*it)->isIgnored() ) { (*it)->setIgnored(false); if ( !(*it)->getReadFlag() ) { changeCnt++; idRef = (*it)->idRef(); while ( idRef != 0 ) { ref=g->byId(idRef); ref->incUnreadFollowUps(); if ( (*it)->isNew() ) ref->incNewFollowUps(); if(ref->listItem() && ((ref->unreadFollowUps()==0 || ref->unreadFollowUps()==1) || (ref->newFollowUps()==0 || ref->newFollowUps()==1))) ref->updateListItem(); idRef=ref->idRef(); } g->decReadCount(); if ( (*it)->isNew() ) g->incNewCount(); } } (*it)->setWatched( watch ); (*it)->updateListItem(); (*it)->setChanged( true ); } if(changeCnt>0) { g->updateListItem(); if(g==g_roup) updateStatusString(); } return watch; } bool KNArticleManager::toggleIgnored(KNRemoteArticle::List &l) { if(l.isEmpty()) return true; KNRemoteArticle *ref = 0; bool ignore = !l.first()->isIgnored(); KNGroup *g = static_cast( l.first()->collection() ); int changeCnt = 0, idRef = 0; for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) { (*it)->setWatched(false); if ( (*it)->isIgnored() != ignore ) { (*it)->setIgnored( ignore ); if ( !(*it)->getReadFlag() ) { changeCnt++; idRef = (*it)->idRef(); while ( idRef != 0 ) { ref = g->byId( idRef ); if ( ignore ) { ref->decUnreadFollowUps(); if ( (*it)->isNew() ) ref->decNewFollowUps(); } else { ref->incUnreadFollowUps(); if ( (*it)->isNew() ) ref->incNewFollowUps(); } if(ref->listItem() && ((ref->unreadFollowUps()==0 || ref->unreadFollowUps()==1) || (ref->newFollowUps()==0 || ref->newFollowUps()==1))) ref->updateListItem(); idRef=ref->idRef(); } if ( ignore ) { g->incReadCount(); if ( (*it)->isNew() ) g->decNewCount(); } else { g->decReadCount(); if ( (*it)->isNew() ) g->incNewCount(); } } } (*it)->updateListItem(); (*it)->setChanged(true); } if(changeCnt>0) { g->updateListItem(); if(g==g_roup) updateStatusString(); } return ignore; } void KNArticleManager::rescoreArticles(KNRemoteArticle::List &l) { if ( l.isEmpty() ) return; KNGroup *g = static_cast( l.first()->collection() ); KScoringManager *sm = knGlobals.scoringManager(); sm->initCache(g->groupname()); for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) { int defScore = 0; if ( (*it)->isIgnored()) defScore = knGlobals.configManager()->scoring()->ignoredThreshold(); else if ( (*it)->isWatched() ) defScore = knGlobals.configManager()->scoring()->watchedThreshold(); (*it)->setScore(defScore); bool read = (*it)->isRead(); KNScorableArticle sa( (*it) ); sm->applyRules(sa); (*it)->updateListItem(); (*it)->setChanged( true ); if ( !read && (*it)->isRead() != read ) g_roup->incReadCount(); } } void KNArticleManager::processJob(KNJobData *j) { if(j->type()==KNJobData::JTfetchArticle && !j->canceled()) { if(j->success()) { KNRemoteArticle *a=static_cast(j->data()); ArticleWidget::articleChanged( a ); if(!a->isOrphant()) //orphant articles are deleted by the displaying widget knGlobals.memoryManager()->updateCacheEntry(a); if(a->listItem()) a->updateListItem(); } else ArticleWidget::articleLoadError(static_cast(j->data()), j->errorString()); } delete j; } void KNArticleManager::createThread(KNRemoteArticle *a) { KNRemoteArticle *ref=a->displayedReference(); if(ref) { if(!ref->listItem()) createThread(ref); a->setListItem(new KNHdrViewItem(ref->listItem())); } else a->setListItem(new KNHdrViewItem(v_iew)); a->setThreadMode(knGlobals.configManager()->readNewsGeneral()->showThreads()); a->initListItem(); } void KNArticleManager::createCompleteThread(KNRemoteArticle *a) { KNRemoteArticle *ref=a->displayedReference(), *art, *top; bool inThread=false; bool showThreads=knGlobals.configManager()->readNewsGeneral()->showThreads(); KNConfig::ReadNewsGeneral *rng=knGlobals.configManager()->readNewsGeneral(); while (ref->displayedReference() != 0) ref=ref->displayedReference(); top = ref; if (!top->listItem()) // shouldn't happen return; for(int i=0; icount(); i++) { art=g_roup->at(i); if(art->filterResult() && !art->listItem()) { if(art->displayedReference()==top) { art->setListItem(new KNHdrViewItem(top->listItem())); art->setThreadMode(showThreads); art->initListItem(); } else { ref=art->displayedReference(); inThread=false; while(ref && !inThread) { inThread=(ref==top); ref=ref->displayedReference(); } if(inThread) createThread(art); } } } if(rng->totalExpandThreads()) top->listItem()->expandChildren(); } void KNArticleManager::updateStatusString() { int displCnt=0; if(g_roup) { if(f_ilter) displCnt=f_ilter->count(); else displCnt=g_roup->count(); TQString name = g_roup->name(); if (g_roup->status()==KNGroup::moderated) name += i18n(" (moderated)"); knGlobals.setStatusMsg(i18n(" %1: %2 new , %3 displayed") .arg(name).arg(g_roup->newCount()).arg(displCnt),SB_GROUP); if(f_ilter) knGlobals.setStatusMsg(i18n(" Filter: %1").arg(f_ilter->translatedName()), SB_FILTER); else knGlobals.setStatusMsg(TQString(), SB_FILTER); } else if(f_older) { if(f_ilter) displCnt=f_ilter->count(); else displCnt=f_older->count(); knGlobals.setStatusMsg(i18n(" %1: %2 displayed") .arg(f_older->name()).arg(displCnt), SB_GROUP); knGlobals.setStatusMsg(TQString(), SB_FILTER); } else { knGlobals.setStatusMsg(TQString(), SB_GROUP); knGlobals.setStatusMsg(TQString(), SB_FILTER); } } void KNArticleManager::slotFilterChanged(KNArticleFilter *f) { f_ilter=f; showHdrs(); } void KNArticleManager::slotSearchDialogDone() { s_earchDlg->hide(); slotFilterChanged(f_ilterMgr->currentFilter()); } void KNArticleManager::slotItemExpanded(TQListViewItem *p) { if (d_isableExpander) // we don't want to call this method recursively return; d_isableExpander = true; KNRemoteArticle *top, *art, *ref; KNHdrViewItem *hdrItem; bool inThread=false; bool showThreads=knGlobals.configManager()->readNewsGeneral()->showThreads(); KNConfig::ReadNewsGeneral *rng=knGlobals.configManager()->readNewsGeneral(); hdrItem=static_cast(p); top=static_cast(hdrItem->art); if (p->childCount() == 0) { knGlobals.top->setCursorBusy(true); for(int i=0; icount(); i++) { art=g_roup->at(i); if(art->filterResult() && !art->listItem()) { if(art->displayedReference()==top) { art->setListItem(new KNHdrViewItem(hdrItem)); art->setThreadMode(showThreads); art->initListItem(); } else if(rng->totalExpandThreads()) { //totalExpand ref=art->displayedReference(); inThread=false; while(ref && !inThread) { inThread=(ref==top); ref=ref->displayedReference(); } if(inThread) createThread(art); } } } knGlobals.top->setCursorBusy(false); } if(rng->totalExpandThreads()) hdrItem->expandChildren(); d_isableExpander = false; } void KNArticleManager::setView(KNHeaderView* v) { v_iew = v; if(v) { connect(v, TQT_SIGNAL(expanded(TQListViewItem*)), this, TQT_SLOT(slotItemExpanded(TQListViewItem*))); } } //----------------------------- #include "knarticlemanager.moc"