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"