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"