mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 18:32:51 +00:00
1108 lines
28 KiB
C++
1108 lines
28 KiB
C++
/*
|
|
KNode, the KDE newsreader
|
|
Copyright (c) 1999-2006 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 "knarticlemanager.h"
|
|
|
|
#include "utils/scoped_cursor_override.h"
|
|
|
|
#include <QByteArray>
|
|
#include <QList>
|
|
#include <krun.h>
|
|
#include <kmessagebox.h>
|
|
#include <kmimetypetrader.h>
|
|
#include <klocale.h>
|
|
#include <kdebug.h>
|
|
#include <kwindowsystem.h>
|
|
#include <ktemporaryfile.h>
|
|
|
|
#include "articlewidget.h"
|
|
#include "knmainwidget.h"
|
|
#include "knglobals.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 "scheduler.h"
|
|
#include "knnntpaccount.h"
|
|
#include "knscoring.h"
|
|
#include "knmemorymanager.h"
|
|
#include "knarticlefactory.h"
|
|
#include "knarticlewindow.h"
|
|
#include "knfoldermanager.h"
|
|
#include "headerview.h"
|
|
#include "nntpjobs.h"
|
|
#include "settings.h"
|
|
|
|
using namespace KNode;
|
|
using namespace KNode::Utilities;
|
|
|
|
|
|
KNArticleManager::KNArticleManager() : QObject(0)
|
|
{
|
|
f_ilterMgr = knGlobals.filterManager();
|
|
f_ilter = f_ilterMgr->currentFilter();
|
|
s_earchDlg=0;
|
|
d_isableExpander=false;
|
|
|
|
connect(f_ilterMgr, SIGNAL(filterChanged(KNArticleFilter*)), this,
|
|
SLOT(slotFilterChanged(KNArticleFilter*)));
|
|
}
|
|
|
|
|
|
KNArticleManager::~KNArticleManager()
|
|
{
|
|
delete s_earchDlg;
|
|
}
|
|
|
|
|
|
void KNArticleManager::deleteTempFiles()
|
|
{
|
|
for ( QList<KTemporaryFile*>::Iterator it = mTempFiles.begin(); it != mTempFiles.end(); ++it ) {
|
|
delete (*it);
|
|
}
|
|
mTempFiles.clear();
|
|
}
|
|
|
|
|
|
void KNArticleManager::saveContentToFile(KMime::Content *c, QWidget *parent)
|
|
{
|
|
KNSaveHelper helper(c->contentType()->name(),parent);
|
|
|
|
QFile *file = helper.getFile(i18n("Save Attachment"));
|
|
|
|
if (file) {
|
|
QByteArray data=c->decodedContent();
|
|
if (file->write(data.data(), data.size()) == -1 )
|
|
KNHelper::displayExternalFileError( parent );
|
|
}
|
|
}
|
|
|
|
|
|
void KNArticleManager::saveArticleToFile( KNArticle::Ptr a, QWidget *parent )
|
|
{
|
|
QString fName = a->subject()->asUnicodeString();
|
|
QString s = "";
|
|
|
|
for ( int i = 0; i < fName.length(); ++i )
|
|
if (fName[i].isLetterOrNumber())
|
|
s.append(fName[i]);
|
|
else
|
|
s.append(' ');
|
|
fName = s.simplified();
|
|
fName.replace(QRegExp("[\\s]"),"_");
|
|
|
|
KNSaveHelper helper(fName,parent);
|
|
QFile *file = helper.getFile(i18n("Save Article"));
|
|
|
|
if (file) {
|
|
QByteArray tmp=a->encodedContent(false);
|
|
if ( file->write(tmp.data(), tmp.size()) == -1 )
|
|
KNHelper::displayExternalFileError( parent );
|
|
}
|
|
}
|
|
|
|
|
|
QString KNArticleManager::saveContentToTemp(KMime::Content *c)
|
|
{
|
|
QString path;
|
|
KTemporaryFile* tmpFile;
|
|
KMime::Headers::Base *pathHdr=c->headerByType("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 ( QList<KTemporaryFile*>::Iterator it = mTempFiles.begin(); it != mTempFiles.end(); ++it ) {
|
|
if ( (*it)->fileName() == path ) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found)
|
|
return path;
|
|
else
|
|
c->removeHeader("X-KNode-Tempfile");
|
|
}
|
|
|
|
tmpFile=new KTemporaryFile();
|
|
if (!tmpFile->open()) {
|
|
KNHelper::displayTempFileError();
|
|
delete tmpFile;
|
|
return QString();
|
|
}
|
|
|
|
mTempFiles.append(tmpFile);
|
|
QByteArray data=c->decodedContent();
|
|
tmpFile->write(data.data(), data.size());
|
|
tmpFile->flush();
|
|
path=tmpFile->fileName();
|
|
pathHdr=new KMime::Headers::Generic("X-KNode-Tempfile", c, path, "UTF-8");
|
|
c->setHeader(pathHdr);
|
|
|
|
return path;
|
|
}
|
|
|
|
|
|
void KNArticleManager::openContent(KMime::Content *c)
|
|
{
|
|
QString path=saveContentToTemp(c);
|
|
if(path.isNull()) return;
|
|
|
|
KService::Ptr offer = KMimeTypeTrader::self()->preferredService(c->contentType()->mimeType(), "Application");
|
|
KUrl::List lst;
|
|
KUrl url;
|
|
url.setPath(path);
|
|
lst.append(url);
|
|
|
|
if (offer)
|
|
KRun::run(*offer, lst, knGlobals.top);
|
|
else
|
|
KRun::displayOpenWithDialog(lst, knGlobals.top);
|
|
}
|
|
|
|
|
|
void KNArticleManager::showHdrs(bool clear)
|
|
{
|
|
if(!g_roup && !f_older) return;
|
|
|
|
bool setFirstChild=true;
|
|
bool showThreads=knGlobals.settings()->showThreads();
|
|
bool expandThreads=knGlobals.settings()->defaultToExpandedThreads();
|
|
|
|
if(clear)
|
|
v_iew->clear();
|
|
|
|
ScopedCursorOverride cursor( Qt::WaitCursor );
|
|
knGlobals.setStatusMsg(i18n(" Creating list..."));
|
|
knGlobals.top->secureProcessEvents();
|
|
|
|
if(g_roup) {
|
|
KNRemoteArticle::Ptr art, ref, current;
|
|
|
|
current = boost::static_pointer_cast<KNRemoteArticle>( knGlobals.top->articleViewer()->article() );
|
|
|
|
if(current && (current->collection() != g_roup)) {
|
|
current.reset();
|
|
knGlobals.top->articleViewer()->setArticle( KNRemoteArticle::Ptr() );
|
|
}
|
|
|
|
if(g_roup->isLocked())
|
|
knGlobals.scheduler()->nntpMutex().lock();
|
|
|
|
if(f_ilter)
|
|
f_ilter->doFilter(g_roup);
|
|
else
|
|
for(int i=0; i<g_roup->length(); ++i) {
|
|
art=g_roup->at(i);
|
|
art->setFilterResult(true);
|
|
art->setFiltered(true);
|
|
ref = ( art->idRef() ? g_roup->byId( art->idRef() ) : KNRemoteArticle::Ptr() );
|
|
art->setDisplayedReference(ref);
|
|
if(ref)
|
|
ref->setVisibleFollowUps(true);
|
|
}
|
|
|
|
d_isableExpander=true;
|
|
|
|
for(int i=0; i<g_roup->length(); ++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 );
|
|
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.scheduler()->nntpMutex().unlock();
|
|
}
|
|
|
|
else if (f_older) {
|
|
|
|
KNLocalArticle::Ptr art;
|
|
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);
|
|
}
|
|
}
|
|
|
|
for(int idx=0; idx<f_older->length(); 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( KNArticle::Ptr() );
|
|
}
|
|
|
|
knGlobals.setStatusMsg( QString() );
|
|
updateStatusString();
|
|
}
|
|
|
|
|
|
void KNArticleManager::updateViewForCollection( KNArticleCollection::Ptr c )
|
|
{
|
|
if(g_roup==c || f_older==c)
|
|
showHdrs(false);
|
|
}
|
|
|
|
|
|
void KNArticleManager::updateListViewItems()
|
|
{
|
|
if(!g_roup && !f_older) return;
|
|
|
|
if(g_roup) {
|
|
KNRemoteArticle::Ptr art;
|
|
|
|
for(int i=0; i<g_roup->length(); ++i) {
|
|
art=g_roup->at(i);
|
|
if(art->listItem())
|
|
art->updateListItem();
|
|
}
|
|
} else { //folder
|
|
KNLocalArticle::Ptr art;
|
|
|
|
for(int idx=0; idx<f_older->length(); idx++) {
|
|
art=f_older->at(idx);
|
|
if(art->listItem())
|
|
art->updateListItem();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void KNArticleManager::setAllThreadsOpen(bool b)
|
|
{
|
|
KNRemoteArticle::Ptr art;
|
|
if(g_roup) {
|
|
ScopedCursorOverride cursor( Qt::WaitCursor );
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
void KNArticleManager::search()
|
|
{
|
|
if(s_earchDlg) {
|
|
s_earchDlg->show();
|
|
#ifdef Q_OS_UNIX
|
|
KWindowSystem::activateWindow(s_earchDlg->winId());
|
|
#endif
|
|
} else {
|
|
s_earchDlg = new SearchDialog( SearchDialog::STgroupSearch, 0 );
|
|
connect(s_earchDlg, SIGNAL(doSearch(KNArticleFilter*)), this,
|
|
SLOT(slotFilterChanged(KNArticleFilter*)));
|
|
connect(s_earchDlg, SIGNAL(dialogDone()), this,
|
|
SLOT(slotSearchDialogDone()));
|
|
s_earchDlg->show();
|
|
}
|
|
}
|
|
|
|
|
|
void KNArticleManager::setGroup( KNGroup::Ptr g )
|
|
{
|
|
g_roup = g;
|
|
if ( g )
|
|
emit aboutToShowGroup();
|
|
}
|
|
|
|
|
|
void KNArticleManager::setFolder( KNFolder::Ptr f )
|
|
{
|
|
f_older = f;
|
|
if ( f )
|
|
emit aboutToShowFolder();
|
|
}
|
|
|
|
|
|
KNArticleCollection::Ptr KNArticleManager::collection()
|
|
{
|
|
if(g_roup)
|
|
return g_roup;
|
|
if(f_older)
|
|
return f_older;
|
|
|
|
return KNArticleCollection::Ptr();
|
|
}
|
|
|
|
|
|
bool KNArticleManager::loadArticle( KNArticle::Ptr a )
|
|
{
|
|
if (!a)
|
|
return false;
|
|
|
|
if (a->hasContent())
|
|
return true;
|
|
|
|
if (a->isLocked()) {
|
|
if ( a->type() == KNArticle::ATremote )
|
|
return true; // locked == we are already loading this article...
|
|
else
|
|
return false;
|
|
}
|
|
|
|
if ( a->type() == KNArticle::ATremote ) {
|
|
KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( a->collection() );
|
|
if(g)
|
|
emitJob( new ArticleFetchJob( this, g->account(), a ) );
|
|
else
|
|
return false;
|
|
}
|
|
else { // local article
|
|
KNFolder::Ptr f = boost::static_pointer_cast<KNFolder>( a->collection() );
|
|
if( f && f->loadArticle( boost::static_pointer_cast<KNLocalArticle>( a ) ) )
|
|
knGlobals.memoryManager()->updateCacheEntry(a);
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool KNArticleManager::unloadArticle( KNArticle::Ptr 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()== KNArticle::ATlocal ) &&
|
|
( KNGlobals::self()->articleFactory()->findComposer( boost::static_pointer_cast<KNLocalArticle>( a ) ) != 0 ) )
|
|
return false;
|
|
|
|
if ( !ArticleWindow::closeAllWindowsForArticle( a, force ) )
|
|
if (!force)
|
|
return false;
|
|
|
|
ArticleWidget::articleRemoved( a );
|
|
if ( a->type() != KNArticle::ATlocal )
|
|
KNGlobals::self()->articleFactory()->deleteComposerForArticle( boost::static_pointer_cast<KNLocalArticle>( a ) );
|
|
a->updateListItem();
|
|
knGlobals.memoryManager()->removeCacheEntry(a);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void KNArticleManager::copyIntoFolder( KNArticle::List &l, KNFolder::Ptr f )
|
|
{
|
|
if(!f) return;
|
|
|
|
KNLocalArticle::Ptr loc;
|
|
KNLocalArticle::List l2;
|
|
|
|
for ( KNArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
|
|
if ( !(*it)->hasContent() )
|
|
continue;
|
|
loc = KNLocalArticle::Ptr( new KNLocalArticle( KNArticleCollection::Ptr() ) );
|
|
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 ) ) {
|
|
l2.clear();
|
|
f->setNotUnloadable(false);
|
|
return;
|
|
}
|
|
|
|
if( !f->saveArticles( l2 ) ) {
|
|
for ( KNLocalArticle::List::Iterator it = l2.begin(); it != l2.end(); ++it ) {
|
|
if ( (*it)->isOrphant() )
|
|
(*it).reset(); // 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( boost::static_pointer_cast<KNArticleCollection>( f ) );
|
|
}
|
|
|
|
f->setNotUnloadable(false);
|
|
}
|
|
}
|
|
|
|
|
|
void KNArticleManager::moveIntoFolder( KNLocalArticle::List &l, KNFolder::Ptr f )
|
|
{
|
|
if(!f) return;
|
|
kDebug(5003) <<" Target folder:" << f->name();
|
|
|
|
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( boost::static_pointer_cast<KNArticle>(*it) );
|
|
knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
|
|
} else {
|
|
for ( KNLocalArticle::List::Iterator it = l.begin(); it != l.end(); ++it )
|
|
if ( (*it)->isOrphant() )
|
|
(*it).reset(); // ok, this is ugly; we simply delete orphant articles
|
|
KNHelper::displayInternalFileError();
|
|
}
|
|
|
|
f->setNotUnloadable(false);
|
|
}
|
|
|
|
|
|
bool KNArticleManager::deleteArticles(KNLocalArticle::List &l, bool ask)
|
|
{
|
|
if(ask) {
|
|
QStringList 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( boost::static_pointer_cast<KNArticle>(*it) );
|
|
|
|
KNFolder::Ptr f = boost::static_pointer_cast<KNFolder>( l.first()->collection() );
|
|
if ( f ) {
|
|
f->removeArticles( l, true );
|
|
knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticleCollection>( f ) );
|
|
return false; // composers for those articles were already removed in removeArticles
|
|
} else {
|
|
l.clear();
|
|
}
|
|
|
|
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::Ptr 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::Ptr ref;
|
|
KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( l.first()->collection() );
|
|
int changeCnt=0, idRef=0;
|
|
|
|
for ( KNRemoteArticle::List::Iterator it = l.begin(); it != l.end(); ++it ) {
|
|
if( r && knGlobals.settings()->markCrossposts() &&
|
|
handleXPosts && (*it)->newsgroups()->isCrossposted() ) {
|
|
|
|
QList<QByteArray> groups = (*it)->newsgroups()->groups();
|
|
KNGroup::Ptr targetGroup;
|
|
KNRemoteArticle::Ptr xp;
|
|
KNRemoteArticle::List al;
|
|
QByteArray mid = (*it)->messageID()->as7BitString( false );
|
|
|
|
for ( QList<QByteArray>::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::Ptr 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::Ptr a = l.first();
|
|
KNRemoteArticle::Ptr ref;
|
|
bool watch = (!a->isWatched());
|
|
KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( 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::Ptr ref;
|
|
bool ignore = !l.first()->isIgnored();
|
|
KNGroup::Ptr g = boost::static_pointer_cast<KNGroup>( 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::Ptr g = boost::static_pointer_cast<KNGroup>( 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.settings()->ignoredThreshold();
|
|
else if ( (*it)->isWatched() )
|
|
defScore = knGlobals.settings()->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()) {
|
|
KNRemoteArticle::Ptr a = boost::static_pointer_cast<KNRemoteArticle>( j->data() );
|
|
if(j->success()) {
|
|
ArticleWidget::articleChanged( a );
|
|
if(!a->isOrphant()) //orphant articles are deleted by the displaying widget
|
|
knGlobals.memoryManager()->updateCacheEntry( boost::static_pointer_cast<KNArticle>( a ) );
|
|
if(a->listItem())
|
|
a->updateListItem();
|
|
} else {
|
|
if ( j->error() == KIO::ERR_DOES_NOT_EXIST ) {
|
|
// article is not available at the server anymore
|
|
QString msgId = a->messageID()->as7BitString( false );
|
|
// strip of '<' and '>'
|
|
msgId = msgId.mid( 1, msgId.length() - 2 );
|
|
ArticleWidget::articleLoadError( a,
|
|
i18n("The article you requested is not available on your news server."
|
|
"<br />You could try to get it from <a href=\"http://groups.google.com/groups?selm=%1\">groups.google.com</a>.",
|
|
msgId ) );
|
|
// mark article as read
|
|
if ( knGlobals.settings()->autoMark() && !a->isOrphant() ) {
|
|
KNRemoteArticle::List l;
|
|
l.append( a );
|
|
setRead( l, true );
|
|
}
|
|
} else
|
|
ArticleWidget::articleLoadError( a, j->errorString() );
|
|
}
|
|
}
|
|
|
|
delete j;
|
|
}
|
|
|
|
|
|
void KNArticleManager::createThread( KNRemoteArticle::Ptr a )
|
|
{
|
|
KNRemoteArticle::Ptr ref = a->displayedReference();
|
|
|
|
if(ref) {
|
|
if(!ref->listItem())
|
|
createThread(ref);
|
|
a->setListItem( new KNHdrViewItem( ref->listItem() ), a );
|
|
}
|
|
else
|
|
a->setListItem( new KNHdrViewItem( v_iew ), a );
|
|
|
|
a->setThreadMode( knGlobals.settings()->showThreads() );
|
|
a->initListItem();
|
|
}
|
|
|
|
|
|
void KNArticleManager::createCompleteThread( KNRemoteArticle::Ptr a )
|
|
{
|
|
KNRemoteArticle::Ptr ref = a->displayedReference();
|
|
if ( !ref ) {
|
|
return;
|
|
}
|
|
|
|
KNRemoteArticle::Ptr art, top;
|
|
bool inThread=false;
|
|
bool showThreads = knGlobals.settings()->showThreads();
|
|
|
|
while (ref->displayedReference() != 0)
|
|
ref=ref->displayedReference();
|
|
|
|
top = ref;
|
|
|
|
if (!top->listItem()) // shouldn't happen
|
|
return;
|
|
|
|
for(int i=0; i<g_roup->count(); ++i) {
|
|
art=g_roup->at(i);
|
|
if(art->filterResult() && !art->listItem()) {
|
|
|
|
if(art->displayedReference()==top) {
|
|
art->setListItem( new KNHdrViewItem( top->listItem() ), art );
|
|
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 ( knGlobals.settings()->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();
|
|
|
|
QString name = g_roup->name();
|
|
if (g_roup->status()==KNGroup::moderated)
|
|
name += i18n(" (moderated)");
|
|
|
|
knGlobals.setStatusMsg(i18n(" %1: %2 new , %3 displayed",
|
|
name, g_roup->newCount(), displCnt),SB_GROUP);
|
|
|
|
if(f_ilter)
|
|
knGlobals.setStatusMsg(i18n(" Filter: %1", f_ilter->translatedName()), SB_FILTER);
|
|
else
|
|
knGlobals.setStatusMsg( QString(), SB_FILTER );
|
|
}
|
|
else if(f_older) {
|
|
if(f_ilter)
|
|
displCnt=f_ilter->count();
|
|
else
|
|
displCnt=f_older->count();
|
|
knGlobals.setStatusMsg(i18n(" %1: %2 displayed",
|
|
f_older->name(), displCnt), SB_GROUP);
|
|
knGlobals.setStatusMsg( QString(), SB_FILTER );
|
|
} else {
|
|
knGlobals.setStatusMsg( QString(), SB_GROUP );
|
|
knGlobals.setStatusMsg( QString(), SB_FILTER );
|
|
}
|
|
}
|
|
|
|
|
|
void KNArticleManager::slotFilterChanged(KNArticleFilter *f)
|
|
{
|
|
f_ilter=f;
|
|
showHdrs();
|
|
}
|
|
|
|
|
|
void KNArticleManager::slotSearchDialogDone()
|
|
{
|
|
s_earchDlg->hide();
|
|
slotFilterChanged(f_ilterMgr->currentFilter());
|
|
}
|
|
|
|
|
|
void KNArticleManager::slotItemExpanded(Q3ListViewItem *p)
|
|
{
|
|
if (d_isableExpander) // we don't want to call this method recursively
|
|
return;
|
|
d_isableExpander = true;
|
|
|
|
KNRemoteArticle::Ptr top, art, ref;
|
|
KNHdrViewItem *hdrItem;
|
|
bool inThread=false;
|
|
bool showThreads = knGlobals.settings()->showThreads();
|
|
hdrItem=static_cast<KNHdrViewItem*>(p);
|
|
top = boost::static_pointer_cast<KNRemoteArticle>( hdrItem->art );
|
|
|
|
if (p->childCount() == 0) {
|
|
ScopedCursorOverride cursor( Qt::WaitCursor );
|
|
|
|
for(int i=0; i<g_roup->count(); ++i) {
|
|
art=g_roup->at(i);
|
|
if(art->filterResult() && !art->listItem()) {
|
|
|
|
if(art->displayedReference()==top) {
|
|
art->setListItem( new KNHdrViewItem( hdrItem ), art );
|
|
art->setThreadMode(showThreads);
|
|
art->initListItem();
|
|
}
|
|
else if( knGlobals.settings()->totalExpandThreads() ) { //totalExpand
|
|
ref=art->displayedReference();
|
|
inThread=false;
|
|
while(ref && !inThread) {
|
|
inThread=(ref==top);
|
|
ref=ref->displayedReference();
|
|
}
|
|
if(inThread)
|
|
createThread(art);
|
|
}
|
|
}
|
|
}
|
|
|
|
cursor.restore();
|
|
}
|
|
|
|
if ( knGlobals.settings()->totalExpandThreads() )
|
|
hdrItem->expandChildren();
|
|
|
|
d_isableExpander = false;
|
|
}
|
|
|
|
|
|
void KNArticleManager::setView(KNHeaderView* v) {
|
|
v_iew = v;
|
|
if(v) {
|
|
connect(v, SIGNAL(expanded(Q3ListViewItem*)), this,
|
|
SLOT(slotItemExpanded(Q3ListViewItem*)));
|
|
}
|
|
}
|
|
|
|
//-----------------------------
|