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