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