akregator/src

akregator_view.cpp

00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
00005                   2004 Sashmit Bhaduri <smt@vfemail.net>
00006                   2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021 
00022     As a special exception, permission is given to link this program
00023     with any edition of Qt, and distribute the resulting executable,
00024     without including the source code for Qt in the source distribution.
00025 */
00026 
00027 #include "actionmanagerimpl.h"
00028 #include "akregator_part.h"
00029 #include "akregator_run.h"
00030 #include "akregator_view.h"
00031 #include "listtabwidget.h"
00032 #include "addfeeddialog.h"
00033 #include "propertiesdialog.h"
00034 #include "frame.h"
00035 #include "fetchqueue.h"
00036 #include "feedlistview.h"
00037 #include "articlelistview.h"
00038 #include "articleviewer.h"
00039 #include "viewer.h"
00040 #include "feed.h"
00041 #include "tagfolder.h"
00042 #include "folder.h"
00043 #include "feedlist.h"
00044 #include "akregatorconfig.h"
00045 #include "kernel.h"
00046 #include "pageviewer.h"
00047 #include "searchbar.h"
00048 #include "speechclient.h"
00049 #include "storage.h"
00050 #include "tabwidget.h"
00051 #include "tag.h"
00052 #include "tagset.h"
00053 #include "tagnode.h"
00054 #include "tagnodelist.h"
00055 #include "tagpropertiesdialog.h"
00056 #include "treenode.h"
00057 #include "progressmanager.h"
00058 #include "treenodevisitor.h"
00059 #include "notificationmanager.h"
00060 
00061 #include <kaction.h>
00062 #include <kapplication.h>
00063 #include <kcharsets.h>
00064 #include <kcombobox.h>
00065 #include <kconfig.h>
00066 #include <kdebug.h>
00067 #include <kdialog.h>
00068 #include <kfiledialog.h>
00069 #include <kfileitem.h>
00070 #include <khtml_part.h>
00071 #include <khtmlview.h>
00072 #include <kiconloader.h>
00073 #include <kinputdialog.h>
00074 #include <klineedit.h>
00075 #include <klistview.h>
00076 #include <klocale.h>
00077 #include <kmessagebox.h>
00078 #include <kpassdlg.h>
00079 #include <kprocess.h>
00080 #include <krun.h>
00081 #include <kshell.h>
00082 #include <kstandarddirs.h>
00083 #include <kurl.h>
00084 #include <kxmlguifactory.h>
00085 #include <kparts/partmanager.h>
00086 
00087 #include <qbuttongroup.h>
00088 #include <qcheckbox.h>
00089 #include <qdatetime.h> // for startup time measure
00090 #include <qfile.h>
00091 #include <qhbox.h>
00092 #include <qlabel.h>
00093 #include <qlayout.h>
00094 #include <qmultilineedit.h>
00095 #include <qpopupmenu.h>
00096 #include <qstylesheet.h>
00097 #include <qtextstream.h>
00098 #include <qtimer.h>
00099 #include <qtoolbutton.h>
00100 #include <qtooltip.h>
00101 #include <qvaluevector.h>
00102 #include <qwhatsthis.h>
00103 #include <qclipboard.h>
00104 
00105 namespace Akregator {
00106 
00107 class View::EditNodePropertiesVisitor : public TreeNodeVisitor
00108 {
00109     public:
00110         EditNodePropertiesVisitor(View* view) : m_view(view) {}
00111 
00112         virtual bool visitTagNode(TagNode* node)
00113         {
00114             TagPropertiesDialog* dlg = new TagPropertiesDialog(m_view);
00115             dlg->setTag(node->tag());
00116             dlg->exec();
00117             delete dlg;
00118             return true;
00119         }
00120 
00121         virtual bool visitFolder(Folder* node)
00122         {
00123             m_view->m_listTabWidget->activeView()->startNodeRenaming(node);
00124             return true;
00125         }
00126 
00127         virtual bool visitFeed(Feed* node)
00128         {
00129             FeedPropertiesDialog *dlg = new FeedPropertiesDialog( m_view, "edit_feed" );
00130             dlg->setFeed(node);
00131             dlg->exec();
00132             delete dlg;
00133             return true;
00134         }
00135     private:
00136 
00137         View* m_view;
00138 };
00139 
00140 class View::DeleteNodeVisitor : public TreeNodeVisitor
00141 {
00142     public:
00143         DeleteNodeVisitor(View* view) : m_view(view) {}
00144 
00145         virtual bool visitTagNode(TagNode* node)
00146         {
00147             QString msg = i18n("<qt>Are you sure you want to delete tag <b>%1</b>? The tag will be removed from all articles.</qt>").arg(node->title());
00148             if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Tag"), KStdGuiItem::del()) == KMessageBox::Continue)
00149             {
00150                 Tag tag = node->tag();
00151                 QValueList<Article> articles = m_view->m_feedList->rootNode()->articles(tag.id());
00152                 node->setNotificationMode(false);
00153                 for (QValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
00154                     (*it).removeTag(tag.id());
00155                 node->setNotificationMode(true);
00156                 Kernel::self()->tagSet()->remove(tag);
00157                 m_view->m_listTabWidget->activeView()->setFocus();
00158             }
00159             return true;
00160         }
00161 
00162         virtual bool visitFolder(Folder* node)
00163         {
00164             QString msg;
00165             if (node->title().isEmpty())
00166                 msg = i18n("<qt>Are you sure you want to delete this folder and its feeds and subfolders?</qt>");
00167             else
00168                 msg = i18n("<qt>Are you sure you want to delete folder <b>%1</b> and its feeds and subfolders?</qt>").arg(node->title());
00169 
00170             if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Folder"), KStdGuiItem::del()) == KMessageBox::Continue)
00171             {
00172                 delete node;
00173                 m_view->m_listTabWidget->activeView()->setFocus();
00174             }
00175             return true;
00176         }
00177 
00178         virtual bool visitFeed(Feed* node)
00179         {
00180             QString msg;
00181             if (node->title().isEmpty())
00182                 msg = i18n("<qt>Are you sure you want to delete this feed?</qt>");
00183             else
00184                 msg = i18n("<qt>Are you sure you want to delete feed <b>%1</b>?</qt>").arg(node->title());
00185 
00186             if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Feed"), KStdGuiItem::del()) == KMessageBox::Continue)
00187             {
00188                 delete node;
00189                 m_view->m_listTabWidget->activeView()->setFocus();
00190             }
00191             return true;
00192         }
00193     private:
00194 
00195         View* m_view;
00196 };
00197 
00198 
00199 View::~View()
00200 {
00201     // if m_shuttingDown is false, slotOnShutdown was not called. That
00202      // means that not the whole app is shutdown, only the part. So it
00203     // should be no risk to do the cleanups now
00204     if (!m_shuttingDown)
00205     {
00206         kdDebug() << "View::~View(): slotOnShutdown() wasn't called. Calling it now." << endl;
00207         slotOnShutdown();
00208     }
00209     kdDebug() << "View::~View(): leaving" << endl;
00210 }
00211 
00212 View::View( Part *part, QWidget *parent, ActionManagerImpl* actionManager, const char *name)
00213  : QWidget(parent, name), m_viewMode(NormalView), m_actionManager(actionManager)
00214 {
00215     m_editNodePropertiesVisitor = new EditNodePropertiesVisitor(this);
00216     m_deleteNodeVisitor = new DeleteNodeVisitor(this);
00217     m_keepFlagIcon = QPixmap(locate("data", "akregator/pics/akregator_flag.png"));
00218     m_part = part;
00219     m_feedList = new FeedList();
00220     m_tagNodeList = new TagNodeList(m_feedList, Kernel::self()->tagSet());
00221     m_shuttingDown = false;
00222     m_displayingAboutPage = false;
00223     m_currentFrame = 0L;
00224     setFocusPolicy(QWidget::StrongFocus);
00225 
00226     QVBoxLayout *lt = new QVBoxLayout( this );
00227     
00228     m_horizontalSplitter = new QSplitter(QSplitter::Horizontal, this);
00229 
00230     m_horizontalSplitter->setOpaqueResize(true);
00231     lt->addWidget(m_horizontalSplitter);
00232 
00233     connect (Kernel::self()->fetchQueue(), SIGNAL(fetched(Feed*)), this, SLOT(slotFeedFetched(Feed*)));
00234     connect (Kernel::self()->fetchQueue(), SIGNAL(signalStarted()), this, SLOT(slotFetchingStarted()));
00235     connect (Kernel::self()->fetchQueue(), SIGNAL(signalStopped()), this, SLOT(slotFetchingStopped()));
00236 
00237     connect(Kernel::self()->tagSet(), SIGNAL(signalTagAdded(const Tag&)), this, SLOT(slotTagCreated(const Tag&)));
00238     connect(Kernel::self()->tagSet(), SIGNAL(signalTagRemoved(const Tag&)), this, SLOT(slotTagRemoved(const Tag&)));
00239 
00240     m_listTabWidget = new ListTabWidget(m_horizontalSplitter);
00241     m_actionManager->initListTabWidget(m_listTabWidget);
00242 
00243     connect(m_listTabWidget, SIGNAL(signalNodeSelected(TreeNode*)), this, SLOT(slotNodeSelected(TreeNode*)));
00244 
00245     if (!Settings::showTaggingGUI())
00246         m_listTabWidget->setViewMode(ListTabWidget::single);
00247 
00248     m_feedListView = new NodeListView( this, "feedtree" );
00249     m_listTabWidget->addView(m_feedListView, i18n("Feeds"), KGlobal::iconLoader()->loadIcon("folder", KIcon::Small));
00250 
00251     connect(m_feedListView, SIGNAL(signalContextMenu(KListView*, TreeNode*, const QPoint&)), this, SLOT(slotFeedTreeContextMenu(KListView*, TreeNode*, const QPoint&)));
00252 
00253     connect(m_feedListView, SIGNAL(signalDropped (KURL::List &, TreeNode*,
00254             Folder*)), this, SLOT(slotFeedURLDropped (KURL::List &,
00255             TreeNode*, Folder*)));
00256 
00257     m_tagNodeListView = new NodeListView(this);
00258     m_listTabWidget->addView(m_tagNodeListView, i18n("Tags"), KGlobal::iconLoader()->loadIcon("rss_tag", KIcon::Small));
00259 
00260     connect(m_tagNodeListView, SIGNAL(signalContextMenu(KListView*, TreeNode*, const QPoint&)), this, SLOT(slotFeedTreeContextMenu(KListView*, TreeNode*, const QPoint&)));
00261 
00262     
00263     ProgressManager::self()->setFeedList(m_feedList);
00264 
00265     m_tabs = new TabWidget(m_horizontalSplitter);
00266     m_actionManager->initTabWidget(m_tabs);
00267 
00268     connect( m_part, SIGNAL(signalSettingsChanged()), m_tabs, SLOT(slotSettingsChanged()));
00269 
00270     connect( m_tabs, SIGNAL( currentFrameChanged(Frame *) ), this,
00271             SLOT( slotFrameChanged(Frame *) ) );
00272 
00273     QWhatsThis::add(m_tabs, i18n("You can view multiple articles in several open tabs."));
00274 
00275     m_mainTab = new QWidget(this, "Article Tab");
00276     QVBoxLayout *mainTabLayout = new QVBoxLayout( m_mainTab, 0, 2, "mainTabLayout");
00277 
00278     QWhatsThis::add(m_mainTab, i18n("Articles list."));
00279 
00280     m_searchBar = new SearchBar(m_mainTab);
00281 
00282     if ( !Settings::showQuickFilter() )
00283         m_searchBar->hide();
00284 
00285     mainTabLayout->addWidget(m_searchBar);
00286 
00287     m_articleSplitter = new QSplitter(QSplitter::Vertical, m_mainTab, "panner2");
00288 
00289     m_articleList = new ArticleListView( m_articleSplitter, "articles" );
00290     m_actionManager->initArticleListView(m_articleList);
00291 
00292     connect( m_articleList, SIGNAL(signalMouseButtonPressed(int, const Article&, const QPoint &, int)), this, SLOT(slotMouseButtonPressed(int, const Article&, const QPoint &, int)));
00293 
00294     // use selectionChanged instead of clicked
00295     connect( m_articleList, SIGNAL(signalArticleChosen(const Article&)),
00296                 this, SLOT( slotArticleSelected(const Article&)) );
00297     connect( m_articleList, SIGNAL(signalDoubleClicked(const Article&, const QPoint&, int)),
00298                 this, SLOT( slotOpenArticleExternal(const Article&, const QPoint&, int)) );
00299 
00300     m_articleViewer = new ArticleViewer(m_articleSplitter, "article_viewer");
00301     m_articleViewer->setSafeMode();  // disable JS, Java, etc...
00302 
00303     m_actionManager->initArticleViewer(m_articleViewer);
00304 
00305     connect(m_searchBar, SIGNAL(signalSearch(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)), m_articleList, SLOT(slotSetFilter(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)));
00306 
00307     connect(m_searchBar, SIGNAL(signalSearch(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)), m_articleViewer, SLOT(slotSetFilter(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)));
00308 
00309     connect( m_articleViewer, SIGNAL(urlClicked(const KURL&, Viewer*, bool, bool)),
00310              this, SLOT(slotUrlClickedInViewer(const KURL&, Viewer*, bool, bool)) );
00311 
00312     connect( m_articleViewer->browserExtension(), SIGNAL(mouseOverInfo(const KFileItem *)),
00313                                             this, SLOT(slotMouseOverInfo(const KFileItem *)) );
00314 
00315     connect( m_part, SIGNAL(signalSettingsChanged()), m_articleViewer, SLOT(slotPaletteOrFontChanged()));
00316     QWhatsThis::add(m_articleViewer->widget(), i18n("Browsing area."));
00317     mainTabLayout->addWidget( m_articleSplitter );
00318 
00319     m_mainFrame=new Frame(this, m_part, m_mainTab, i18n("Articles"), false);
00320     connectFrame(m_mainFrame);
00321     m_tabs->addFrame(m_mainFrame);
00322 
00323     m_horizontalSplitter->setSizes( Settings::splitter1Sizes() );
00324     m_articleSplitter->setSizes( Settings::splitter2Sizes() );
00325 
00326     KConfig *conf = Settings::self()->config();
00327     conf->setGroup("General");
00328     if(!conf->readBoolEntry("Disable Introduction", false))
00329     {
00330         m_articleList->hide();
00331         m_searchBar->hide();
00332         m_articleViewer->displayAboutPage();
00333         m_mainFrame->setTitle(i18n("About"));
00334         m_displayingAboutPage = true;
00335     }
00336 
00337     m_fetchTimer = new QTimer(this);
00338     connect( m_fetchTimer, SIGNAL(timeout()), this, SLOT(slotDoIntervalFetches()) );
00339     m_fetchTimer->start(1000*60);
00340 
00341     // delete expired articles once per hour
00342     m_expiryTimer = new QTimer(this);
00343     connect(m_expiryTimer, SIGNAL(timeout()), this,
00344             SLOT(slotDeleteExpiredArticles()) );
00345     m_expiryTimer->start(3600*1000);
00346 
00347     m_markReadTimer = new QTimer(this);
00348     connect(m_markReadTimer, SIGNAL(timeout()), this, SLOT(slotSetCurrentArticleReadDelayed()) );
00349 
00350     switch (Settings::viewMode())
00351     {
00352         case CombinedView:
00353             slotCombinedView();
00354             break;
00355         case WidescreenView:
00356             slotWidescreenView();
00357             break;
00358         default:
00359             slotNormalView();
00360     }
00361 
00362     if (!Settings::resetQuickFilterOnNodeChange())
00363     {
00364         m_searchBar->slotSetStatus(Settings::statusFilter());
00365         m_searchBar->slotSetText(Settings::textFilter());
00366     }
00367 
00368     QTimer::singleShot(1000, this, SLOT(slotDeleteExpiredArticles()) );
00369     QTimer::singleShot(0, this, SLOT(delayedInit()));
00370 }
00371 
00372 void View::delayedInit()
00373 {
00374     // HACK, FIXME:
00375     // for some reason, m_part->factory() is NULL at startup of kontact,
00376     // and thus the article viewer GUI can't be merged when creating the view.
00377     // Even the delayed init didn't help. Well, we retry every half a second until
00378     // it works. This is kind of creative, but a dirty hack nevertheless.
00379     if ( !m_part->mergePart(m_articleViewer) )
00380         QTimer::singleShot(500, this, SLOT(delayedInit()));
00381 }
00382 
00383 void View::slotSettingsChanged()
00384 {
00385     // if tagging is hidden, show only feed list
00386     m_listTabWidget->setViewMode(Settings::showTaggingGUI() ? ListTabWidget::verticalTabs : ListTabWidget::single);
00387     
00388 }
00389 
00390 void View::slotOnShutdown()
00391 {
00392     m_shuttingDown = true; // prevents slotFrameChanged from crashing
00393 
00394     m_articleList->slotShowNode(0);
00395     m_articleViewer->slotShowNode(0);
00396 
00397     Kernel::self()->fetchQueue()->slotAbort();
00398 
00399     m_feedListView->setNodeList(0);
00400     ProgressManager::self()->setFeedList(0);
00401 
00402     delete m_feedList;
00403     delete m_tagNodeList;
00404 
00405     // close all pageviewers in a controlled way
00406     // fixes bug 91660, at least when no part loading data
00407     m_tabs->setCurrentPage(m_tabs->count()-1); // select last page
00408     while (m_tabs->count() > 1) // remove frames until only the main frame remains
00409         m_tabs->slotRemoveCurrentFrame();
00410 
00411     delete m_mainTab;
00412     delete m_mainFrame;
00413     delete m_editNodePropertiesVisitor;
00414     delete m_deleteNodeVisitor;
00415 }
00416 
00417 void View::saveSettings()
00418 {
00419     Settings::setSplitter1Sizes( m_horizontalSplitter->sizes() );
00420     Settings::setSplitter2Sizes( m_articleSplitter->sizes() );
00421     Settings::setViewMode( m_viewMode );
00422     Settings::writeConfig();
00423 }
00424 
00425 void View::slotOpenNewTab(const KURL& url, bool background)
00426 {
00427     PageViewer* page = new PageViewer(this, "page");
00428     
00429     connect( m_part, SIGNAL(signalSettingsChanged()), page, SLOT(slotPaletteOrFontChanged()));
00430 
00431     connect( page, SIGNAL(setTabIcon(const QPixmap&)),
00432             this, SLOT(setTabIcon(const QPixmap&)));
00433     connect( page, SIGNAL(urlClicked(const KURL &, Viewer*, bool, bool)),
00434             this, SLOT(slotUrlClickedInViewer(const KURL &, Viewer*, bool, bool)) );
00435 
00436     Frame* frame = new Frame(this, page, page->widget(), i18n("Untitled"));
00437     frame->setAutoDeletePart(true); // delete page viewer when removing the tab
00438 
00439     connect(page, SIGNAL(setWindowCaption (const QString &)), frame, SLOT(setTitle (const QString &)));
00440     connectFrame(frame);
00441     m_tabs->addFrame(frame);
00442 
00443     if(!background)
00444         m_tabs->showPage(page->widget());
00445     else
00446         setFocus();
00447 
00448     page->openURL(url);
00449 }
00450 
00451 
00452 void View::setTabIcon(const QPixmap& icon)
00453 {
00454     const PageViewer *s = dynamic_cast<const PageViewer*>(sender());
00455     if (s) {
00456         m_tabs->setTabIconSet(const_cast<PageViewer*>(s)->widget(), icon);
00457     }
00458 }
00459 
00460 void View::connectFrame(Frame *f)
00461 {
00462     connect(f, SIGNAL(statusText(const QString &)), this, SLOT(slotStatusText(const QString&)));
00463     connect(f, SIGNAL(captionChanged (const QString &)), this, SLOT(slotCaptionChanged (const QString &)));
00464     connect(f, SIGNAL(loadingProgress(int)), this, SLOT(slotLoadingProgress(int)) );
00465     connect(f, SIGNAL(started()), this, SLOT(slotStarted()));
00466     connect(f, SIGNAL(completed()), this, SLOT(slotCompleted()));
00467     connect(f, SIGNAL(canceled(const QString &)), this, SLOT(slotCanceled(const QString&)));
00468 }
00469 
00470 void View::slotStatusText(const QString &c)
00471 {
00472     if (sender() == m_currentFrame)
00473         emit setStatusBarText(c);
00474 }
00475 
00476 void View::slotCaptionChanged(const QString &c)
00477 {
00478     if (sender() == m_currentFrame)
00479         emit setWindowCaption(c);
00480 }
00481 
00482 void View::slotStarted()
00483 {
00484     if (sender() == m_currentFrame)
00485         emit signalStarted(0);
00486 }
00487 
00488 void View::slotCanceled(const QString &s)
00489 {
00490     if (sender() == m_currentFrame)
00491         emit signalCanceled(s);
00492 }
00493 
00494 void View::slotCompleted()
00495 {
00496     if (sender() == m_currentFrame)
00497         emit signalCompleted();
00498 }
00499 
00500 void View::slotLoadingProgress(int percent)
00501 {
00502     if (sender() == m_currentFrame)
00503         emit setProgress(percent);
00504 }
00505 
00506 bool View::importFeeds(const QDomDocument& doc)
00507 {
00508     FeedList* feedList = new FeedList();
00509     bool parsed = feedList->readFromXML(doc);
00510 
00511     // FIXME: parsing error, print some message
00512     if (!parsed)
00513     {
00514         delete feedList;
00515         return false;
00516     }
00517     QString title = feedList->title();
00518 
00519     if (title.isEmpty())
00520         title = i18n("Imported Folder");
00521 
00522     bool ok;
00523     title = KInputDialog::getText(i18n("Add Imported Folder"), i18n("Imported folder name:"), title, &ok);
00524 
00525     if (!ok)
00526     {
00527         delete feedList;
00528         return false;
00529     }
00530 
00531     Folder* fg = new Folder(title);
00532     m_feedList->rootNode()->appendChild(fg);
00533     m_feedList->append(feedList, fg);
00534 
00535     return true;
00536 }
00537 
00538 bool View::loadFeeds(const QDomDocument& doc, Folder* parent)
00539 {
00540     FeedList* feedList = new FeedList();
00541     bool parsed = feedList->readFromXML(doc);
00542 
00543     // parsing went wrong
00544     if (!parsed)
00545     {
00546         delete feedList;
00547         return false;
00548     }
00549     m_feedListView->setUpdatesEnabled(false);
00550     m_tagNodeListView->setUpdatesEnabled(false);
00551     if (!parent)
00552     {
00553         TagSet* tagSet = Kernel::self()->tagSet();
00554 
00555         Kernel::self()->setFeedList(feedList);
00556         ProgressManager::self()->setFeedList(feedList);
00557         disconnectFromFeedList(m_feedList);
00558         delete m_feedList;
00559         delete m_tagNodeList;
00560         m_feedList = feedList;
00561         connectToFeedList(m_feedList);
00562 
00563         m_tagNodeList = new TagNodeList(m_feedList, tagSet);
00564         m_feedListView->setNodeList(m_feedList);
00565         m_tagNodeListView->setNodeList(m_tagNodeList);
00566 
00567         QStringList tagIDs = m_feedList->rootNode()->tags();
00568         QStringList::ConstIterator end = tagIDs.end();
00569         for (QStringList::ConstIterator it = tagIDs.begin(); it != end; ++it)
00570         {
00571             kdDebug() << *it << endl;
00572             // create a tag for every tag ID in the archive that is not part of the tagset
00573             // this is a fallback in case the tagset was corrupted,
00574             // so the tagging information from archive does not get lost.
00575             if (!tagSet->containsID(*it))
00576             {
00577                 Tag tag(*it, *it);
00578                 tagSet->insert(tag);
00579             }
00580         }
00581     }
00582     else
00583         m_feedList->append(feedList, parent);
00584 
00585     m_feedListView->setUpdatesEnabled(true);
00586     m_feedListView->triggerUpdate();
00587     m_tagNodeListView->setUpdatesEnabled(true);
00588     m_tagNodeListView->triggerUpdate();
00589     return true;
00590 }
00591 
00592 void View::slotDeleteExpiredArticles()
00593 {
00594     TreeNode* rootNode = m_feedList->rootNode();
00595     if (rootNode)
00596         rootNode->slotDeleteExpiredArticles();
00597 }
00598 
00599 QDomDocument View::feedListToOPML()
00600 {
00601     return m_feedList->toXML();
00602 }
00603 
00604 void View::addFeedToGroup(const QString& url, const QString& groupName)
00605 {
00606 
00607     // Locate the group.
00608     TreeNode* node = m_feedListView->findNodeByTitle(groupName);
00609 
00610     Folder* group = 0;
00611     if (!node || !node->isGroup())
00612     {
00613         Folder* g = new Folder( groupName );
00614         m_feedList->rootNode()->appendChild(g);
00615         group = g;
00616     }
00617     else
00618         group = static_cast<Folder*>(node);
00619 
00620     // Invoke the Add Feed dialog with url filled in.
00621     if (group)
00622         addFeed(url, 0, group, true);
00623 }
00624 
00625 void View::slotNormalView()
00626 {
00627     if (m_viewMode == NormalView)
00628     return;
00629 
00630     if (m_viewMode == CombinedView)
00631     {
00632         m_articleList->slotShowNode(m_listTabWidget->activeView()->selectedNode());
00633         m_articleList->show();
00634 
00635         Article article = m_articleList->currentArticle();
00636 
00637         if (!article.isNull())
00638             m_articleViewer->slotShowArticle(article);
00639         else
00640             m_articleViewer->slotShowSummary(m_listTabWidget->activeView()->selectedNode());
00641     }
00642 
00643     m_articleSplitter->setOrientation(QSplitter::Vertical);
00644     m_viewMode = NormalView;
00645 
00646     Settings::setViewMode( m_viewMode );
00647 }
00648 
00649 void View::slotWidescreenView()
00650 {
00651     if (m_viewMode == WidescreenView)
00652     return;
00653 
00654     if (m_viewMode == CombinedView)
00655     {
00656         m_articleList->slotShowNode(m_listTabWidget->activeView()->selectedNode());
00657         m_articleList->show();
00658 
00659         Article article = m_articleList->currentArticle();
00660 
00661         if (!article.isNull())
00662             m_articleViewer->slotShowArticle(article);
00663         else
00664             m_articleViewer->slotShowSummary(m_listTabWidget->activeView()->selectedNode());
00665     }
00666 
00667     m_articleSplitter->setOrientation(QSplitter::Horizontal);
00668     m_viewMode = WidescreenView;
00669 
00670     Settings::setViewMode( m_viewMode );
00671 }
00672 
00673 void View::slotCombinedView()
00674 {
00675     if (m_viewMode == CombinedView)
00676         return;
00677 
00678     m_articleList->slotClear();
00679     m_articleList->hide();
00680     m_viewMode = CombinedView;
00681 
00682     slotNodeSelected(m_listTabWidget->activeView()->selectedNode());
00683     Settings::setViewMode( m_viewMode );
00684 }
00685 
00686 void View::slotFrameChanged(Frame *f)
00687 {
00688     if (m_shuttingDown)
00689         return;
00690 
00691     m_currentFrame=f;
00692 
00693     emit setWindowCaption(f->caption());
00694     emit setProgress(f->progress());
00695     emit setStatusBarText(f->statusText());
00696 
00697     m_part->mergePart(m_articleViewer);
00698 
00699     if (f->part() == m_part)
00700         m_part->mergePart(m_articleViewer);
00701     else
00702         m_part->mergePart(f->part());
00703 
00704     f->widget()->setFocus();
00705 
00706     switch (f->state())
00707     {
00708         case Frame::Started:
00709             emit signalStarted(0);
00710             break;
00711         case Frame::Canceled:
00712             emit signalCanceled(QString::null);
00713             break;
00714         case Frame::Idle:
00715         case Frame::Completed:
00716         default:
00717             emit signalCompleted();
00718     }
00719 }
00720 
00721 void View::slotFeedTreeContextMenu(KListView*, TreeNode* /*node*/, const QPoint& /*p*/)
00722 {
00723     m_tabs->showPage(m_mainTab);
00724 }
00725 
00726 void View::slotMoveCurrentNodeUp()
00727 {
00728     TreeNode* current = m_listTabWidget->activeView()->selectedNode();
00729     if (!current)
00730         return;
00731     TreeNode* prev = current->prevSibling();
00732     Folder* parent = current->parent();
00733 
00734     if (!prev || !parent)
00735         return;
00736 
00737     parent->removeChild(prev);
00738     parent->insertChild(prev, current);
00739     m_listTabWidget->activeView()->ensureNodeVisible(current);
00740 }
00741 
00742 void View::slotMoveCurrentNodeDown()
00743 {
00744     TreeNode* current = m_listTabWidget->activeView()->selectedNode();
00745     if (!current)
00746         return;
00747     TreeNode* next = current->nextSibling();
00748     Folder* parent = current->parent();
00749 
00750     if (!next || !parent)
00751         return;
00752 
00753     parent->removeChild(current);
00754     parent->insertChild(current, next);
00755     m_listTabWidget->activeView()->ensureNodeVisible(current);
00756 }
00757 
00758 void View::slotMoveCurrentNodeLeft()
00759 {
00760     TreeNode* current = m_listTabWidget->activeView()->selectedNode();
00761     if (!current || !current->parent() || !current->parent()->parent())
00762         return;
00763 
00764     Folder* parent = current->parent();
00765     Folder* grandparent = current->parent()->parent();
00766 
00767     parent->removeChild(current);
00768     grandparent->insertChild(current, parent);
00769     m_listTabWidget->activeView()->ensureNodeVisible(current);
00770 }
00771 
00772 void View::slotMoveCurrentNodeRight()
00773 {
00774     TreeNode* current = m_listTabWidget->activeView()->selectedNode();
00775     if (!current || !current->parent())
00776         return;
00777     TreeNode* prev = current->prevSibling();
00778 
00779     if ( prev && prev->isGroup() )
00780     {
00781         Folder* fg = static_cast<Folder*>(prev);
00782         current->parent()->removeChild(current);
00783         fg->appendChild(current);
00784         m_listTabWidget->activeView()->ensureNodeVisible(current);
00785     }
00786 }
00787 
00788 void View::slotNodeSelected(TreeNode* node)
00789 {
00790     m_markReadTimer->stop();
00791 
00792     if (node)
00793     {
00794         kdDebug() << "node selected: " << node->title() << endl;
00795         kdDebug() << "unread: " << node->unread() << endl;
00796         kdDebug() << "total: " << node->totalCount() << endl;
00797     }
00798 
00799     if (m_displayingAboutPage)
00800     {
00801         m_mainFrame->setTitle(i18n("Articles"));
00802         if (m_viewMode != CombinedView)
00803             m_articleList->show();
00804         if (Settings::showQuickFilter())
00805             m_searchBar->show();
00806         m_displayingAboutPage = false;
00807     }
00808 
00809     m_tabs->showPage(m_mainTab);
00810 
00811     if (Settings::resetQuickFilterOnNodeChange())
00812         m_searchBar->slotClearSearch();
00813 
00814     if (m_viewMode == CombinedView)
00815         m_articleViewer->slotShowNode(node);
00816     else
00817     {
00818         m_articleList->slotShowNode(node);
00819         m_articleViewer->slotShowSummary(node);
00820     }
00821 
00822     if (node)
00823         m_mainFrame->setCaption(node->title());
00824 
00825     m_actionManager->slotNodeSelected(node);
00826 
00827     updateTagActions();
00828 }
00829 
00830 void View::slotOpenURL(const KURL& url, Viewer* currentViewer, BrowserRun::OpeningMode mode)
00831 {
00832     if (mode == BrowserRun::EXTERNAL)
00833         Viewer::displayInExternalBrowser(url);
00834     else
00835     {
00836          KParts::URLArgs args = currentViewer ? currentViewer->browserExtension()->urlArgs() : KParts::URLArgs();
00837             
00838         BrowserRun* r = new BrowserRun(this, currentViewer, url, args, mode);
00839         connect(r, SIGNAL(signalOpenInViewer(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)),
00840             this, SLOT(slotOpenURLReply(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)));
00841     }
00842 }
00843 
00844 //TODO: KDE4 remove this ugly ugly hack
00845 void View::slotUrlClickedInViewer(const KURL& url, Viewer* viewer, bool newTab, bool background)
00846 {
00847     
00848     if (!newTab)
00849     {
00850         slotOpenURL(url, viewer, BrowserRun::CURRENT_TAB);
00851     }
00852     else
00853     {
00854         slotOpenURL(url, 0L, background ? BrowserRun::NEW_TAB_BACKGROUND : BrowserRun::NEW_TAB_FOREGROUND);
00855     }
00856 }
00857 
00858 //TODO: KDE4 remove this ugly ugly hack
00859 void View::slotOpenURLReply(const KURL& url, Viewer* currentViewer, BrowserRun::OpeningMode mode)
00860 {
00861     switch (mode)
00862     {
00863         case BrowserRun::CURRENT_TAB:
00864             currentViewer->openURL(url);
00865             break;
00866         case BrowserRun::NEW_TAB_FOREGROUND:
00867         case BrowserRun::NEW_TAB_BACKGROUND:
00868             slotOpenNewTab(url, mode == BrowserRun::NEW_TAB_BACKGROUND);
00869             break;
00870         case BrowserRun::EXTERNAL:
00871             Viewer::displayInExternalBrowser(url);
00872             break;
00873     }
00874 }
00875 
00876 void View::slotFeedAdd()
00877 {
00878     Folder* group = 0;
00879     if (!m_feedListView->selectedNode())
00880         group = m_feedList->rootNode(); // all feeds
00881     else
00882     {
00883         //TODO: tag nodes need rework
00884         if ( m_feedListView->selectedNode()->isGroup())
00885             group = static_cast<Folder*>(m_feedListView->selectedNode());
00886         else
00887             group= m_feedListView->selectedNode()->parent();
00888 
00889     }
00890 
00891     TreeNode* lastChild = group->children().last();
00892 
00893     addFeed(QString::null, lastChild, group, false);
00894 }
00895 
00896 void View::addFeed(const QString& url, TreeNode *after, Folder* parent, bool autoExec)
00897 {
00898 
00899     AddFeedDialog *afd = new AddFeedDialog( 0, "add_feed" );
00900 
00901     afd->setURL(KURL::decode_string(url));
00902 
00903     if (autoExec)
00904         afd->slotOk();
00905     else
00906     {
00907         if (afd->exec() != QDialog::Accepted)
00908         {
00909             delete afd;
00910             return;
00911         }
00912     }
00913 
00914     Feed* feed = afd->feed;
00915     delete afd;
00916 
00917     FeedPropertiesDialog *dlg = new FeedPropertiesDialog( 0, "edit_feed" );
00918     dlg->setFeed(feed);
00919 
00920     dlg->selectFeedName();
00921 
00922     if (!autoExec)
00923         if (dlg->exec() != QDialog::Accepted)
00924         {
00925             delete feed;
00926             delete dlg;
00927             return;
00928         }
00929 
00930     if (!parent)
00931         parent = m_feedList->rootNode();
00932 
00933     parent->insertChild(feed, after);
00934 
00935     m_feedListView->ensureNodeVisible(feed);
00936 
00937 
00938     delete dlg;
00939 }
00940 
00941 void View::slotFeedAddGroup()
00942 {
00943     TreeNode* node = m_feedListView->selectedNode();
00944     TreeNode* after = 0;
00945 
00946     if (!node)
00947         node = m_feedListView->rootNode();
00948 
00949     // if a feed is selected, add group next to it
00950     //TODO: tag nodes need rework
00951     if (!node->isGroup())
00952     {
00953         after = node;
00954         node = node->parent();
00955     }
00956 
00957     Folder* currentGroup = static_cast<Folder*> (node);
00958 
00959     bool Ok;
00960 
00961     QString text = KInputDialog::getText(i18n("Add Folder"), i18n("Folder name:"), "", &Ok);
00962 
00963     if (Ok)
00964     {
00965         Folder* newGroup = new Folder(text);
00966         if (!after)
00967             currentGroup->appendChild(newGroup);
00968         else
00969             currentGroup->insertChild(newGroup, after);
00970 
00971         m_feedListView->ensureNodeVisible(newGroup);
00972     }
00973 }
00974 
00975 void View::slotFeedRemove()
00976 {
00977     TreeNode* selectedNode = m_listTabWidget->activeView()->selectedNode();
00978 
00979     // don't delete root element! (safety valve)
00980     if (!selectedNode || selectedNode == m_feedList->rootNode())
00981         return;
00982 
00983     m_deleteNodeVisitor->visit(selectedNode);
00984 }
00985 
00986 void View::slotFeedModify()
00987 {
00988     TreeNode* node = m_listTabWidget->activeView()->selectedNode();
00989     if (node)
00990         m_editNodePropertiesVisitor->visit(node);
00991 
00992 }
00993 
00994 void View::slotNextUnreadArticle()
00995 {
00996     if (m_viewMode == CombinedView)
00997         m_listTabWidget->activeView()->slotNextUnreadFeed();
00998     
00999     TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
01000     if (sel && sel->unread() > 0)
01001         m_articleList->slotNextUnreadArticle();
01002     else
01003         m_listTabWidget->activeView()->slotNextUnreadFeed();
01004 }
01005 
01006 void View::slotPrevUnreadArticle()
01007 {
01008     if (m_viewMode == CombinedView)
01009         m_listTabWidget->activeView()->slotPrevUnreadFeed();
01010     
01011     TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
01012     if (sel && sel->unread() > 0)
01013         m_articleList->slotPreviousUnreadArticle();
01014     else
01015         m_listTabWidget->activeView()->slotPrevUnreadFeed();
01016 }
01017 
01018 void View::slotMarkAllFeedsRead()
01019 {
01020     m_feedList->rootNode()->slotMarkAllArticlesAsRead();
01021 }
01022 
01023 void View::slotMarkAllRead()
01024 {
01025     if(!m_listTabWidget->activeView()->selectedNode()) return;
01026     m_listTabWidget->activeView()->selectedNode()->slotMarkAllArticlesAsRead();
01027 }
01028 
01029 void View::slotOpenHomepage()
01030 {
01031     Feed* feed = dynamic_cast<Feed *>(m_listTabWidget->activeView()->selectedNode());
01032 
01033     if (!feed)
01034         return;
01035 
01036     KURL url = KURL(feed->htmlUrl())
01037 ;
01038     switch (Settings::lMBBehaviour())
01039     {
01040         case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
01041             slotOpenURL(url, 0, BrowserRun::EXTERNAL);
01042             break;
01043         case Settings::EnumLMBBehaviour::OpenInBackground:
01044             slotOpenURL(url, 0, BrowserRun::NEW_TAB_BACKGROUND);
01045             break;
01046         default:
01047             slotOpenURL(url, 0, BrowserRun::NEW_TAB_FOREGROUND);
01048     }
01049 }
01050 
01051 void View::slotSetTotalUnread()
01052 {
01053     emit signalUnreadCountChanged( m_feedList->rootNode()->unread() );
01054 }
01055 
01056 void View::slotDoIntervalFetches()
01057 {
01058     m_feedList->rootNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue(), true);
01059 }
01060 
01061 void View::slotFetchCurrentFeed()
01062 {
01063     if ( !m_listTabWidget->activeView()->selectedNode() )
01064         return;
01065     m_listTabWidget->activeView()->selectedNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
01066 }
01067 
01068 void View::slotFetchAllFeeds()
01069 {
01070     m_feedList->rootNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
01071 }
01072 
01073 void View::slotFetchingStarted()
01074 {
01075     m_mainFrame->setState(Frame::Started);
01076     m_actionManager->action("feed_stop")->setEnabled(true);
01077     m_mainFrame->setStatusText(i18n("Fetching Feeds..."));
01078 }
01079 
01080 void View::slotFetchingStopped()
01081 {
01082     m_mainFrame->setState(Frame::Completed);
01083     m_actionManager->action("feed_stop")->setEnabled(false);
01084     m_mainFrame->setStatusText(QString::null);
01085 }
01086 
01087 void View::slotFeedFetched(Feed *feed)
01088 {
01089     // iterate through the articles (once again) to do notifications properly
01090     if (feed->articles().count() > 0)
01091     {
01092         QValueList<Article> articles = feed->articles();
01093         QValueList<Article>::ConstIterator it;
01094         QValueList<Article>::ConstIterator end = articles.end();
01095         for (it = articles.begin(); it != end; ++it)
01096         {
01097             if ((*it).status()==Article::New && ((*it).feed()->useNotification() || Settings::useNotifications()))
01098             {
01099                 NotificationManager::self()->slotNotifyArticle(*it);
01100             }
01101         }
01102     }
01103 }
01104 
01105 void View::slotMouseButtonPressed(int button, const Article& article, const QPoint &, int)
01106 {
01107     if (button == Qt::MidButton)
01108     {
01109         KURL link = article.link();
01110         switch (Settings::mMBBehaviour())
01111         {
01112             case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
01113                 slotOpenURL(link, 0L, BrowserRun::EXTERNAL);
01114                 break;
01115             case Settings::EnumMMBBehaviour::OpenInBackground:
01116                 slotOpenURL(link, 0L, BrowserRun::NEW_TAB_BACKGROUND);
01117                 break;
01118             default:
01119                 slotOpenURL(link, 0L, BrowserRun::NEW_TAB_FOREGROUND);
01120         }
01121     }
01122 }
01123 
01124 void View::slotAssignTag(const Tag& tag, bool assign)
01125 {
01126     kdDebug() << (assign ? "assigned" : "removed") << " tag \"" << tag.id() << "\"" << endl;
01127     QValueList<Article> selectedArticles = m_articleList->selectedArticles();
01128     for (QValueList<Article>::Iterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
01129     {
01130         if (assign)
01131             (*it).addTag(tag.id());
01132         else
01133             (*it).removeTag(tag.id());
01134     }
01135     updateTagActions();
01136 }
01137 /*
01138 void View::slotRemoveTag(const Tag& tag)
01139 {
01140     kdDebug() << "remove tag \"" << tag.id() << "\" from selected articles" << endl;
01141     QValueList<Article> selectedArticles = m_articleList->selectedArticles();
01142     for (QValueList<Article>::Iterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
01143         (*it).removeTag(tag.id());
01144 
01145     updateTagActions();
01146 }
01147 */
01148 void View::slotNewTag()
01149 {
01150     Tag tag(KApplication::randomString(8), "New Tag");
01151     Kernel::self()->tagSet()->insert(tag);
01152     TagNode* node = m_tagNodeList->findByTagID(tag.id());
01153     if (node)
01154         m_tagNodeListView->startNodeRenaming(node);
01155 }
01156 
01157 void View::slotTagCreated(const Tag& tag)
01158 {
01159     if (m_tagNodeList && !m_tagNodeList->containsTagId(tag.id()))
01160     {
01161         TagNode* tagNode = new TagNode(tag, m_feedList->rootNode());
01162         m_tagNodeList->rootNode()->appendChild(tagNode);
01163     }
01164 }
01165 
01166 void View::slotTagRemoved(const Tag& /*tag*/)
01167 {
01168 }
01169 
01170 void View::slotArticleSelected(const Article& article)
01171 {
01172     if (m_viewMode == CombinedView)
01173         return;
01174 
01175     m_markReadTimer->stop();
01176 
01177     Feed *feed = article.feed();
01178     if (!feed)
01179         return;
01180 
01181     Article a(article);
01182     if (a.status() != Article::Read)
01183     {
01184         int delay;
01185 
01186         if ( Settings::useMarkReadDelay() )
01187         {
01188             delay = Settings::markReadDelay();
01189 
01190             if (delay > 0)
01191                 m_markReadTimer->start( delay*1000, true );
01192             else
01193                 a.setStatus(Article::Read);
01194         }
01195     }
01196 
01197     KToggleAction*  maai = dynamic_cast<KToggleAction*>(m_actionManager->action("article_set_status_important"));
01198     maai->setChecked(a.keep());
01199 
01200     kdDebug() << "selected: " << a.guid() << endl;
01201 
01202     updateTagActions();
01203 
01204     m_articleViewer->slotShowArticle(a);
01205 }
01206 
01207 void View::slotOpenArticleExternal(const Article& article, const QPoint&, int)
01208 {
01209     if (!article.isNull())
01210         Viewer::displayInExternalBrowser(article.link());
01211 }
01212 
01213 
01214 void View::slotOpenCurrentArticle()
01215 {
01216     Article article = m_articleList->currentArticle();
01217 
01218     if (article.isNull())
01219         return;
01220 
01221     KURL link;
01222     if (article.link().isValid())
01223         link = article.link();
01224     else if (article.guidIsPermaLink())
01225         link = KURL(article.guid());
01226     
01227     if (link.isValid()) 
01228     {
01229         slotOpenURL(link, 0L, BrowserRun::NEW_TAB_FOREGROUND);
01230     }
01231 }
01232 
01233 void View::slotOpenCurrentArticleExternal()
01234 {
01235     slotOpenArticleExternal(m_articleList->currentArticle(), QPoint(), 0);
01236 }
01237 
01238 void View::slotOpenCurrentArticleBackgroundTab()
01239 {
01240     Article article = m_articleList->currentArticle();
01241 
01242     if (article.isNull())
01243         return;
01244 
01245     KURL link;
01246 
01247     if (article.link().isValid())
01248         link = article.link();
01249     else if (article.guidIsPermaLink())
01250         link = KURL(article.guid());
01251     
01252     if (link.isValid()) 
01253     {
01254         slotOpenURL(link, 0L, BrowserRun::NEW_TAB_BACKGROUND);
01255     }
01256 }
01257 
01258 void View::slotCopyLinkAddress()
01259 {
01260     Article article = m_articleList->currentArticle();
01261 
01262     if(article.isNull())
01263        return;
01264 
01265     QString link;
01266     if (article.link().isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
01267     {
01268         // in case link isn't valid, fall back to the guid permaLink.
01269         if (article.link().isValid())
01270             link = article.link().url();
01271         else
01272             link = article.guid();
01273         QClipboard *cb = QApplication::clipboard();
01274         cb->setText(link, QClipboard::Clipboard);
01275         cb->setText(link, QClipboard::Selection);
01276     }
01277 }
01278 
01279 void View::slotFeedURLDropped(KURL::List &urls, TreeNode* after, Folder* parent)
01280 {
01281     KURL::List::iterator it;
01282     for ( it = urls.begin(); it != urls.end(); ++it )
01283     {
01284         addFeed((*it).prettyURL(), after, parent, false);
01285     }
01286 }
01287 
01288 void View::slotToggleShowQuickFilter()
01289 {
01290     if ( Settings::showQuickFilter() )
01291     {
01292         Settings::setShowQuickFilter(false);
01293         m_searchBar->slotClearSearch();
01294         m_searchBar->hide();
01295     }
01296     else
01297     {
01298         Settings::setShowQuickFilter(true);
01299         if (!m_displayingAboutPage)
01300             m_searchBar->show();
01301     }
01302 
01303 }
01304 
01305 void View::slotArticleDelete()
01306 {
01307 
01308     if ( m_viewMode == CombinedView )
01309         return;
01310 
01311     QValueList<Article> articles = m_articleList->selectedArticles();
01312 
01313     QString msg;
01314     switch (articles.count())
01315     {
01316         case 0:
01317             return;
01318         case 1:
01319             msg = i18n("<qt>Are you sure you want to delete article <b>%1</b>?</qt>").arg(QStyleSheet::escape(articles.first().title()));
01320             break;
01321         default:
01322             msg = i18n("<qt>Are you sure you want to delete the selected article?</qt>", 
01323         "<qt>Are you sure you want to delete the %n selected articles?</qt>",
01324         articles.count());
01325     }
01326 
01327     if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Article"), KStdGuiItem::del()) == KMessageBox::Continue)
01328     {
01329         if (m_listTabWidget->activeView()->selectedNode())
01330             m_listTabWidget->activeView()->selectedNode()->setNotificationMode(false);
01331 
01332         QValueList<Feed*> feeds;
01333         for (QValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
01334         {
01335             Feed* feed = (*it).feed();
01336             if (!feeds.contains(feed))
01337                 feeds.append(feed);
01338             feed->setNotificationMode(false);
01339             (*it).setDeleted();
01340         }
01341 
01342         for (QValueList<Feed*>::Iterator it = feeds.begin(); it != feeds.end(); ++it)
01343         {
01344             (*it)->setNotificationMode(true);
01345         }
01346 
01347         if (m_listTabWidget->activeView()->selectedNode())
01348             m_listTabWidget->activeView()->selectedNode()->setNotificationMode(true);
01349     }
01350 }
01351 
01352 
01353 void View::slotArticleToggleKeepFlag(bool /*enabled*/)
01354 {
01355     QValueList<Article> articles = m_articleList->selectedArticles();
01356 
01357     if (articles.isEmpty())
01358         return;
01359 
01360     bool allFlagsSet = true;
01361     for (QValueList<Article>::Iterator it = articles.begin(); allFlagsSet && it != articles.end(); ++it)
01362         if (!(*it).keep())
01363             allFlagsSet = false;
01364 
01365     for (QValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
01366         (*it).setKeep(!allFlagsSet);
01367 }
01368 
01369 void View::slotSetSelectedArticleRead()
01370 {
01371     QValueList<Article> articles = m_articleList->selectedArticles();
01372 
01373     if (articles.isEmpty())
01374         return;
01375 
01376     for (QValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
01377         (*it).setStatus(Article::Read);
01378 }
01379 
01380 void View::slotTextToSpeechRequest()
01381 {
01382     if (m_currentFrame == m_mainFrame)
01383     {
01384         if (m_viewMode != CombinedView)
01385         {
01386             // in non-combined view, read selected articles
01387             SpeechClient::self()->slotSpeak(m_articleList->selectedArticles());
01388             // TODO: if article viewer has a selection, read only the selected text?
01389         }
01390         else
01391         {
01392             if (m_listTabWidget->activeView()->selectedNode())
01393             {
01394                 //TODO: read articles in current node, respecting quick filter!
01395             }
01396         }
01397     }
01398     else
01399     {
01400         QString selectedText = static_cast<PageViewer *>(m_currentFrame->part())->selectedText();
01401         
01402         if (!selectedText.isEmpty())
01403             SpeechClient::self()->slotSpeak(selectedText, "en");
01404     }
01405 }
01406 
01407 void View::slotSetSelectedArticleUnread()
01408 {
01409     QValueList<Article> articles = m_articleList->selectedArticles();
01410 
01411     if (articles.isEmpty())
01412         return;
01413 
01414     for (QValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
01415         (*it).setStatus(Article::Unread);
01416 }
01417 
01418 void View::slotSetSelectedArticleNew()
01419 {
01420     QValueList<Article> articles = m_articleList->selectedArticles();
01421 
01422     if (articles.isEmpty())
01423         return;
01424 
01425     for (QValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
01426         (*it).setStatus(Article::New);
01427 }
01428 
01429 void View::slotSetCurrentArticleReadDelayed()
01430 {
01431     Article article = m_articleList->currentArticle();
01432 
01433     if (article.isNull())
01434         return;
01435 
01436     article.setStatus(Article::Read);
01437 }
01438 
01439 void View::slotMouseOverInfo(const KFileItem *kifi)
01440 {
01441     if (kifi)
01442     {
01443         KFileItem *k=(KFileItem*)kifi;
01444         m_mainFrame->setStatusText(k->url().prettyURL());//getStatusBarInfo());
01445     }
01446     else
01447     {
01448         m_mainFrame->setStatusText(QString::null);
01449     }
01450 }
01451 
01452 void View::readProperties(KConfig* config)
01453 {
01454     
01455     if (!Settings::resetQuickFilterOnNodeChange())
01456     {
01457         m_searchBar->slotSetText(config->readEntry("searchLine"));
01458         int statusfilter = config->readNumEntry("searchCombo", -1);
01459         if (statusfilter != -1)
01460             m_searchBar->slotSetStatus(statusfilter);
01461     }
01462     
01463     int selectedID = config->readNumEntry("selectedNodeID", -1);
01464     if (selectedID != -1)
01465     {
01466         TreeNode* selNode = m_feedList->findByID(selectedID);
01467         if (selNode)
01468             m_listTabWidget->activeView()->setSelectedNode(selNode);
01469     }
01470 }
01471 
01472 void View::saveProperties(KConfig* config)
01473 {
01474     // save filter settings
01475     config->writeEntry("searchLine", m_searchBar->text());
01476     config->writeEntry("searchCombo", m_searchBar->status());
01477     
01478     TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
01479 
01480     if (sel)
01481     {
01482         config->writeEntry("selectedNodeID", sel->id() );
01483     }
01484 }
01485 
01486 void View::connectToFeedList(FeedList* feedList)
01487 {
01488     connect(feedList->rootNode(), SIGNAL(signalChanged(TreeNode*)), this, SLOT(slotSetTotalUnread()));
01489     slotSetTotalUnread();
01490 }
01491 
01492 void View::disconnectFromFeedList(FeedList* feedList)
01493 {
01494     disconnect(feedList->rootNode(), SIGNAL(signalChanged(TreeNode*)), this, SLOT(slotSetTotalUnread()));
01495 }
01496 
01497 void View::updateTagActions()
01498 {
01499     QStringList tags;
01500 
01501     QValueList<Article> selectedArticles = m_articleList->selectedArticles();
01502 
01503     for (QValueList<Article>::ConstIterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
01504     {
01505         QStringList atags = (*it).tags();
01506         for (QStringList::ConstIterator it2 = atags.begin(); it2 != atags.end(); ++it2)
01507         {
01508             if (!tags.contains(*it2))
01509                 tags += *it2;
01510         }
01511     }
01512     m_actionManager->slotUpdateTagActions(!selectedArticles.isEmpty(), tags);
01513 }
01514 
01515 } // namespace Akregator
01516 
01517 #include "akregator_view.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys