akregator/src

akregator_view.cpp
1 /*
2  This file is part of Akregator.
3 
4  Copyright (C) 2004 Stanislav Karchebny <Stanislav.Karchebny@kdemail.net>
5  2004 Sashmit Bhaduri <smt@vfemail.net>
6  2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 
22  As a special exception, permission is given to link this program
23  with any edition of TQt, and distribute the resulting executable,
24  without including the source code for TQt in the source distribution.
25 */
26 
27 #include "actionmanagerimpl.h"
28 #include "akregator_part.h"
29 #include "akregator_run.h"
30 #include "akregator_view.h"
31 #include "listtabwidget.h"
32 #include "addfeeddialog.h"
33 #include "propertiesdialog.h"
34 #include "frame.h"
35 #include "fetchqueue.h"
36 #include "feedlistview.h"
37 #include "articlelistview.h"
38 #include "articleviewer.h"
39 #include "viewer.h"
40 #include "feed.h"
41 #include "tagfolder.h"
42 #include "folder.h"
43 #include "feedlist.h"
44 #include "akregatorconfig.h"
45 #include "kernel.h"
46 #include "pageviewer.h"
47 #include "searchbar.h"
48 #include "speechclient.h"
49 #include "storage.h"
50 #include "tabwidget.h"
51 #include "tag.h"
52 #include "tagset.h"
53 #include "tagnode.h"
54 #include "tagnodelist.h"
55 #include "tagpropertiesdialog.h"
56 #include "treenode.h"
57 #include "progressmanager.h"
58 #include "treenodevisitor.h"
59 #include "notificationmanager.h"
60 
61 #include <kaction.h>
62 #include <kapplication.h>
63 #include <kcharsets.h>
64 #include <kcombobox.h>
65 #include <kconfig.h>
66 #include <kdebug.h>
67 #include <kdialog.h>
68 #include <kfiledialog.h>
69 #include <kfileitem.h>
70 #include <khtml_part.h>
71 #include <khtmlview.h>
72 #include <kiconloader.h>
73 #include <kinputdialog.h>
74 #include <klineedit.h>
75 #include <klistview.h>
76 #include <klocale.h>
77 #include <kmessagebox.h>
78 #include <kpassdlg.h>
79 #include <kprocess.h>
80 #include <krun.h>
81 #include <kshell.h>
82 #include <kstandarddirs.h>
83 #include <kurl.h>
84 #include <kxmlguifactory.h>
85 #include <kparts/partmanager.h>
86 
87 #include <tqbuttongroup.h>
88 #include <tqcheckbox.h>
89 #include <tqdatetime.h> // for startup time measure
90 #include <tqfile.h>
91 #include <tqhbox.h>
92 #include <tqlabel.h>
93 #include <tqlayout.h>
94 #include <tqmultilineedit.h>
95 #include <tqpopupmenu.h>
96 #include <tqptrlist.h>
97 #include <tqstylesheet.h>
98 #include <tqtextstream.h>
99 #include <tqtimer.h>
100 #include <tqtoolbutton.h>
101 #include <tqtooltip.h>
102 #include <tqvaluevector.h>
103 #include <tqwhatsthis.h>
104 #include <tqclipboard.h>
105 
106 namespace Akregator {
107 
108 class View::EditNodePropertiesVisitor : public TreeNodeVisitor
109 {
110  public:
111  EditNodePropertiesVisitor(View* view) : m_view(view) {}
112 
113  virtual bool visitTagNode(TagNode* node)
114  {
115  TagPropertiesDialog* dlg = new TagPropertiesDialog(m_view);
116  dlg->setTag(node->tag());
117  dlg->exec();
118  delete dlg;
119  return true;
120  }
121 
122  virtual bool visitFolder(Folder* node)
123  {
124  m_view->m_listTabWidget->activeView()->startNodeRenaming(node);
125  return true;
126  }
127 
128  virtual bool visitFeed(Feed* node)
129  {
130  FeedPropertiesDialog *dlg = new FeedPropertiesDialog( m_view, "edit_feed" );
131  dlg->setFeed(node);
132  dlg->exec();
133  delete dlg;
134  return true;
135  }
136  private:
137 
138  View* m_view;
139 };
140 
141 class View::DeleteNodeVisitor : public TreeNodeVisitor
142 {
143  public:
144  DeleteNodeVisitor(View* view) : m_view(view) {}
145 
146  virtual bool visitTagNode(TagNode* node)
147  {
148  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());
149  if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Tag"), KStdGuiItem::del()) == KMessageBox::Continue)
150  {
151  Tag tag = node->tag();
152  TQValueList<Article> articles = m_view->m_feedList->rootNode()->articles(tag.id());
153  node->setNotificationMode(false);
154  for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
155  (*it).removeTag(tag.id());
156  node->setNotificationMode(true);
157  Kernel::self()->tagSet()->remove(tag);
158  m_view->m_listTabWidget->activeView()->setFocus();
159  }
160  return true;
161  }
162 
163  virtual bool visitFolder(Folder* node)
164  {
165  TQString msg;
166  if (node->title().isEmpty())
167  msg = i18n("<qt>Are you sure you want to delete this folder and its feeds and subfolders?</qt>");
168  else
169  msg = i18n("<qt>Are you sure you want to delete folder <b>%1</b> and its feeds and subfolders?</qt>").arg(node->title());
170 
171  if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Folder"), KStdGuiItem::del()) == KMessageBox::Continue)
172  {
173  delete node;
174  m_view->m_listTabWidget->activeView()->setFocus();
175  }
176  return true;
177  }
178 
179  virtual bool visitFeed(Feed* node)
180  {
181  TQString msg;
182  if (node->title().isEmpty())
183  msg = i18n("<qt>Are you sure you want to delete this feed?</qt>");
184  else
185  msg = i18n("<qt>Are you sure you want to delete feed <b>%1</b>?</qt>").arg(node->title());
186 
187  if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Feed"), KStdGuiItem::del()) == KMessageBox::Continue)
188  {
189  delete node;
190  m_view->m_listTabWidget->activeView()->setFocus();
191  }
192  return true;
193  }
194  private:
195 
196  View* m_view;
197 };
198 
199 
201 {
202  // if m_shuttingDown is false, slotOnShutdown was not called. That
203  // means that not the whole app is shutdown, only the part. So it
204  // should be no risk to do the cleanups now
205  if (!m_shuttingDown)
206  {
207  kdDebug() << "View::~View(): slotOnShutdown() wasn't called. Calling it now." << endl;
208  slotOnShutdown();
209  }
210  kdDebug() << "View::~View(): leaving" << endl;
211 }
212 
213 View::View( Part *part, TQWidget *parent, ActionManagerImpl* actionManager, const char *name)
214  : TQWidget(parent, name), m_viewMode(NormalView), m_actionManager(actionManager)
215 {
216  m_editNodePropertiesVisitor = new EditNodePropertiesVisitor(this);
217  m_deleteNodeVisitor = new DeleteNodeVisitor(this);
218  m_keepFlagIcon = TQPixmap(locate("data", "akregator/pics/akregator_flag.png"));
219  m_part = part;
220  m_feedList = new FeedList();
221  m_tagNodeList = new TagNodeList(m_feedList, Kernel::self()->tagSet());
222  m_shuttingDown = false;
223  m_displayingAboutPage = false;
224  m_currentFrame = 0L;
225  setFocusPolicy(TQ_StrongFocus);
226 
227  TQVBoxLayout *lt = new TQVBoxLayout( this );
228 
229  m_horizontalSplitter = new TQSplitter(Qt::Horizontal, this);
230 
231  m_horizontalSplitter->setOpaqueResize(true);
232  lt->addWidget(m_horizontalSplitter);
233 
234  connect (Kernel::self()->fetchQueue(), TQT_SIGNAL(fetched(Feed*)), this, TQT_SLOT(slotFeedFetched(Feed*)));
235  connect (Kernel::self()->fetchQueue(), TQT_SIGNAL(signalStarted()), this, TQT_SLOT(slotFetchingStarted()));
236  connect (Kernel::self()->fetchQueue(), TQT_SIGNAL(signalStopped()), this, TQT_SLOT(slotFetchingStopped()));
237 
238  connect(Kernel::self()->tagSet(), TQT_SIGNAL(signalTagAdded(const Tag&)), this, TQT_SLOT(slotTagCreated(const Tag&)));
239  connect(Kernel::self()->tagSet(), TQT_SIGNAL(signalTagRemoved(const Tag&)), this, TQT_SLOT(slotTagRemoved(const Tag&)));
240 
241  m_listTabWidget = new ListTabWidget(m_horizontalSplitter);
242  m_actionManager->initListTabWidget(m_listTabWidget);
243 
244  connect(m_listTabWidget, TQT_SIGNAL(signalNodeSelected(TreeNode*)), this, TQT_SLOT(slotNodeSelected(TreeNode*)));
245 
246  if (!Settings::showTaggingGUI())
247  m_listTabWidget->setViewMode(ListTabWidget::single);
248 
249  m_feedListView = new NodeListView( this, "feedtree" );
250  m_listTabWidget->addView(m_feedListView, i18n("Feeds"), KGlobal::iconLoader()->loadIcon("folder", KIcon::Small));
251 
252  connect(m_feedListView, TQT_SIGNAL(signalContextMenu(KListView*, TreeNode*, const TQPoint&)), this, TQT_SLOT(slotFeedTreeContextMenu(KListView*, TreeNode*, const TQPoint&)));
253 
254  connect(m_feedListView, TQT_SIGNAL(signalDropped (KURL::List &, TreeNode*,
255  Folder*)), this, TQT_SLOT(slotFeedURLDropped (KURL::List &,
256  TreeNode*, Folder*)));
257 
258  m_tagNodeListView = new NodeListView(this);
259  m_listTabWidget->addView(m_tagNodeListView, i18n("Tags"), KGlobal::iconLoader()->loadIcon("rss_tag", KIcon::Small));
260 
261  connect(m_tagNodeListView, TQT_SIGNAL(signalContextMenu(KListView*, TreeNode*, const TQPoint&)), this, TQT_SLOT(slotFeedTreeContextMenu(KListView*, TreeNode*, const TQPoint&)));
262 
263 
264  ProgressManager::self()->setFeedList(m_feedList);
265 
266  m_tabs = new TabWidget(m_horizontalSplitter);
267  m_actionManager->initTabWidget(m_tabs);
268 
269  connect( m_part, TQT_SIGNAL(signalSettingsChanged()), m_tabs, TQT_SLOT(slotSettingsChanged()));
270 
271  connect( m_tabs, TQT_SIGNAL( currentFrameChanged(Frame *) ), this,
272  TQT_SLOT( slotFrameChanged(Frame *) ) );
273 
274  TQWhatsThis::add(m_tabs, i18n("You can view multiple articles in several open tabs."));
275 
276  m_mainTab = new TQWidget(this, "Article Tab");
277  TQVBoxLayout *mainTabLayout = new TQVBoxLayout( m_mainTab, 0, 2, "mainTabLayout");
278 
279  TQWhatsThis::add(m_mainTab, i18n("Articles list."));
280 
281  m_searchBar = new SearchBar(m_mainTab);
282 
283  if ( !Settings::showQuickFilter() )
284  m_searchBar->hide();
285 
286  mainTabLayout->addWidget(m_searchBar);
287 
288  m_articleSplitter = new TQSplitter(Qt::Vertical, m_mainTab, "panner2");
289 
290  m_articleList = new ArticleListView( m_articleSplitter, "articles" );
291  m_actionManager->initArticleListView(m_articleList);
292 
293  connect( m_articleList, TQT_SIGNAL(signalMouseButtonPressed(int, const Article&, const TQPoint &, int)), this, TQT_SLOT(slotMouseButtonPressed(int, const Article&, const TQPoint &, int)));
294 
295  // use selectionChanged instead of clicked
296  connect( m_articleList, TQT_SIGNAL(signalArticleChosen(const Article&)),
297  this, TQT_SLOT( slotArticleSelected(const Article&)) );
298  connect( m_articleList, TQT_SIGNAL(signalDoubleClicked(const Article&, const TQPoint&, int)),
299  this, TQT_SLOT( slotOpenArticleExternal(const Article&, const TQPoint&, int)) );
300 
301  m_articleViewer = new ArticleViewer(m_articleSplitter, "article_viewer");
302  m_articleViewer->setSafeMode(); // disable JS, Java, etc...
303 
304  m_actionManager->initArticleViewer(m_articleViewer);
305 
306  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&)));
307 
308  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&)));
309 
310  connect( m_articleViewer, TQT_SIGNAL(urlClicked(const KURL&, Viewer*, bool, bool)),
311  this, TQT_SLOT(slotUrlClickedInViewer(const KURL&, Viewer*, bool, bool)) );
312 
313  connect( m_articleViewer->browserExtension(), TQT_SIGNAL(mouseOverInfo(const KFileItem *)),
314  this, TQT_SLOT(slotMouseOverInfo(const KFileItem *)) );
315 
316  connect( m_part, TQT_SIGNAL(signalSettingsChanged()), m_articleViewer, TQT_SLOT(slotPaletteOrFontChanged()));
317  TQWhatsThis::add(m_articleViewer->widget(), i18n("Browsing area."));
318  mainTabLayout->addWidget( m_articleSplitter );
319 
320  m_mainFrame=new Frame(TQT_TQOBJECT(this), m_part, m_mainTab, i18n("Articles"), false);
321  connectFrame(m_mainFrame);
322  m_tabs->addFrame(m_mainFrame);
323 
324  const TQValueList<int> sp1sizes = Settings::splitter1Sizes();
325  if ( sp1sizes.count() >= m_horizontalSplitter->sizes().count() )
326  m_horizontalSplitter->setSizes( sp1sizes );
327  const TQValueList<int> sp2sizes = Settings::splitter2Sizes();
328  if ( sp2sizes.count() >= m_articleSplitter->sizes().count() )
329  m_articleSplitter->setSizes( sp2sizes );
330 
331  KConfig *conf = Settings::self()->config();
332  conf->setGroup("General");
333  if(!conf->readBoolEntry("Disable Introduction", false))
334  {
335  m_articleList->hide();
336  m_searchBar->hide();
337  m_articleViewer->displayAboutPage();
338  m_mainFrame->setTitle(i18n("About"));
339  m_displayingAboutPage = true;
340  }
341 
342  m_fetchTimer = new TQTimer(this);
343  connect( m_fetchTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotDoIntervalFetches()) );
344  m_fetchTimer->start(1000*60);
345 
346  // delete expired articles once per hour
347  m_expiryTimer = new TQTimer(this);
348  connect(m_expiryTimer, TQT_SIGNAL(timeout()), this,
349  TQT_SLOT(slotDeleteExpiredArticles()) );
350  m_expiryTimer->start(3600*1000);
351 
352  m_markReadTimer = new TQTimer(this);
353  connect(m_markReadTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotSetCurrentArticleReadDelayed()) );
354 
355  switch (Settings::viewMode())
356  {
357  case CombinedView:
359  break;
360  case WidescreenView:
362  break;
363  default:
364  slotNormalView();
365  }
366 
367  if (!Settings::resetQuickFilterOnNodeChange())
368  {
369  m_searchBar->slotSetStatus(Settings::statusFilter());
370  m_searchBar->slotSetText(Settings::textFilter());
371  }
372 
373  TQTimer::singleShot(1000, this, TQT_SLOT(slotDeleteExpiredArticles()) );
374  m_part->mergePart(m_articleViewer);
375 }
376 
377 void View::slotSettingsChanged()
378 {
379  // if tagging is hidden, show only feed list
380  m_listTabWidget->setViewMode(Settings::showTaggingGUI() ? ListTabWidget::verticalTabs : ListTabWidget::single);
381 
382 }
383 
384 void View::slotOnShutdown()
385 {
386  m_shuttingDown = true; // prevents slotFrameChanged from crashing
387 
388  m_articleList->slotShowNode(0);
389  m_articleViewer->slotShowNode(0);
390 
391  Kernel::self()->fetchQueue()->slotAbort();
392 
393  m_feedListView->setNodeList(0);
394  ProgressManager::self()->setFeedList(0);
395 
396  delete m_feedList;
397  delete m_tagNodeList;
398 
399  // close all pageviewers in a controlled way
400  // fixes bug 91660, at least when no part loading data
401  m_tabs->setCurrentPage(m_tabs->count()-1); // select last page
402  while (m_tabs->count() > 1) // remove frames until only the main frame remains
403  m_tabs->slotRemoveCurrentFrame();
404 
405  delete m_mainTab;
406  delete m_mainFrame;
407  delete m_editNodePropertiesVisitor;
408  delete m_deleteNodeVisitor;
409 }
410 
412 {
413  const TQValueList<int> spl1 = m_horizontalSplitter->sizes();
414  if ( spl1.contains( 0 ) == 0 )
415  Settings::setSplitter1Sizes( spl1 );
416  const TQValueList<int> spl2 = m_articleSplitter->sizes();
417  if ( spl2.contains( 0 ) == 0 )
418  Settings::setSplitter2Sizes( spl2 );
419  Settings::setViewMode( m_viewMode );
420  Settings::writeConfig();
421 }
422 
423 void View::slotOpenNewTab(const KURL& url, bool background)
424 {
425  PageViewer* page = new PageViewer(this, "page");
426 
427  connect( m_part, TQT_SIGNAL(signalSettingsChanged()), page, TQT_SLOT(slotPaletteOrFontChanged()));
428 
429  connect( page, TQT_SIGNAL(setTabIcon(const TQPixmap&)),
430  this, TQT_SLOT(setTabIcon(const TQPixmap&)));
431  connect( page, TQT_SIGNAL(urlClicked(const KURL &, Viewer*, bool, bool)),
432  this, TQT_SLOT(slotUrlClickedInViewer(const KURL &, Viewer*, bool, bool)) );
433 
434  Frame* frame = new Frame(TQT_TQOBJECT(this), page, page->widget(), i18n("Untitled"));
435  frame->setAutoDeletePart(true); // delete page viewer when removing the tab
436 
437  connect(page, TQT_SIGNAL(setWindowCaption (const TQString &)), frame, TQT_SLOT(setTitle (const TQString &)));
438  connectFrame(frame);
439  m_tabs->addFrame(frame);
440 
441  if(!background)
442  m_tabs->showPage(page->widget());
443  else
444  setFocus();
445 
446  page->openURL(url);
447 }
448 
449 
450 void View::setTabIcon(const TQPixmap& icon)
451 {
452  const PageViewer *s = dynamic_cast<const PageViewer*>(sender());
453  if (s) {
454  m_tabs->setTabIconSet(const_cast<PageViewer*>(s)->widget(), icon);
455  }
456 }
457 
458 void View::connectFrame(Frame *f)
459 {
460  connect(f, TQT_SIGNAL(statusText(const TQString &)), this, TQT_SLOT(slotStatusText(const TQString&)));
461  connect(f, TQT_SIGNAL(captionChanged (const TQString &)), this, TQT_SLOT(slotCaptionChanged (const TQString &)));
462  connect(f, TQT_SIGNAL(loadingProgress(int)), this, TQT_SLOT(slotLoadingProgress(int)) );
463  connect(f, TQT_SIGNAL(started()), this, TQT_SLOT(slotStarted()));
464  connect(f, TQT_SIGNAL(completed()), this, TQT_SLOT(slotCompleted()));
465  connect(f, TQT_SIGNAL(canceled(const TQString &)), this, TQT_SLOT(slotCanceled(const TQString&)));
466 }
467 
468 void View::slotStatusText(const TQString &c)
469 {
470  if (sender() == m_currentFrame)
471  emit setStatusBarText(c);
472 }
473 
474 void View::slotCaptionChanged(const TQString &c)
475 {
476  if (sender() == m_currentFrame)
477  emit setWindowCaption(c);
478 }
479 
480 void View::slotStarted()
481 {
482  if (sender() == m_currentFrame)
483  emit signalStarted(0);
484 }
485 
486 void View::slotCanceled(const TQString &s)
487 {
488  if (sender() == m_currentFrame)
489  emit signalCanceled(s);
490 }
491 
492 void View::slotCompleted()
493 {
494  if (sender() == m_currentFrame)
495  emit signalCompleted();
496 }
497 
498 void View::slotLoadingProgress(int percent)
499 {
500  if (sender() == m_currentFrame)
501  emit setProgress(percent);
502 }
503 
504 bool View::importFeeds(const TQDomDocument& doc)
505 {
506  FeedList* feedList = new FeedList();
507  bool parsed = feedList->readFromXML(doc);
508 
509  // FIXME: parsing error, print some message
510  if (!parsed)
511  {
512  delete feedList;
513  return false;
514  }
515  TQString title = feedList->title();
516 
517  if (title.isEmpty())
518  title = i18n("Imported Folder");
519 
520  bool ok;
521  title = KInputDialog::getText(i18n("Add Imported Folder"), i18n("Imported folder name:"), title, &ok);
522 
523  if (!ok)
524  {
525  delete feedList;
526  return false;
527  }
528 
529  Folder* fg = new Folder(title);
530  m_feedList->rootNode()->appendChild(fg);
531  m_feedList->append(feedList, fg);
532 
533  return true;
534 }
535 
536 bool View::loadFeeds(const TQDomDocument& doc, Folder* parent)
537 {
538  FeedList* feedList = new FeedList();
539  bool parsed = feedList->readFromXML(doc);
540 
541  // parsing went wrong
542  if (!parsed)
543  {
544  delete feedList;
545  return false;
546  }
547  m_feedListView->setUpdatesEnabled(false);
548  m_tagNodeListView->setUpdatesEnabled(false);
549  if (!parent)
550  {
551  TagSet* tagSet = Kernel::self()->tagSet();
552 
553  Kernel::self()->setFeedList(feedList);
554  ProgressManager::self()->setFeedList(feedList);
555  disconnectFromFeedList(m_feedList);
556  delete m_feedList;
557  delete m_tagNodeList;
558  m_feedList = feedList;
559  connectToFeedList(m_feedList);
560 
561  m_tagNodeList = new TagNodeList(m_feedList, tagSet);
562  m_feedListView->setNodeList(m_feedList);
563  m_tagNodeListView->setNodeList(m_tagNodeList);
564 
565  TQStringList tagIDs = m_feedList->rootNode()->tags();
566  TQStringList::ConstIterator end = tagIDs.end();
567  for (TQStringList::ConstIterator it = tagIDs.begin(); it != end; ++it)
568  {
569  kdDebug() << *it << endl;
570  // create a tag for every tag ID in the archive that is not part of the tagset
571  // this is a fallback in case the tagset was corrupted,
572  // so the tagging information from archive does not get lost.
573  if (!tagSet->containsID(*it))
574  {
575  Tag tag(*it, *it);
576  tagSet->insert(tag);
577  }
578  }
579  }
580  else
581  m_feedList->append(feedList, parent);
582 
583  m_feedListView->setUpdatesEnabled(true);
584  m_feedListView->triggerUpdate();
585  m_tagNodeListView->setUpdatesEnabled(true);
586  m_tagNodeListView->triggerUpdate();
587  return true;
588 }
589 
590 void View::slotDeleteExpiredArticles()
591 {
592  TreeNode* rootNode = m_feedList->rootNode();
593  if (rootNode)
594  rootNode->slotDeleteExpiredArticles();
595 }
596 
597 TQDomDocument View::feedListToOPML()
598 {
599  return m_feedList->toXML();
600 }
601 
602 void View::addFeedToGroup(const TQString& url, const TQString& groupName)
603 {
604 
605  // Locate the group.
606  TreeNode* node = m_feedListView->findNodeByTitle(groupName);
607 
608  Folder* group = 0;
609  if (!node || !node->isGroup())
610  {
611  Folder* g = new Folder( groupName );
612  m_feedList->rootNode()->appendChild(g);
613  group = g;
614  }
615  else
616  group = static_cast<Folder*>(node);
617 
618  // Invoke the Add Feed dialog with url filled in.
619  if (group)
620  addFeed(url, 0, group, true);
621 }
622 
624 {
625  if (m_viewMode == NormalView)
626  return;
627 
628  if (m_viewMode == CombinedView)
629  {
630  m_articleList->slotShowNode(m_listTabWidget->activeView()->selectedNode());
631  m_articleList->show();
632 
633  Article article = m_articleList->currentArticle();
634 
635  if (!article.isNull())
636  m_articleViewer->slotShowArticle(article);
637  else
638  m_articleViewer->slotShowSummary(m_listTabWidget->activeView()->selectedNode());
639  }
640 
641  m_articleSplitter->setOrientation(Qt::Vertical);
642  m_viewMode = NormalView;
643 
644  Settings::setViewMode( m_viewMode );
645 }
646 
648 {
649  if (m_viewMode == WidescreenView)
650  return;
651 
652  if (m_viewMode == CombinedView)
653  {
654  m_articleList->slotShowNode(m_listTabWidget->activeView()->selectedNode());
655  m_articleList->show();
656 
657  Article article = m_articleList->currentArticle();
658 
659  if (!article.isNull())
660  m_articleViewer->slotShowArticle(article);
661  else
662  m_articleViewer->slotShowSummary(m_listTabWidget->activeView()->selectedNode());
663  }
664 
665  m_articleSplitter->setOrientation(Qt::Horizontal);
666  m_viewMode = WidescreenView;
667 
668  Settings::setViewMode( m_viewMode );
669 }
670 
672 {
673  if (m_viewMode == CombinedView)
674  return;
675 
676  m_articleList->slotClear();
677  m_articleList->hide();
678  m_viewMode = CombinedView;
679 
680  slotNodeSelected(m_listTabWidget->activeView()->selectedNode());
681  Settings::setViewMode( m_viewMode );
682 }
683 
685 {
686  if (m_shuttingDown)
687  return;
688 
689  m_currentFrame=f;
690 
691  emit setWindowCaption(f->caption());
692  emit setProgress(f->progress());
693  emit setStatusBarText(f->statusText());
694 
695  if (f->part() == m_part)
696  m_part->mergePart(m_articleViewer);
697  else
698  m_part->mergePart(f->part());
699 
700  f->widget()->setFocus();
701 
702  switch (f->state())
703  {
704  case Frame::Started:
705  emit signalStarted(0);
706  break;
707  case Frame::Canceled:
708  emit signalCanceled(TQString());
709  break;
710  case Frame::Idle:
711  case Frame::Completed:
712  default:
713  emit signalCompleted();
714  }
715 }
716 
717 void View::slotFeedTreeContextMenu(KListView*, TreeNode* /*node*/, const TQPoint& /*p*/)
718 {
719  m_tabs->showPage(m_mainTab);
720 }
721 
722 void View::slotMoveCurrentNodeUp()
723 {
724  TreeNode* current = m_listTabWidget->activeView()->selectedNode();
725  if (!current)
726  return;
727  TreeNode* prev = current->prevSibling();
728  Folder* parent = current->parent();
729 
730  if (!prev || !parent)
731  return;
732 
733  parent->removeChild(prev);
734  parent->insertChild(prev, current);
735  m_listTabWidget->activeView()->ensureNodeVisible(current);
736 }
737 
738 void View::slotMoveCurrentNodeDown()
739 {
740  TreeNode* current = m_listTabWidget->activeView()->selectedNode();
741  if (!current)
742  return;
743  TreeNode* next = current->nextSibling();
744  Folder* parent = current->parent();
745 
746  if (!next || !parent)
747  return;
748 
749  parent->removeChild(current);
750  parent->insertChild(current, next);
751  m_listTabWidget->activeView()->ensureNodeVisible(current);
752 }
753 
754 void View::slotMoveCurrentNodeLeft()
755 {
756  TreeNode* current = m_listTabWidget->activeView()->selectedNode();
757  if (!current || !current->parent() || !current->parent()->parent())
758  return;
759 
760  Folder* parent = current->parent();
761  Folder* grandparent = current->parent()->parent();
762 
763  parent->removeChild(current);
764  grandparent->insertChild(current, parent);
765  m_listTabWidget->activeView()->ensureNodeVisible(current);
766 }
767 
768 void View::slotMoveCurrentNodeRight()
769 {
770  TreeNode* current = m_listTabWidget->activeView()->selectedNode();
771  if (!current || !current->parent())
772  return;
773  TreeNode* prev = current->prevSibling();
774 
775  if ( prev && prev->isGroup() )
776  {
777  Folder* fg = static_cast<Folder*>(prev);
778  current->parent()->removeChild(current);
779  fg->appendChild(current);
780  m_listTabWidget->activeView()->ensureNodeVisible(current);
781  }
782 }
783 
785 {
786  m_markReadTimer->stop();
787 
788  if (node)
789  {
790  kdDebug() << "node selected: " << node->title() << endl;
791  kdDebug() << "unread: " << node->unread() << endl;
792  kdDebug() << "total: " << node->totalCount() << endl;
793  }
794 
795  if (m_displayingAboutPage)
796  {
797  m_mainFrame->setTitle(i18n("Articles"));
798  if (m_viewMode != CombinedView)
799  m_articleList->show();
800  if (Settings::showQuickFilter())
801  m_searchBar->show();
802  m_displayingAboutPage = false;
803  }
804 
805  m_tabs->showPage(m_mainTab);
806 
807  if (Settings::resetQuickFilterOnNodeChange())
808  m_searchBar->slotClearSearch();
809 
810  if (m_viewMode == CombinedView)
811  m_articleViewer->slotShowNode(node);
812  else
813  {
814  m_articleList->slotShowNode(node);
815  m_articleViewer->slotShowSummary(node);
816  }
817 
818  if (node)
819  m_mainFrame->setCaption(node->title());
820 
821  m_actionManager->slotNodeSelected(node);
822 
823  updateTagActions();
824 }
825 
826 void View::slotOpenURL(const KURL& url, Viewer* currentViewer, BrowserRun::OpeningMode mode)
827 {
828  if (mode == BrowserRun::EXTERNAL)
829  Viewer::displayInExternalBrowser(url);
830  else
831  {
832  KParts::URLArgs args = currentViewer ? currentViewer->browserExtension()->urlArgs() : KParts::URLArgs();
833 
834  BrowserRun* r = new BrowserRun(this, currentViewer, url, args, mode);
835  connect(r, TQT_SIGNAL(signalOpenInViewer(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)),
836  this, TQT_SLOT(slotOpenURLReply(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)));
837  }
838 }
839 
840 //TODO: KDE4 remove this ugly ugly hack
841 void View::slotUrlClickedInViewer(const KURL& url, Viewer* viewer, bool newTab, bool background)
842 {
843 
844  if (!newTab)
845  {
846  slotOpenURL(url, viewer, BrowserRun::CURRENT_TAB);
847  }
848  else
849  {
850  slotOpenURL(url, 0L, background ? BrowserRun::NEW_TAB_BACKGROUND : BrowserRun::NEW_TAB_FOREGROUND);
851  }
852 }
853 
854 //TODO: KDE4 remove this ugly ugly hack
855 void View::slotOpenURLReply(const KURL& url, Viewer* currentViewer, BrowserRun::OpeningMode mode)
856 {
857  switch (mode)
858  {
859  case BrowserRun::CURRENT_TAB:
860  currentViewer->openURL(url);
861  break;
862  case BrowserRun::NEW_TAB_FOREGROUND:
863  case BrowserRun::NEW_TAB_BACKGROUND:
864  slotOpenNewTab(url, mode == BrowserRun::NEW_TAB_BACKGROUND);
865  break;
866  case BrowserRun::EXTERNAL:
867  Viewer::displayInExternalBrowser(url);
868  break;
869  }
870 }
871 
873 {
874  Folder* group = 0;
875  if (!m_feedListView->selectedNode())
876  group = m_feedList->rootNode(); // all feeds
877  else
878  {
879  //TODO: tag nodes need rework
880  if ( m_feedListView->selectedNode()->isGroup())
881  group = static_cast<Folder*>(m_feedListView->selectedNode());
882  else
883  group= m_feedListView->selectedNode()->parent();
884 
885  }
886 
887  TreeNode* lastChild = group->children().last();
888 
889  addFeed(TQString(), lastChild, group, false);
890 }
891 
892 void View::addFeed(const TQString& url, TreeNode *after, Folder* parent, bool autoExec)
893 {
894 
895  AddFeedDialog *afd = new AddFeedDialog( 0, "add_feed" );
896 
897  afd->setURL(KURL::decode_string(url));
898 
899  if (autoExec)
900  afd->slotOk();
901  else
902  {
903  if (afd->exec() != TQDialog::Accepted)
904  {
905  delete afd;
906  return;
907  }
908  }
909 
910  Feed* feed = afd->feed;
911  delete afd;
912 
913  FeedPropertiesDialog *dlg = new FeedPropertiesDialog( 0, "edit_feed" );
914  dlg->setFeed(feed);
915 
916  dlg->selectFeedName();
917 
918  if (!autoExec)
919  if (dlg->exec() != TQDialog::Accepted)
920  {
921  delete feed;
922  delete dlg;
923  return;
924  }
925 
926  if (!parent)
927  parent = m_feedList->rootNode();
928 
929  parent->insertChild(feed, after);
930 
931  m_feedListView->ensureNodeVisible(feed);
932 
933 
934  delete dlg;
935 }
936 
938 {
939  TreeNode* node = m_feedListView->selectedNode();
940  TreeNode* after = 0;
941 
942  if (!node)
943  node = m_feedListView->rootNode();
944 
945  // if a feed is selected, add group next to it
946  //TODO: tag nodes need rework
947  if (!node->isGroup())
948  {
949  after = node;
950  node = node->parent();
951  }
952 
953  Folder* currentGroup = static_cast<Folder*> (node);
954 
955  bool Ok;
956 
957  TQString text = KInputDialog::getText(i18n("Add Folder"), i18n("Folder name:"), "", &Ok);
958 
959  if (Ok)
960  {
961  Folder* newGroup = new Folder(text);
962  if (!after)
963  currentGroup->appendChild(newGroup);
964  else
965  currentGroup->insertChild(newGroup, after);
966 
967  m_feedListView->ensureNodeVisible(newGroup);
968  }
969 }
970 
972 {
973  TreeNode* selectedNode = m_listTabWidget->activeView()->selectedNode();
974 
975  // don't delete root element! (safety valve)
976  if (!selectedNode || selectedNode == m_feedList->rootNode())
977  return;
978 
979  m_deleteNodeVisitor->visit(selectedNode);
980 }
981 
983 {
984  TreeNode* node = m_listTabWidget->activeView()->selectedNode();
985  if (node)
986  m_editNodePropertiesVisitor->visit(node);
987 
988 }
989 
991 {
992  if (m_viewMode == CombinedView)
993  m_listTabWidget->activeView()->slotNextUnreadFeed();
994 
995  TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
996  if (sel && sel->unread() > 0)
997  m_articleList->slotNextUnreadArticle();
998  else
999  m_listTabWidget->activeView()->slotNextUnreadFeed();
1000 }
1001 
1003 {
1004  if (m_viewMode == CombinedView)
1005  m_listTabWidget->activeView()->slotPrevUnreadFeed();
1006 
1007  TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
1008  if (sel && sel->unread() > 0)
1009  m_articleList->slotPreviousUnreadArticle();
1010  else
1011  m_listTabWidget->activeView()->slotPrevUnreadFeed();
1012 }
1013 
1015 {
1016  m_feedList->rootNode()->slotMarkAllArticlesAsRead();
1017 }
1018 
1020 {
1021  if(!m_listTabWidget->activeView()->selectedNode()) return;
1022  m_listTabWidget->activeView()->selectedNode()->slotMarkAllArticlesAsRead();
1023 }
1024 
1026 {
1027  Feed* feed = dynamic_cast<Feed *>(m_listTabWidget->activeView()->selectedNode());
1028 
1029  if (!feed)
1030  return;
1031 
1032  KURL url = KURL(feed->htmlUrl())
1033 ;
1034  switch (Settings::lMBBehaviour())
1035  {
1036  case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
1037  slotOpenURL(url, 0, BrowserRun::EXTERNAL);
1038  break;
1039  case Settings::EnumLMBBehaviour::OpenInBackground:
1040  slotOpenURL(url, 0, BrowserRun::NEW_TAB_BACKGROUND);
1041  break;
1042  default:
1043  slotOpenURL(url, 0, BrowserRun::NEW_TAB_FOREGROUND);
1044  }
1045 }
1046 
1048 {
1049  emit signalUnreadCountChanged( m_feedList->rootNode()->unread() );
1050 }
1051 
1052 void View::slotDoIntervalFetches()
1053 {
1054  m_feedList->rootNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue(), true);
1055 }
1056 
1058 {
1059  if ( !m_listTabWidget->activeView()->selectedNode() )
1060  return;
1061  m_listTabWidget->activeView()->selectedNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
1062 }
1063 
1065 {
1066  m_feedList->rootNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
1067 }
1068 
1069 void View::slotFetchingStarted()
1070 {
1071  m_mainFrame->setState(Frame::Started);
1072  m_actionManager->action("feed_stop")->setEnabled(true);
1073  m_mainFrame->setStatusText(i18n("Fetching Feeds..."));
1074 }
1075 
1076 void View::slotFetchingStopped()
1077 {
1078  m_mainFrame->setState(Frame::Completed);
1079  m_actionManager->action("feed_stop")->setEnabled(false);
1080  m_mainFrame->setStatusText(TQString());
1081 }
1082 
1084 {
1085  // iterate through the articles (once again) to do notifications properly
1086  if (feed->articles().count() > 0)
1087  {
1088  TQValueList<Article> articles = feed->articles();
1089  TQValueList<Article>::ConstIterator it;
1090  TQValueList<Article>::ConstIterator end = articles.end();
1091  for (it = articles.begin(); it != end; ++it)
1092  {
1093  if ((*it).status()==Article::New && ((*it).feed()->useNotification() || Settings::useNotifications()))
1094  {
1096  }
1097  }
1098  }
1099 }
1100 
1101 void View::slotMouseButtonPressed(int button, const Article& article, const TQPoint &, int)
1102 {
1103  if (button == Qt::MidButton)
1104  {
1105  KURL link = article.link();
1106  switch (Settings::mMBBehaviour())
1107  {
1108  case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
1109  slotOpenURL(link, 0L, BrowserRun::EXTERNAL);
1110  break;
1111  case Settings::EnumMMBBehaviour::OpenInBackground:
1112  slotOpenURL(link, 0L, BrowserRun::NEW_TAB_BACKGROUND);
1113  break;
1114  default:
1115  slotOpenURL(link, 0L, BrowserRun::NEW_TAB_FOREGROUND);
1116  }
1117  }
1118 }
1119 
1120 void View::slotAssignTag(const Tag& tag, bool assign)
1121 {
1122  kdDebug() << (assign ? "assigned" : "removed") << " tag \"" << tag.id() << "\"" << endl;
1123  TQValueList<Article> selectedArticles = m_articleList->selectedArticles();
1124  for (TQValueList<Article>::Iterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
1125  {
1126  if (assign)
1127  (*it).addTag(tag.id());
1128  else
1129  (*it).removeTag(tag.id());
1130  }
1131  updateTagActions();
1132 }
1133 /*
1134 void View::slotRemoveTag(const Tag& tag)
1135 {
1136  kdDebug() << "remove tag \"" << tag.id() << "\" from selected articles" << endl;
1137  TQValueList<Article> selectedArticles = m_articleList->selectedArticles();
1138  for (TQValueList<Article>::Iterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
1139  (*it).removeTag(tag.id());
1140 
1141  updateTagActions();
1142 }
1143 */
1144 void View::slotNewTag()
1145 {
1146  Tag tag(KApplication::randomString(8), "New Tag");
1147  Kernel::self()->tagSet()->insert(tag);
1148  TagNode* node = m_tagNodeList->findByTagID(tag.id());
1149  if (node)
1150  m_tagNodeListView->startNodeRenaming(node);
1151 }
1152 
1153 void View::slotTagCreated(const Tag& tag)
1154 {
1155  if (m_tagNodeList && !m_tagNodeList->containsTagId(tag.id()))
1156  {
1157  TagNode* tagNode = new TagNode(tag, m_feedList->rootNode());
1158  m_tagNodeList->rootNode()->appendChild(tagNode);
1159  }
1160 }
1161 
1162 void View::slotTagRemoved(const Tag& /*tag*/)
1163 {
1164 }
1165 
1167 {
1168  if (m_viewMode == CombinedView)
1169  return;
1170 
1171  m_markReadTimer->stop();
1172 
1173  Feed *feed = article.feed();
1174  if (!feed)
1175  return;
1176 
1177  Article a(article);
1178  if (a.status() != Article::Read)
1179  {
1180  int delay;
1181 
1182  if ( Settings::useMarkReadDelay() )
1183  {
1184  delay = Settings::markReadDelay();
1185 
1186  if (delay > 0)
1187  m_markReadTimer->start( delay*1000, true );
1188  else
1189  a.setStatus(Article::Read);
1190  }
1191  }
1192 
1193  KToggleAction* maai = dynamic_cast<KToggleAction*>(m_actionManager->action("article_set_status_important"));
1194  maai->setChecked(a.keep());
1195 
1196  kdDebug() << "selected: " << a.guid() << endl;
1197 
1198  updateTagActions();
1199 
1200  m_articleViewer->slotShowArticle(a);
1201 }
1202 
1203 void View::slotOpenArticleExternal(const Article& article, const TQPoint&, int)
1204 {
1205  if (!article.isNull())
1206  Viewer::displayInExternalBrowser(article.link());
1207 }
1208 
1209 
1211 {
1212  Article article = m_articleList->currentArticle();
1213 
1214  if (article.isNull())
1215  return;
1216 
1217  KURL link;
1218  if (article.link().isValid())
1219  link = article.link();
1220  else if (article.guidIsPermaLink())
1221  link = KURL(article.guid());
1222 
1223  if (link.isValid())
1224  {
1225  slotOpenURL(link, 0L, BrowserRun::NEW_TAB_FOREGROUND);
1226  }
1227 }
1228 
1230 {
1231  slotOpenArticleExternal(m_articleList->currentArticle(), TQPoint(), 0);
1232 }
1233 
1235 {
1236  Article article = m_articleList->currentArticle();
1237 
1238  if (article.isNull())
1239  return;
1240 
1241  KURL link;
1242 
1243  if (article.link().isValid())
1244  link = article.link();
1245  else if (article.guidIsPermaLink())
1246  link = KURL(article.guid());
1247 
1248  if (link.isValid())
1249  {
1250  slotOpenURL(link, 0L, BrowserRun::NEW_TAB_BACKGROUND);
1251  }
1252 }
1253 
1255 {
1256  Article article = m_articleList->currentArticle();
1257 
1258  if(article.isNull())
1259  return;
1260 
1261  TQString link;
1262  if (article.link().isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
1263  {
1264  // in case link isn't valid, fall back to the guid permaLink.
1265  if (article.link().isValid())
1266  link = article.link().url();
1267  else
1268  link = article.guid();
1269  TQClipboard *cb = TQApplication::clipboard();
1270  cb->setText(link, TQClipboard::Clipboard);
1271  cb->setText(link, TQClipboard::Selection);
1272  }
1273 }
1274 
1275 void View::slotFeedURLDropped(KURL::List &urls, TreeNode* after, Folder* parent)
1276 {
1277  KURL::List::iterator it;
1278  for ( it = urls.begin(); it != urls.end(); ++it )
1279  {
1280  addFeed((*it).prettyURL(), after, parent, false);
1281  }
1282 }
1283 
1285 {
1286  if ( Settings::showQuickFilter() )
1287  {
1288  Settings::setShowQuickFilter(false);
1289  m_searchBar->slotClearSearch();
1290  m_searchBar->hide();
1291  }
1292  else
1293  {
1294  Settings::setShowQuickFilter(true);
1295  if (!m_displayingAboutPage)
1296  m_searchBar->show();
1297  }
1298 
1299 }
1300 
1302 {
1303 
1304  if ( m_viewMode == CombinedView )
1305  return;
1306 
1307  TQValueList<Article> articles = m_articleList->selectedArticles();
1308 
1309  TQString msg;
1310  switch (articles.count())
1311  {
1312  case 0:
1313  return;
1314  case 1:
1315  msg = i18n("<qt>Are you sure you want to delete article <b>%1</b>?</qt>").arg(TQStyleSheet::escape(articles.first().title()));
1316  break;
1317  default:
1318  msg = i18n("<qt>Are you sure you want to delete the selected article?</qt>",
1319  "<qt>Are you sure you want to delete the %n selected articles?</qt>",
1320  articles.count());
1321  }
1322 
1323  if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Article"), KStdGuiItem::del()) == KMessageBox::Continue)
1324  {
1325  if (m_listTabWidget->activeView()->selectedNode())
1326  m_listTabWidget->activeView()->selectedNode()->setNotificationMode(false);
1327 
1328  TQValueList<Feed*> feeds;
1329  for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1330  {
1331  Feed* feed = (*it).feed();
1332  if (!feeds.contains(feed))
1333  feeds.append(feed);
1334  feed->setNotificationMode(false);
1335  (*it).setDeleted();
1336  }
1337 
1338  for (TQValueList<Feed*>::Iterator it = feeds.begin(); it != feeds.end(); ++it)
1339  {
1340  (*it)->setNotificationMode(true);
1341  }
1342 
1343  if (m_listTabWidget->activeView()->selectedNode())
1344  m_listTabWidget->activeView()->selectedNode()->setNotificationMode(true);
1345  }
1346 }
1347 
1348 
1349 void View::slotArticleToggleKeepFlag(bool /*enabled*/)
1350 {
1351  TQValueList<Article> articles = m_articleList->selectedArticles();
1352 
1353  if (articles.isEmpty())
1354  return;
1355 
1356  bool allFlagsSet = true;
1357  for (TQValueList<Article>::Iterator it = articles.begin(); allFlagsSet && it != articles.end(); ++it)
1358  if (!(*it).keep())
1359  allFlagsSet = false;
1360 
1361  for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1362  (*it).setKeep(!allFlagsSet);
1363 }
1364 
1366 {
1367  TQValueList<Article> articles = m_articleList->selectedArticles();
1368 
1369  if (articles.isEmpty())
1370  return;
1371 
1372  for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1373  (*it).setStatus(Article::Read);
1374 }
1375 
1377 {
1378  if (m_currentFrame == m_mainFrame)
1379  {
1380  if (m_viewMode != CombinedView)
1381  {
1382  // in non-combined view, read selected articles
1383  SpeechClient::self()->slotSpeak(m_articleList->selectedArticles());
1384  // TODO: if article viewer has a selection, read only the selected text?
1385  }
1386  else
1387  {
1388  if (m_listTabWidget->activeView()->selectedNode())
1389  {
1390  //TODO: read articles in current node, respecting quick filter!
1391  }
1392  }
1393  }
1394  else
1395  {
1396  TQString selectedText = static_cast<PageViewer *>(m_currentFrame->part())->selectedText();
1397 
1398  if (!selectedText.isEmpty())
1399  SpeechClient::self()->slotSpeak(selectedText, "en");
1400  }
1401 }
1402 
1404 {
1405  TQValueList<Article> articles = m_articleList->selectedArticles();
1406 
1407  if (articles.isEmpty())
1408  return;
1409 
1410  for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1411  (*it).setStatus(Article::Unread);
1412 }
1413 
1415 {
1416  TQValueList<Article> articles = m_articleList->selectedArticles();
1417 
1418  if (articles.isEmpty())
1419  return;
1420 
1421  for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1422  (*it).setStatus(Article::New);
1423 }
1424 
1426 {
1427  Article article = m_articleList->currentArticle();
1428 
1429  if (article.isNull())
1430  return;
1431 
1432  article.setStatus(Article::Read);
1433 }
1434 
1435 void View::slotMouseOverInfo(const KFileItem *kifi)
1436 {
1437  if (kifi)
1438  {
1439  KFileItem *k=(KFileItem*)kifi;
1440  m_mainFrame->setStatusText(k->url().prettyURL());//geStatusBarInfo());
1441  }
1442  else
1443  {
1444  m_mainFrame->setStatusText(TQString());
1445  }
1446 }
1447 
1448 void View::readProperties(KConfig* config)
1449 {
1450 
1451  if (!Settings::resetQuickFilterOnNodeChange())
1452  {
1453  m_searchBar->slotSetText(config->readEntry("searchLine"));
1454  int statusfilter = config->readNumEntry("searchCombo", -1);
1455  if (statusfilter != -1)
1456  m_searchBar->slotSetStatus(statusfilter);
1457  }
1458 
1459  int selectedID = config->readNumEntry("selectedNodeID", -1);
1460  if (selectedID != -1)
1461  {
1462  TreeNode* selNode = m_feedList->findByID(selectedID);
1463  if (selNode)
1464  m_listTabWidget->activeView()->setSelectedNode(selNode);
1465  }
1466 
1467  TQStringList urls = config->readListEntry("FeedBrowserURLs");
1468  TQStringList::ConstIterator it = urls.begin();
1469  for (; it != urls.end(); ++it)
1470  {
1471  KURL url = KURL::fromPathOrURL(*it);
1472  if (url.isValid())
1473  slotOpenNewTab(url, true); // open in background
1474  }
1475 }
1476 
1477 void View::saveProperties(KConfig* config)
1478 {
1479  // save filter settings
1480  config->writeEntry("searchLine", m_searchBar->text());
1481  config->writeEntry("searchCombo", m_searchBar->status());
1482 
1483  TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
1484 
1485  if (sel)
1486  {
1487  config->writeEntry("selectedNodeID", sel->id() );
1488  }
1489 
1490  // save browser URLs
1491  TQStringList urls;
1492  TQPtrList<Frame> frames = m_tabs->frames();
1493  TQPtrList<Frame>::ConstIterator it = frames.begin();
1494  for (; it != frames.end(); ++it)
1495  {
1496  Frame *frame = *it;
1497  KParts::ReadOnlyPart *part = frame->part();
1498  PageViewer *pageViewer = dynamic_cast<PageViewer*>(part); // don't save the ArticleViewer
1499  if (pageViewer)
1500  {
1501  KURL url = pageViewer->url();
1502  if (url.isValid())
1503  urls.append(url.prettyURL());
1504  }
1505  }
1506 
1507  config->writeEntry("FeedBrowserURLs", urls);
1508 }
1509 
1510 void View::connectToFeedList(FeedList* feedList)
1511 {
1512  connect(feedList->rootNode(), TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotSetTotalUnread()));
1514 }
1515 
1516 void View::disconnectFromFeedList(FeedList* feedList)
1517 {
1518  disconnect(feedList->rootNode(), TQT_SIGNAL(signalChanged(TreeNode*)), this, TQT_SLOT(slotSetTotalUnread()));
1519 }
1520 
1521 void View::updateTagActions()
1522 {
1523  TQStringList tags;
1524 
1525  TQValueList<Article> selectedArticles = m_articleList->selectedArticles();
1526 
1527  for (TQValueList<Article>::ConstIterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
1528  {
1529  TQStringList atags = (*it).tags();
1530  for (TQStringList::ConstIterator it2 = atags.begin(); it2 != atags.end(); ++it2)
1531  {
1532  if (!tags.contains(*it2))
1533  tags += *it2;
1534  }
1535  }
1536  m_actionManager->slotUpdateTagActions(!selectedArticles.isEmpty(), tags);
1537 }
1538 
1539 } // namespace Akregator
1540 
1541 #include "akregator_view.moc"