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 <tdeaction.h>
62#include <tdeapplication.h>
63#include <kcharsets.h>
64#include <kcombobox.h>
65#include <tdeconfig.h>
66#include <kdebug.h>
67#include <kdialog.h>
68#include <tdefiledialog.h>
69#include <tdefileitem.h>
70#include <tdehtml_part.h>
71#include <tdehtmlview.h>
72#include <kiconloader.h>
73#include <kinputdialog.h>
74#include <klineedit.h>
75#include <tdelistview.h>
76#include <tdelocale.h>
77#include <tdemessagebox.h>
78#include <kpassdlg.h>
79#include <tdeprocess.h>
80#include <krun.h>
81#include <kshell.h>
82#include <tdestandarddirs.h>
83#include <kurl.h>
84#include <kxmlguifactory.h>
85#include <tdeparts/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
106namespace Akregator {
107
108class View::EditNodePropertiesVisitor : public TreeNodeVisitor
109{
110 public:
111 EditNodePropertiesVisitor(View* view) : m_view(view) {}
112 virtual ~EditNodePropertiesVisitor() {}
113
114 virtual bool visitTagNode(TagNode* node)
115 {
116 TagPropertiesDialog* dlg = new TagPropertiesDialog(m_view);
117 dlg->setTag(node->tag());
118 dlg->exec();
119 delete dlg;
120 return true;
121 }
122
123 virtual bool visitFolder(Folder* node)
124 {
125 m_view->m_listTabWidget->activeView()->startNodeRenaming(node);
126 return true;
127 }
128
129 virtual bool visitFeed(Feed* node)
130 {
131 FeedPropertiesDialog *dlg = new FeedPropertiesDialog( m_view, "edit_feed" );
132 dlg->setFeed(node);
133 dlg->exec();
134 delete dlg;
135 return true;
136 }
137 private:
138
139 View* m_view;
140};
141
142class View::DeleteNodeVisitor : public TreeNodeVisitor
143{
144 public:
145 DeleteNodeVisitor(View* view) : m_view(view) {}
146 virtual ~DeleteNodeVisitor() {}
147
148 virtual bool visitTagNode(TagNode* node)
149 {
150 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());
151 if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Tag"), KStdGuiItem::del()) == KMessageBox::Continue)
152 {
153 Tag tag = node->tag();
154 TQValueList<Article> articles = m_view->m_feedList->rootNode()->articles(tag.id());
155 node->setNotificationMode(false);
156 for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
157 (*it).removeTag(tag.id());
158 node->setNotificationMode(true);
159 Kernel::self()->tagSet()->remove(tag);
160 m_view->m_listTabWidget->activeView()->setFocus();
161 }
162 return true;
163 }
164
165 virtual bool visitFolder(Folder* node)
166 {
167 TQString msg;
168 if (node->title().isEmpty())
169 msg = i18n("<qt>Are you sure you want to delete this folder and its feeds and subfolders?</qt>");
170 else
171 msg = i18n("<qt>Are you sure you want to delete folder <b>%1</b> and its feeds and subfolders?</qt>").arg(node->title());
172
173 if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Folder"), KStdGuiItem::del()) == KMessageBox::Continue)
174 {
175 delete node;
176 m_view->m_listTabWidget->activeView()->setFocus();
177 }
178 return true;
179 }
180
181 virtual bool visitFeed(Feed* node)
182 {
183 TQString msg;
184 if (node->title().isEmpty())
185 msg = i18n("<qt>Are you sure you want to delete this feed?</qt>");
186 else
187 msg = i18n("<qt>Are you sure you want to delete feed <b>%1</b>?</qt>").arg(node->title());
188
189 if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Feed"), KStdGuiItem::del()) == KMessageBox::Continue)
190 {
191 delete node;
192 m_view->m_listTabWidget->activeView()->setFocus();
193 }
194 return true;
195 }
196 private:
197
198 View* m_view;
199};
200
201
203{
204 // if m_shuttingDown is false, slotOnShutdown was not called. That
205 // means that not the whole app is shutdown, only the part. So it
206 // should be no risk to do the cleanups now
207 if (!m_shuttingDown)
208 {
209 kdDebug() << "View::~View(): slotOnShutdown() wasn't called. Calling it now." << endl;
210 slotOnShutdown();
211 }
212 kdDebug() << "View::~View(): leaving" << endl;
213}
214
215View::View( Part *part, TQWidget *parent, ActionManagerImpl* actionManager, const char *name)
216 : TQWidget(parent, name), m_viewMode(NormalView), m_actionManager(actionManager)
217{
218 m_editNodePropertiesVisitor = new EditNodePropertiesVisitor(this);
219 m_deleteNodeVisitor = new DeleteNodeVisitor(this);
220 m_keepFlagIcon = TQPixmap(locate("data", "akregator/pics/akregator_flag.png"));
221 m_part = part;
222 m_feedList = new FeedList();
223 m_tagNodeList = new TagNodeList(m_feedList, Kernel::self()->tagSet());
224 m_shuttingDown = false;
225 m_displayingAboutPage = false;
226 m_currentFrame = 0L;
227 setFocusPolicy(TQWidget::StrongFocus);
228
229 TQVBoxLayout *lt = new TQVBoxLayout( this );
230
231 m_horizontalSplitter = new TQSplitter(TQt::Horizontal, this);
232
233 m_horizontalSplitter->setOpaqueResize(true);
234 lt->addWidget(m_horizontalSplitter);
235
236 connect (Kernel::self()->fetchQueue(), TQ_SIGNAL(fetched(Feed*)), this, TQ_SLOT(slotFeedFetched(Feed*)));
237 connect (Kernel::self()->fetchQueue(), TQ_SIGNAL(signalStarted()), this, TQ_SLOT(slotFetchingStarted()));
238 connect (Kernel::self()->fetchQueue(), TQ_SIGNAL(signalStopped()), this, TQ_SLOT(slotFetchingStopped()));
239
240 connect(Kernel::self()->tagSet(), TQ_SIGNAL(signalTagAdded(const Tag&)), this, TQ_SLOT(slotTagCreated(const Tag&)));
241 connect(Kernel::self()->tagSet(), TQ_SIGNAL(signalTagRemoved(const Tag&)), this, TQ_SLOT(slotTagRemoved(const Tag&)));
242
243 m_listTabWidget = new ListTabWidget(m_horizontalSplitter);
244 m_actionManager->initListTabWidget(m_listTabWidget);
245
246 connect(m_listTabWidget, TQ_SIGNAL(signalNodeSelected(TreeNode*)), this, TQ_SLOT(slotNodeSelected(TreeNode*)));
247
248 if (!Settings::showTaggingGUI())
249 m_listTabWidget->setViewMode(ListTabWidget::single);
250
251 m_feedListView = new NodeListView( this, "feedtree" );
252 m_listTabWidget->addView(m_feedListView, i18n("Feeds"), TDEGlobal::iconLoader()->loadIcon("folder", TDEIcon::Small));
253
254 connect(m_feedListView, TQ_SIGNAL(signalContextMenu(TDEListView*, TreeNode*, const TQPoint&)), this, TQ_SLOT(slotFeedTreeContextMenu(TDEListView*, TreeNode*, const TQPoint&)));
255
256 connect(m_feedListView, TQ_SIGNAL(signalDropped (KURL::List &, TreeNode*,
257 Folder*)), this, TQ_SLOT(slotFeedURLDropped (KURL::List &,
258 TreeNode*, Folder*)));
259
260 m_tagNodeListView = new NodeListView(this);
261 m_listTabWidget->addView(m_tagNodeListView, i18n("Tags"), TDEGlobal::iconLoader()->loadIcon("rss_tag", TDEIcon::Small));
262
263 connect(m_tagNodeListView, TQ_SIGNAL(signalContextMenu(TDEListView*, TreeNode*, const TQPoint&)), this, TQ_SLOT(slotFeedTreeContextMenu(TDEListView*, TreeNode*, const TQPoint&)));
264
265
266 ProgressManager::self()->setFeedList(m_feedList);
267
268 m_tabs = new TabWidget(m_horizontalSplitter);
269 m_actionManager->initTabWidget(m_tabs);
270
271 connect( m_part, TQ_SIGNAL(signalSettingsChanged()), m_tabs, TQ_SLOT(slotSettingsChanged()));
272
273 connect( m_tabs, TQ_SIGNAL( currentFrameChanged(Frame *) ), this,
274 TQ_SLOT( slotFrameChanged(Frame *) ) );
275
276 TQWhatsThis::add(m_tabs, i18n("You can view multiple articles in several open tabs."));
277
278 m_mainTab = new TQWidget(this, "Article Tab");
279 TQVBoxLayout *mainTabLayout = new TQVBoxLayout( m_mainTab, 0, 2, "mainTabLayout");
280
281 TQWhatsThis::add(m_mainTab, i18n("Articles list."));
282
283 m_searchBar = new SearchBar(m_mainTab);
284
285 if ( !Settings::showQuickFilter() )
286 m_searchBar->hide();
287
288 mainTabLayout->addWidget(m_searchBar);
289
290 m_articleSplitter = new TQSplitter(TQt::Vertical, m_mainTab, "panner2");
291
292 m_articleList = new ArticleListView( m_articleSplitter, "articles" );
293 m_actionManager->initArticleListView(m_articleList);
294
295 connect( m_articleList, TQ_SIGNAL(signalMouseButtonPressed(int, const Article&, const TQPoint &, int)), this, TQ_SLOT(slotMouseButtonPressed(int, const Article&, const TQPoint &, int)));
296
297 // use selectionChanged instead of clicked
298 connect( m_articleList, TQ_SIGNAL(signalArticleChosen(const Article&)),
299 this, TQ_SLOT( slotArticleSelected(const Article&)) );
300 connect( m_articleList, TQ_SIGNAL(signalDoubleClicked(const Article&, const TQPoint&, int)),
301 this, TQ_SLOT( slotOpenArticleExternal(const Article&, const TQPoint&, int)) );
302
303 m_articleViewer = new ArticleViewer(m_articleSplitter, "article_viewer");
304 m_articleViewer->setSafeMode(); // disable JS, Java, etc...
305
306 m_actionManager->initArticleViewer(m_articleViewer);
307
308 connect(m_searchBar, TQ_SIGNAL(signalSearch(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)), m_articleList, TQ_SLOT(slotSetFilter(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)));
309
310 connect(m_searchBar, TQ_SIGNAL(signalSearch(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)), m_articleViewer, TQ_SLOT(slotSetFilter(const Akregator::Filters::ArticleMatcher&, const Akregator::Filters::ArticleMatcher&)));
311
312 connect( m_articleViewer, TQ_SIGNAL(urlClicked(const KURL&, Viewer*, bool, bool)),
313 this, TQ_SLOT(slotUrlClickedInViewer(const KURL&, Viewer*, bool, bool)) );
314
315 connect( m_articleViewer->browserExtension(), TQ_SIGNAL(mouseOverInfo(const KFileItem *)),
316 this, TQ_SLOT(slotMouseOverInfo(const KFileItem *)) );
317
318 connect( m_part, TQ_SIGNAL(signalSettingsChanged()), m_articleViewer, TQ_SLOT(slotPaletteOrFontChanged()));
319 TQWhatsThis::add(m_articleViewer->widget(), i18n("Browsing area."));
320 mainTabLayout->addWidget( m_articleSplitter );
321
322 m_mainFrame=new Frame(this, m_part, m_mainTab, i18n("Articles"), false);
323 connectFrame(m_mainFrame);
324 m_tabs->addFrame(m_mainFrame);
325
326 const TQValueList<int> sp1sizes = Settings::splitter1Sizes();
327 if ( sp1sizes.count() >= m_horizontalSplitter->sizes().count() )
328 m_horizontalSplitter->setSizes( sp1sizes );
329 const TQValueList<int> sp2sizes = Settings::splitter2Sizes();
330 if ( sp2sizes.count() >= m_articleSplitter->sizes().count() )
331 m_articleSplitter->setSizes( sp2sizes );
332
333 TDEConfig *conf = Settings::self()->config();
334 conf->setGroup("General");
335 if(!conf->readBoolEntry("Disable Introduction", false))
336 {
337 m_articleList->hide();
338 m_searchBar->hide();
339 m_articleViewer->displayAboutPage();
340 m_mainFrame->setTitle(i18n("About"));
341 m_displayingAboutPage = true;
342 }
343
344 m_fetchTimer = new TQTimer(this);
345 connect( m_fetchTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotDoIntervalFetches()) );
346 m_fetchTimer->start(1000*60);
347
348 // delete expired articles once per hour
349 m_expiryTimer = new TQTimer(this);
350 connect(m_expiryTimer, TQ_SIGNAL(timeout()), this,
351 TQ_SLOT(slotDeleteExpiredArticles()) );
352 m_expiryTimer->start(3600*1000);
353
354 m_markReadTimer = new TQTimer(this);
355 connect(m_markReadTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotSetCurrentArticleReadDelayed()) );
356
357 switch (Settings::viewMode())
358 {
359 case CombinedView:
361 break;
362 case WidescreenView:
364 break;
365 default:
367 }
368
369 if (!Settings::resetQuickFilterOnNodeChange())
370 {
371 m_searchBar->slotSetStatus(Settings::statusFilter());
372 m_searchBar->slotSetText(Settings::textFilter());
373 }
374
375 TQTimer::singleShot(1000, this, TQ_SLOT(slotDeleteExpiredArticles()) );
376 m_part->mergePart(m_articleViewer);
377}
378
379void View::slotSettingsChanged()
380{
381 // if tagging is hidden, show only feed list
382 m_listTabWidget->setViewMode(Settings::showTaggingGUI() ? ListTabWidget::verticalTabs : ListTabWidget::single);
383
384 // In case text colors changed, repaint to apply changes immediately
385 if (m_articleList->isShown()) {
386 m_articleList->repaintContents();
387 }
388 if (m_feedListView->isShown()) {
389 m_feedListView->repaintContents();
390 }
391}
392
393void View::slotOnShutdown()
394{
395 m_shuttingDown = true; // prevents slotFrameChanged from crashing
396
397 m_articleList->slotShowNode(0);
398 m_articleViewer->slotShowNode(0);
399
400 Kernel::self()->fetchQueue()->slotAbort();
401
402 m_feedListView->setNodeList(0);
403 ProgressManager::self()->setFeedList(0);
404
405 delete m_feedList;
406 delete m_tagNodeList;
407
408 // close all pageviewers in a controlled way
409 // fixes bug 91660, at least when no part loading data
410 m_tabs->setCurrentPage(m_tabs->count()-1); // select last page
411 while (m_tabs->count() > 1) // remove frames until only the main frame remains
412 m_tabs->slotRemoveCurrentFrame();
413
414 delete m_mainTab;
415 delete m_mainFrame;
416 delete m_editNodePropertiesVisitor;
417 delete m_deleteNodeVisitor;
418}
419
421{
422 const TQValueList<int> spl1 = m_horizontalSplitter->sizes();
423 if ( spl1.contains( 0 ) == 0 )
424 Settings::setSplitter1Sizes( spl1 );
425 const TQValueList<int> spl2 = m_articleSplitter->sizes();
426 if ( spl2.contains( 0 ) == 0 )
427 Settings::setSplitter2Sizes( spl2 );
428 Settings::setViewMode( m_viewMode );
429 Settings::writeConfig();
430}
431
432void View::slotOpenNewTab(const KURL& url, bool background)
433{
434 PageViewer* page = new PageViewer(this, "page");
435
436 connect( m_part, TQ_SIGNAL(signalSettingsChanged()), page, TQ_SLOT(slotPaletteOrFontChanged()));
437
438 connect( page, TQ_SIGNAL(setTabIcon(const TQPixmap&)),
439 this, TQ_SLOT(setTabIcon(const TQPixmap&)));
440 connect( page, TQ_SIGNAL(urlClicked(const KURL &, Viewer*, bool, bool)),
441 this, TQ_SLOT(slotUrlClickedInViewer(const KURL &, Viewer*, bool, bool)) );
442
443 Frame* frame = new Frame(this, page, page->widget(), i18n("Untitled"));
444 frame->setAutoDeletePart(true); // delete page viewer when removing the tab
445
446 connect(page, TQ_SIGNAL(setWindowCaption (const TQString &)), frame, TQ_SLOT(setTitle (const TQString &)));
447 connectFrame(frame);
448 m_tabs->addFrame(frame);
449
450 if(!background)
451 m_tabs->showPage(page->widget());
452 else
453 setFocus();
454
455 page->openURL(url);
456}
457
458
459void View::setTabIcon(const TQPixmap& icon)
460{
461 const PageViewer *s = dynamic_cast<const PageViewer*>(sender());
462 if (s) {
463 m_tabs->setTabIconSet(const_cast<PageViewer*>(s)->widget(), icon);
464 }
465}
466
467void View::connectFrame(Frame *f)
468{
469 connect(f, TQ_SIGNAL(statusText(const TQString &)), this, TQ_SLOT(slotStatusText(const TQString&)));
470 connect(f, TQ_SIGNAL(captionChanged (const TQString &)), this, TQ_SLOT(slotCaptionChanged (const TQString &)));
471 connect(f, TQ_SIGNAL(loadingProgress(int)), this, TQ_SLOT(slotLoadingProgress(int)) );
472 connect(f, TQ_SIGNAL(started()), this, TQ_SLOT(slotStarted()));
473 connect(f, TQ_SIGNAL(completed()), this, TQ_SLOT(slotCompleted()));
474 connect(f, TQ_SIGNAL(canceled(const TQString &)), this, TQ_SLOT(slotCanceled(const TQString&)));
475}
476
477void View::slotStatusText(const TQString &c)
478{
479 if (sender() == m_currentFrame)
480 emit setStatusBarText(c);
481}
482
483void View::slotCaptionChanged(const TQString &c)
484{
485 if (sender() == m_currentFrame)
486 emit setWindowCaption(c);
487}
488
489void View::slotStarted()
490{
491 if (sender() == m_currentFrame)
492 emit signalStarted(0);
493}
494
495void View::slotCanceled(const TQString &s)
496{
497 if (sender() == m_currentFrame)
498 emit signalCanceled(s);
499}
500
501void View::slotCompleted()
502{
503 if (sender() == m_currentFrame)
504 emit signalCompleted();
505}
506
507void View::slotLoadingProgress(int percent)
508{
509 if (sender() == m_currentFrame)
510 emit setProgress(percent);
511}
512
513bool View::importFeeds(const TQDomDocument& doc)
514{
515 FeedList* feedList = new FeedList();
516 bool parsed = feedList->readFromXML(doc);
517
518 // FIXME: parsing error, print some message
519 if (!parsed)
520 {
521 delete feedList;
522 return false;
523 }
524 TQString title = feedList->title();
525
526 if (title.isEmpty())
527 title = i18n("Imported Folder");
528
529 bool ok;
530 title = KInputDialog::getText(i18n("Add Imported Folder"), i18n("Imported folder name:"), title, &ok);
531
532 if (!ok)
533 {
534 delete feedList;
535 return false;
536 }
537
538 Folder* fg = new Folder(title);
539 m_feedList->rootNode()->appendChild(fg);
540 m_feedList->append(feedList, fg);
541
542 return true;
543}
544
545bool View::loadFeeds(const TQDomDocument& doc, Folder* parent)
546{
547 FeedList* feedList = new FeedList();
548 bool parsed = feedList->readFromXML(doc);
549
550 // parsing went wrong
551 if (!parsed)
552 {
553 delete feedList;
554 return false;
555 }
556 m_feedListView->setUpdatesEnabled(false);
557 m_tagNodeListView->setUpdatesEnabled(false);
558 if (!parent)
559 {
560 TagSet* tagSet = Kernel::self()->tagSet();
561
562 Kernel::self()->setFeedList(feedList);
563 ProgressManager::self()->setFeedList(feedList);
564 disconnectFromFeedList(m_feedList);
565 delete m_feedList;
566 delete m_tagNodeList;
567 m_feedList = feedList;
568 connectToFeedList(m_feedList);
569
570 m_tagNodeList = new TagNodeList(m_feedList, tagSet);
571 m_feedListView->setNodeList(m_feedList);
572 m_tagNodeListView->setNodeList(m_tagNodeList);
573
574 TQStringList tagIDs = m_feedList->rootNode()->tags();
575 TQStringList::ConstIterator end = tagIDs.end();
576 for (TQStringList::ConstIterator it = tagIDs.begin(); it != end; ++it)
577 {
578 kdDebug() << *it << endl;
579 // create a tag for every tag ID in the archive that is not part of the tagset
580 // this is a fallback in case the tagset was corrupted,
581 // so the tagging information from archive does not get lost.
582 if (!tagSet->containsID(*it))
583 {
584 Tag tag(*it, *it);
585 tagSet->insert(tag);
586 }
587 }
588 }
589 else
590 m_feedList->append(feedList, parent);
591
592 m_feedListView->setUpdatesEnabled(true);
593 m_feedListView->triggerUpdate();
594 m_tagNodeListView->setUpdatesEnabled(true);
595 m_tagNodeListView->triggerUpdate();
596 return true;
597}
598
599void View::slotDeleteExpiredArticles()
600{
601 TreeNode* rootNode = m_feedList->rootNode();
602 if (rootNode)
603 rootNode->slotDeleteExpiredArticles();
604}
605
606TQDomDocument View::feedListToOPML()
607{
608 return m_feedList->toXML();
609}
610
611void View::addFeedToGroup(const TQString& url, const TQString& groupName)
612{
613
614 // Locate the group.
615 TreeNode* node = m_feedListView->findNodeByTitle(groupName);
616
617 Folder* group = 0;
618 if (!node || !node->isGroup())
619 {
620 Folder* g = new Folder( groupName );
621 m_feedList->rootNode()->appendChild(g);
622 group = g;
623 }
624 else
625 group = static_cast<Folder*>(node);
626
627 // Invoke the Add Feed dialog with url filled in.
628 if (group)
629 addFeed(url, 0, group, true);
630}
631
633{
634 if (m_viewMode == NormalView)
635 return;
636
637 if (m_viewMode == CombinedView)
638 {
639 m_articleList->slotShowNode(m_listTabWidget->activeView()->selectedNode());
640 m_articleList->show();
641
642 Article article = m_articleList->currentArticle();
643
644 if (!article.isNull())
645 m_articleViewer->slotShowArticle(article);
646 else
647 m_articleViewer->slotShowSummary(m_listTabWidget->activeView()->selectedNode());
648 }
649
650 m_articleSplitter->setOrientation(TQt::Vertical);
651 m_viewMode = NormalView;
652
653 Settings::setViewMode( m_viewMode );
654}
655
657{
658 if (m_viewMode == WidescreenView)
659 return;
660
661 if (m_viewMode == CombinedView)
662 {
663 m_articleList->slotShowNode(m_listTabWidget->activeView()->selectedNode());
664 m_articleList->show();
665
666 Article article = m_articleList->currentArticle();
667
668 if (!article.isNull())
669 m_articleViewer->slotShowArticle(article);
670 else
671 m_articleViewer->slotShowSummary(m_listTabWidget->activeView()->selectedNode());
672 }
673
674 m_articleSplitter->setOrientation(TQt::Horizontal);
675 m_viewMode = WidescreenView;
676
677 Settings::setViewMode( m_viewMode );
678}
679
681{
682 if (m_viewMode == CombinedView)
683 return;
684
685 m_articleList->slotClear();
686 m_articleList->hide();
687 m_viewMode = CombinedView;
688
689 slotNodeSelected(m_listTabWidget->activeView()->selectedNode());
690 Settings::setViewMode( m_viewMode );
691}
692
694{
695 if (m_shuttingDown)
696 return;
697
698 m_currentFrame=f;
699
700 emit setWindowCaption(f->caption());
701 emit setProgress(f->progress());
702 emit setStatusBarText(f->statusText());
703
704 if (f->part() == m_part)
705 m_part->mergePart(m_articleViewer);
706 else
707 m_part->mergePart(f->part());
708
709 f->widget()->setFocus();
710
711 switch (f->state())
712 {
713 case Frame::Started:
714 emit signalStarted(0);
715 break;
716 case Frame::Canceled:
717 emit signalCanceled(TQString());
718 break;
719 case Frame::Idle:
720 case Frame::Completed:
721 default:
722 emit signalCompleted();
723 }
724}
725
726void View::slotFeedTreeContextMenu(TDEListView*, TreeNode* /*node*/, const TQPoint& /*p*/)
727{
728 m_tabs->showPage(m_mainTab);
729}
730
731void View::slotMoveCurrentNodeUp()
732{
733 TreeNode* current = m_listTabWidget->activeView()->selectedNode();
734 if (!current)
735 return;
736 TreeNode* prev = current->prevSibling();
737 Folder* parent = current->parent();
738
739 if (!prev || !parent)
740 return;
741
742 parent->removeChild(prev);
743 parent->insertChild(prev, current);
744 m_listTabWidget->activeView()->ensureNodeVisible(current);
745}
746
747void View::slotMoveCurrentNodeDown()
748{
749 TreeNode* current = m_listTabWidget->activeView()->selectedNode();
750 if (!current)
751 return;
752 TreeNode* next = current->nextSibling();
753 Folder* parent = current->parent();
754
755 if (!next || !parent)
756 return;
757
758 parent->removeChild(current);
759 parent->insertChild(current, next);
760 m_listTabWidget->activeView()->ensureNodeVisible(current);
761}
762
763void View::slotMoveCurrentNodeLeft()
764{
765 TreeNode* current = m_listTabWidget->activeView()->selectedNode();
766 if (!current || !current->parent() || !current->parent()->parent())
767 return;
768
769 Folder* parent = current->parent();
770 Folder* grandparent = current->parent()->parent();
771
772 parent->removeChild(current);
773 grandparent->insertChild(current, parent);
774 m_listTabWidget->activeView()->ensureNodeVisible(current);
775}
776
777void View::slotMoveCurrentNodeRight()
778{
779 TreeNode* current = m_listTabWidget->activeView()->selectedNode();
780 if (!current || !current->parent())
781 return;
782 TreeNode* prev = current->prevSibling();
783
784 if ( prev && prev->isGroup() )
785 {
786 Folder* fg = static_cast<Folder*>(prev);
787 current->parent()->removeChild(current);
788 fg->appendChild(current);
789 m_listTabWidget->activeView()->ensureNodeVisible(current);
790 }
791}
792
794{
795 m_markReadTimer->stop();
796
797 if (node)
798 {
799 kdDebug() << "node selected: " << node->title() << endl;
800 kdDebug() << "unread: " << node->unread() << endl;
801 kdDebug() << "total: " << node->totalCount() << endl;
802 }
803
804 if (m_displayingAboutPage)
805 {
806 m_mainFrame->setTitle(i18n("Articles"));
807 if (m_viewMode != CombinedView)
808 m_articleList->show();
809 if (Settings::showQuickFilter())
810 m_searchBar->show();
811 m_displayingAboutPage = false;
812 }
813
814 m_tabs->showPage(m_mainTab);
815
816 if (Settings::resetQuickFilterOnNodeChange())
817 m_searchBar->slotClearSearch();
818
819 if (m_viewMode == CombinedView)
820 m_articleViewer->slotShowNode(node);
821 else
822 {
823 m_articleList->slotShowNode(node);
824 m_articleViewer->slotShowSummary(node);
825 }
826
827 if (node)
828 m_mainFrame->setCaption(node->title());
829
830 m_actionManager->slotNodeSelected(node);
831
832 updateTagActions();
833}
834
835void View::slotOpenURL(const KURL& url, Viewer* currentViewer, BrowserRun::OpeningMode mode)
836{
837 if (mode == BrowserRun::EXTERNAL)
838 Viewer::displayInExternalBrowser(url);
839 else
840 {
841 KParts::URLArgs args = currentViewer ? currentViewer->browserExtension()->urlArgs() : KParts::URLArgs();
842
843 BrowserRun* r = new BrowserRun(this, currentViewer, url, args, mode);
844 connect(r, TQ_SIGNAL(signalOpenInViewer(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)),
845 this, TQ_SLOT(slotOpenURLReply(const KURL&, Akregator::Viewer*, Akregator::BrowserRun::OpeningMode)));
846 }
847}
848
849//TODO: KDE4 remove this ugly ugly hack
850void View::slotUrlClickedInViewer(const KURL& url, Viewer* viewer, bool newTab, bool background)
851{
852
853 if (!newTab)
854 {
855 slotOpenURL(url, viewer, BrowserRun::CURRENT_TAB);
856 }
857 else
858 {
859 slotOpenURL(url, 0L, background ? BrowserRun::NEW_TAB_BACKGROUND : BrowserRun::NEW_TAB_FOREGROUND);
860 }
861}
862
863//TODO: KDE4 remove this ugly ugly hack
864void View::slotOpenURLReply(const KURL& url, Viewer* currentViewer, BrowserRun::OpeningMode mode)
865{
866 switch (mode)
867 {
868 case BrowserRun::CURRENT_TAB:
869 currentViewer->openURL(url);
870 break;
871 case BrowserRun::NEW_TAB_FOREGROUND:
872 case BrowserRun::NEW_TAB_BACKGROUND:
873 slotOpenNewTab(url, mode == BrowserRun::NEW_TAB_BACKGROUND);
874 break;
875 case BrowserRun::EXTERNAL:
876 Viewer::displayInExternalBrowser(url);
877 break;
878 }
879}
880
882{
883 Folder* group = 0;
884 if (!m_feedListView->selectedNode())
885 group = m_feedList->rootNode(); // all feeds
886 else
887 {
888 //TODO: tag nodes need rework
889 if ( m_feedListView->selectedNode()->isGroup())
890 group = static_cast<Folder*>(m_feedListView->selectedNode());
891 else
892 group= m_feedListView->selectedNode()->parent();
893
894 }
895
896 TreeNode* lastChild = group->children().last();
897
898 addFeed(TQString(), lastChild, group, false);
899}
900
901void View::addFeed(const TQString& url, TreeNode *after, Folder* parent, bool autoExec)
902{
903
904 AddFeedDialog *afd = new AddFeedDialog( 0, "add_feed" );
905
906 afd->setURL(KURL::decode_string(url));
907
908 if (autoExec)
909 afd->slotOk();
910 else
911 {
912 if (afd->exec() != TQDialog::Accepted)
913 {
914 delete afd;
915 return;
916 }
917 }
918
919 Feed* feed = afd->feed;
920 delete afd;
921
922 FeedPropertiesDialog *dlg = new FeedPropertiesDialog( 0, "edit_feed" );
923 dlg->setFeed(feed);
924
925 dlg->selectFeedName();
926
927 if (!autoExec)
928 if (dlg->exec() != TQDialog::Accepted)
929 {
930 delete feed;
931 delete dlg;
932 return;
933 }
934
935 if (!parent)
936 parent = m_feedList->rootNode();
937
938 parent->insertChild(feed, after);
939
940 m_feedListView->ensureNodeVisible(feed);
941
942
943 delete dlg;
944}
945
947{
948 TreeNode* node = m_feedListView->selectedNode();
949 TreeNode* after = 0;
950
951 if (!node)
952 node = m_feedListView->rootNode();
953
954 // if a feed is selected, add group next to it
955 //TODO: tag nodes need rework
956 if (!node->isGroup())
957 {
958 after = node;
959 node = node->parent();
960 }
961
962 Folder* currentGroup = static_cast<Folder*> (node);
963
964 bool Ok;
965
966 TQString text = KInputDialog::getText(i18n("Add Folder"), i18n("Folder name:"), "", &Ok);
967
968 if (Ok)
969 {
970 Folder* newGroup = new Folder(text);
971 if (!after)
972 currentGroup->appendChild(newGroup);
973 else
974 currentGroup->insertChild(newGroup, after);
975
976 m_feedListView->ensureNodeVisible(newGroup);
977 }
978}
979
981{
982 TreeNode* selectedNode = m_listTabWidget->activeView()->selectedNode();
983
984 // don't delete root element! (safety valve)
985 if (!selectedNode || selectedNode == m_feedList->rootNode())
986 return;
987
988 m_deleteNodeVisitor->visit(selectedNode);
989}
990
992{
993 TreeNode* node = m_listTabWidget->activeView()->selectedNode();
994 if (node)
995 m_editNodePropertiesVisitor->visit(node);
996
997}
998
1000{
1001 if (m_viewMode == CombinedView)
1002 m_listTabWidget->activeView()->slotNextUnreadFeed();
1003
1004 TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
1005 if (sel && sel->unread() > 0)
1006 m_articleList->slotNextUnreadArticle();
1007 else
1008 m_listTabWidget->activeView()->slotNextUnreadFeed();
1009}
1010
1012{
1013 if (m_viewMode == CombinedView)
1014 m_listTabWidget->activeView()->slotPrevUnreadFeed();
1015
1016 TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
1017 if (sel && sel->unread() > 0)
1018 m_articleList->slotPreviousUnreadArticle();
1019 else
1020 m_listTabWidget->activeView()->slotPrevUnreadFeed();
1021}
1022
1024{
1025 m_feedList->rootNode()->slotMarkAllArticlesAsRead();
1026}
1027
1029{
1030 if(!m_listTabWidget->activeView()->selectedNode()) return;
1031 m_listTabWidget->activeView()->selectedNode()->slotMarkAllArticlesAsRead();
1032}
1033
1035{
1036 Feed* feed = dynamic_cast<Feed *>(m_listTabWidget->activeView()->selectedNode());
1037
1038 if (!feed)
1039 return;
1040
1041 KURL url = KURL(feed->htmlUrl())
1042;
1043 switch (Settings::lMBBehaviour())
1044 {
1045 case Settings::EnumLMBBehaviour::OpenInExternalBrowser:
1046 slotOpenURL(url, 0, BrowserRun::EXTERNAL);
1047 break;
1048 case Settings::EnumLMBBehaviour::OpenInBackground:
1049 slotOpenURL(url, 0, BrowserRun::NEW_TAB_BACKGROUND);
1050 break;
1051 default:
1052 slotOpenURL(url, 0, BrowserRun::NEW_TAB_FOREGROUND);
1053 }
1054}
1055
1057{
1058 emit signalUnreadCountChanged( m_feedList->rootNode()->unread() );
1059}
1060
1061void View::slotDoIntervalFetches()
1062{
1063 m_feedList->rootNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue(), true);
1064}
1065
1067{
1068 if ( !m_listTabWidget->activeView()->selectedNode() )
1069 return;
1070 m_listTabWidget->activeView()->selectedNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
1071}
1072
1074{
1075 m_feedList->rootNode()->slotAddToFetchQueue(Kernel::self()->fetchQueue());
1076}
1077
1078void View::slotFetchingStarted()
1079{
1080 m_mainFrame->setState(Frame::Started);
1081 m_actionManager->action("feed_stop")->setEnabled(true);
1082 m_mainFrame->setStatusText(i18n("Fetching Feeds..."));
1083}
1084
1085void View::slotFetchingStopped()
1086{
1087 m_mainFrame->setState(Frame::Completed);
1088 m_actionManager->action("feed_stop")->setEnabled(false);
1089 m_mainFrame->setStatusText(TQString());
1090}
1091
1093{
1094 // iterate through the articles (once again) to do notifications properly
1095 if (feed->articles().count() > 0)
1096 {
1097 TQValueList<Article> articles = feed->articles();
1098 TQValueList<Article>::ConstIterator it;
1099 TQValueList<Article>::ConstIterator end = articles.end();
1100 for (it = articles.begin(); it != end; ++it)
1101 {
1102 if ((*it).status()==Article::New && ((*it).feed()->useNotification() || Settings::useNotifications()))
1103 {
1105 }
1106 }
1107 }
1108}
1109
1110void View::slotMouseButtonPressed(int button, const Article& article, const TQPoint &, int)
1111{
1112 if (button == TQt::MidButton)
1113 {
1114 KURL link = article.link();
1115 switch (Settings::mMBBehaviour())
1116 {
1117 case Settings::EnumMMBBehaviour::OpenInExternalBrowser:
1118 slotOpenURL(link, 0L, BrowserRun::EXTERNAL);
1119 break;
1120 case Settings::EnumMMBBehaviour::OpenInBackground:
1121 slotOpenURL(link, 0L, BrowserRun::NEW_TAB_BACKGROUND);
1122 break;
1123 default:
1124 slotOpenURL(link, 0L, BrowserRun::NEW_TAB_FOREGROUND);
1125 }
1126 }
1127}
1128
1129void View::slotAssignTag(const Tag& tag, bool assign)
1130{
1131 kdDebug() << (assign ? "assigned" : "removed") << " tag \"" << tag.id() << "\"" << endl;
1132 TQValueList<Article> selectedArticles = m_articleList->selectedArticles();
1133 for (TQValueList<Article>::Iterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
1134 {
1135 if (assign)
1136 (*it).addTag(tag.id());
1137 else
1138 (*it).removeTag(tag.id());
1139 }
1140 updateTagActions();
1141}
1142/*
1143void View::slotRemoveTag(const Tag& tag)
1144{
1145 kdDebug() << "remove tag \"" << tag.id() << "\" from selected articles" << endl;
1146 TQValueList<Article> selectedArticles = m_articleList->selectedArticles();
1147 for (TQValueList<Article>::Iterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
1148 (*it).removeTag(tag.id());
1149
1150 updateTagActions();
1151}
1152*/
1153void View::slotNewTag()
1154{
1155 Tag tag(TDEApplication::randomString(8), "New Tag");
1156 Kernel::self()->tagSet()->insert(tag);
1157 TagNode* node = m_tagNodeList->findByTagID(tag.id());
1158 if (node)
1159 m_tagNodeListView->startNodeRenaming(node);
1160}
1161
1162void View::slotTagCreated(const Tag& tag)
1163{
1164 if (m_tagNodeList && !m_tagNodeList->containsTagId(tag.id()))
1165 {
1166 TagNode* tagNode = new TagNode(tag, m_feedList->rootNode());
1167 m_tagNodeList->rootNode()->appendChild(tagNode);
1168 }
1169}
1170
1171void View::slotTagRemoved(const Tag& /*tag*/)
1172{
1173}
1174
1176{
1177 if (m_viewMode == CombinedView)
1178 return;
1179
1180 m_markReadTimer->stop();
1181
1182 Feed *feed = article.feed();
1183 if (!feed)
1184 return;
1185
1186 Article a(article);
1187 if (a.status() != Article::Read)
1188 {
1189 int delay;
1190
1191 if ( Settings::useMarkReadDelay() )
1192 {
1193 delay = Settings::markReadDelay();
1194
1195 if (delay > 0)
1196 m_markReadTimer->start( delay*1000, true );
1197 else
1198 a.setStatus(Article::Read);
1199 }
1200 }
1201
1202 TDEToggleAction* maai = dynamic_cast<TDEToggleAction*>(m_actionManager->action("article_set_status_important"));
1203 maai->setChecked(a.keep());
1204
1205 kdDebug() << "selected: " << a.guid() << endl;
1206
1207 updateTagActions();
1208
1209 m_articleViewer->slotShowArticle(a);
1210}
1211
1212void View::slotOpenArticleExternal(const Article& article, const TQPoint&, int)
1213{
1214 if (!article.isNull())
1215 Viewer::displayInExternalBrowser(article.link());
1216}
1217
1218
1220{
1221 Article article = m_articleList->currentArticle();
1222
1223 if (article.isNull())
1224 return;
1225
1226 KURL link;
1227 if (article.link().isValid())
1228 link = article.link();
1229 else if (article.guidIsPermaLink())
1230 link = KURL(article.guid());
1231
1232 if (link.isValid())
1233 {
1234 slotOpenURL(link, 0L, BrowserRun::NEW_TAB_FOREGROUND);
1235 }
1236}
1237
1239{
1240 slotOpenArticleExternal(m_articleList->currentArticle(), TQPoint(), 0);
1241}
1242
1244{
1245 Article article = m_articleList->currentArticle();
1246
1247 if (article.isNull())
1248 return;
1249
1250 KURL link;
1251
1252 if (article.link().isValid())
1253 link = article.link();
1254 else if (article.guidIsPermaLink())
1255 link = KURL(article.guid());
1256
1257 if (link.isValid())
1258 {
1259 slotOpenURL(link, 0L, BrowserRun::NEW_TAB_BACKGROUND);
1260 }
1261}
1262
1264{
1265 Article article = m_articleList->currentArticle();
1266
1267 if(article.isNull())
1268 return;
1269
1270 TQString link;
1271 if (article.link().isValid() || (article.guidIsPermaLink() && KURL(article.guid()).isValid()))
1272 {
1273 // in case link isn't valid, fall back to the guid permaLink.
1274 if (article.link().isValid())
1275 link = article.link().url();
1276 else
1277 link = article.guid();
1278 TQClipboard *cb = TQApplication::clipboard();
1279 cb->setText(link, TQClipboard::Clipboard);
1280 cb->setText(link, TQClipboard::Selection);
1281 }
1282}
1283
1284void View::slotFeedURLDropped(KURL::List &urls, TreeNode* after, Folder* parent)
1285{
1286 KURL::List::iterator it;
1287 for ( it = urls.begin(); it != urls.end(); ++it )
1288 {
1289 addFeed((*it).prettyURL(), after, parent, false);
1290 }
1291}
1292
1294{
1295 if ( Settings::showQuickFilter() )
1296 {
1297 Settings::setShowQuickFilter(false);
1298 m_searchBar->slotClearSearch();
1299 m_searchBar->hide();
1300 }
1301 else
1302 {
1303 Settings::setShowQuickFilter(true);
1304 if (!m_displayingAboutPage)
1305 m_searchBar->show();
1306 }
1307
1308}
1309
1311{
1312
1313 if ( m_viewMode == CombinedView )
1314 return;
1315
1316 TQValueList<Article> articles = m_articleList->selectedArticles();
1317
1318 TQString msg;
1319 switch (articles.count())
1320 {
1321 case 0:
1322 return;
1323 case 1:
1324 msg = i18n("<qt>Are you sure you want to delete article <b>%1</b>?</qt>").arg(TQStyleSheet::escape(articles.first().title()));
1325 break;
1326 default:
1327 msg = i18n("<qt>Are you sure you want to delete the selected article?</qt>",
1328 "<qt>Are you sure you want to delete the %n selected articles?</qt>",
1329 articles.count());
1330 }
1331
1332 if (KMessageBox::warningContinueCancel(0, msg, i18n("Delete Article"), KStdGuiItem::del()) == KMessageBox::Continue)
1333 {
1334 if (m_listTabWidget->activeView()->selectedNode())
1335 m_listTabWidget->activeView()->selectedNode()->setNotificationMode(false);
1336
1337 TQValueList<Feed*> feeds;
1338 for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1339 {
1340 Feed* feed = (*it).feed();
1341 if (!feeds.contains(feed))
1342 feeds.append(feed);
1343 feed->setNotificationMode(false);
1344 (*it).setDeleted();
1345 }
1346
1347 for (TQValueList<Feed*>::Iterator it = feeds.begin(); it != feeds.end(); ++it)
1348 {
1349 (*it)->setNotificationMode(true);
1350 }
1351
1352 if (m_listTabWidget->activeView()->selectedNode())
1353 m_listTabWidget->activeView()->selectedNode()->setNotificationMode(true);
1354 }
1355}
1356
1357
1359{
1360 TQValueList<Article> articles = m_articleList->selectedArticles();
1361
1362 if (articles.isEmpty())
1363 return;
1364
1365 bool allFlagsSet = true;
1366 for (TQValueList<Article>::Iterator it = articles.begin(); allFlagsSet && it != articles.end(); ++it)
1367 if (!(*it).keep())
1368 allFlagsSet = false;
1369
1370 for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1371 (*it).setKeep(!allFlagsSet);
1372}
1373
1375{
1376 TQValueList<Article> articles = m_articleList->selectedArticles();
1377
1378 if (articles.isEmpty())
1379 return;
1380
1381 for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1382 (*it).setStatus(Article::Read);
1383}
1384
1386{
1387 if (m_currentFrame == m_mainFrame)
1388 {
1389 if (m_viewMode != CombinedView)
1390 {
1391 // in non-combined view, read selected articles
1392 SpeechClient::self()->slotSpeak(m_articleList->selectedArticles());
1393 // TODO: if article viewer has a selection, read only the selected text?
1394 }
1395 else
1396 {
1397 if (m_listTabWidget->activeView()->selectedNode())
1398 {
1399 //TODO: read articles in current node, respecting quick filter!
1400 }
1401 }
1402 }
1403 else
1404 {
1405 TQString selectedText = static_cast<PageViewer *>(m_currentFrame->part())->selectedText();
1406
1407 if (!selectedText.isEmpty())
1408 SpeechClient::self()->slotSpeak(selectedText, "en");
1409 }
1410}
1411
1413{
1414 TQValueList<Article> articles = m_articleList->selectedArticles();
1415
1416 if (articles.isEmpty())
1417 return;
1418
1419 for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1420 (*it).setStatus(Article::Unread);
1421}
1422
1424{
1425 TQValueList<Article> articles = m_articleList->selectedArticles();
1426
1427 if (articles.isEmpty())
1428 return;
1429
1430 for (TQValueList<Article>::Iterator it = articles.begin(); it != articles.end(); ++it)
1431 (*it).setStatus(Article::New);
1432}
1433
1435{
1436 Article article = m_articleList->currentArticle();
1437
1438 if (article.isNull())
1439 return;
1440
1441 article.setStatus(Article::Read);
1442}
1443
1444void View::slotMouseOverInfo(const KFileItem *kifi)
1445{
1446 if (kifi)
1447 {
1448 KFileItem *k=(KFileItem*)kifi;
1449 m_mainFrame->setStatusText(k->url().prettyURL());//geStatusBarInfo());
1450 }
1451 else
1452 {
1453 m_mainFrame->setStatusText(TQString());
1454 }
1455}
1456
1457void View::readProperties(TDEConfig* config)
1458{
1459
1460 if (!Settings::resetQuickFilterOnNodeChange())
1461 {
1462 m_searchBar->slotSetText(config->readEntry("searchLine"));
1463 int statusfilter = config->readNumEntry("searchCombo", -1);
1464 if (statusfilter != -1)
1465 m_searchBar->slotSetStatus(statusfilter);
1466 }
1467
1468 int selectedID = config->readNumEntry("selectedNodeID", -1);
1469 if (selectedID != -1)
1470 {
1471 TreeNode* selNode = m_feedList->findByID(selectedID);
1472 if (selNode)
1473 m_listTabWidget->activeView()->setSelectedNode(selNode);
1474 }
1475
1476 TQStringList urls = config->readListEntry("FeedBrowserURLs");
1477 TQStringList::ConstIterator it = urls.begin();
1478 for (; it != urls.end(); ++it)
1479 {
1480 KURL url = KURL::fromPathOrURL(*it);
1481 if (url.isValid())
1482 slotOpenNewTab(url, true); // open in background
1483 }
1484}
1485
1486void View::saveProperties(TDEConfig* config)
1487{
1488 // save filter settings
1489 config->writeEntry("searchLine", m_searchBar->text());
1490 config->writeEntry("searchCombo", m_searchBar->status());
1491
1492 TreeNode* sel = m_listTabWidget->activeView()->selectedNode();
1493
1494 if (sel)
1495 {
1496 config->writeEntry("selectedNodeID", sel->id() );
1497 }
1498
1499 // save browser URLs
1500 TQStringList urls;
1501 TQPtrList<Frame> frames = m_tabs->frames();
1502 TQPtrList<Frame>::ConstIterator it = frames.begin();
1503 for (; it != frames.end(); ++it)
1504 {
1505 Frame *frame = *it;
1506 KParts::ReadOnlyPart *part = frame->part();
1507 PageViewer *pageViewer = dynamic_cast<PageViewer*>(part); // don't save the ArticleViewer
1508 if (pageViewer)
1509 {
1510 KURL url = pageViewer->url();
1511 if (url.isValid())
1512 urls.append(url.prettyURL());
1513 }
1514 }
1515
1516 config->writeEntry("FeedBrowserURLs", urls);
1517}
1518
1519void View::connectToFeedList(FeedList* feedList)
1520{
1521 connect(feedList->rootNode(), TQ_SIGNAL(signalChanged(TreeNode*)), this, TQ_SLOT(slotSetTotalUnread()));
1523}
1524
1525void View::disconnectFromFeedList(FeedList* feedList)
1526{
1527 disconnect(feedList->rootNode(), TQ_SIGNAL(signalChanged(TreeNode*)), this, TQ_SLOT(slotSetTotalUnread()));
1528}
1529
1530void View::updateTagActions()
1531{
1532 TQStringList tags;
1533
1534 TQValueList<Article> selectedArticles = m_articleList->selectedArticles();
1535
1536 for (TQValueList<Article>::ConstIterator it = selectedArticles.begin(); it != selectedArticles.end(); ++it)
1537 {
1538 TQStringList atags = (*it).tags();
1539 for (TQStringList::ConstIterator it2 = atags.begin(); it2 != atags.end(); ++it2)
1540 {
1541 if (!tags.contains(*it2))
1542 tags += *it2;
1543 }
1544 }
1545 m_actionManager->slotUpdateTagActions(!selectedArticles.isEmpty(), tags);
1546}
1547
1548} // namespace Akregator
1549
1550#include "akregator_view.moc"
Akregator-specific implementation of the ActionManager interface.
void slotUpdateTagActions(bool enabled, const TQStringList &tagIds)
fills the remove tag menu with the given tags enables/disables tag menu action according to enabled
This HTML viewer is used to display articles.
Definition: articleviewer.h:49
void slotShowArticle(const Article &article)
Show single article (normal view)
void slotShowNode(TreeNode *node)
Shows the articles of the tree node node (combined view).
A proxy class for RSS::Article with some additional methods to assist sorting.
Definition: article.h:58
bool keep() const
if true, the article should be kept even when expired
Definition: article.cpp:387
The model of a feed tree, represents an OPML document.
Definition: feedlist.h:45
virtual TQDomDocument toXML() const
exports the feed list as OPML.
Definition: feedlist.cpp:238
virtual bool readFromXML(const TQDomDocument &doc)
reads an OPML document and appends the items to this list
Definition: feedlist.cpp:145
void append(FeedList *list, Folder *parent=0, TreeNode *after=0)
appends another feed list as sub tree.
Definition: feedlist.cpp:219
represents a feed
Definition: feed.h:63
virtual TQValueList< Article > articles(const TQString &tag=TQString())
Returns a sequence of the articles this node contains.
Definition: feed.cpp:192
const TQString & htmlUrl() const
returns the URL of the HTML page of this feed
Definition: feed.cpp:355
a powerful matcher supporting multiple criterions, which can be combined via logical OR or AND
Represents a folder (containing feeds and/or other folders)
Definition: folder.h:45
virtual void insertChild(TreeNode *node, TreeNode *after)
inserts node as child after child node after.
Definition: folder.cpp:138
virtual TQValueList< TreeNode * > children() const
returns the (direct) children of this node.
Definition: folder.cpp:133
virtual void removeChild(TreeNode *node)
remove node from children.
Definition: folder.cpp:202
virtual void appendChild(TreeNode *node)
inserts node as last child
Definition: folder.cpp:168
A widget containing multiple list views, e.g.
Definition: listtabwidget.h:46
void slotNotifyArticle(const Article &article)
notifies an article.
static NotificationManager * self()
singleton instance of notification manager
This is a RSS Aggregator "Part".
virtual bool mergePart(KParts::Part *)
merges a nested part's GUI into the gui of this part
represents a set of tags (see Tag) In an application, there is usually one central tag set that is us...
Definition: tagset.h:48
bool containsID(const TQString &id) const
returns true if this set contains a tag with a given ID
Definition: tagset.cpp:75
void insert(const Tag &tag)
adds a tag to the tag set.
Definition: tagset.cpp:55
Abstract base class for all kind of elements in the feed tree, like feeds and feed groups (and search...
Definition: treenode.h:52
virtual uint id() const
returns the ID of this node.
Definition: treenode.cpp:145
virtual bool isGroup() const =0
Helps the rest of the app to decide if node should be handled as group or not.
virtual int totalCount() const =0
returns the number of total articles in the node (for groups: the accumulated count of the subtree)
virtual TreeNode * prevSibling() const
Get the previous sibling.
Definition: treenode.cpp:104
virtual void setNotificationMode(bool doNotify, bool notifyOccurredChanges=true)
Definition: treenode.cpp:125
virtual int unread() const =0
The unread count, returns the number of new/unread articles in the node (for groups: the accumulated ...
virtual const TQString & title() const
Get title of node.
Definition: treenode.cpp:77
virtual Folder * parent() const
Returns the parent node.
Definition: treenode.cpp:115
virtual void slotDeleteExpiredArticles()=0
Deletes all expired articles in the node (depending on the expiry settings).
void slotMouseButtonPressed(int button, const Article &article, const TQPoint &pos, int c)
special behaviour in article list view (TODO: move code there?)
void slotFeedURLDropped(KURL::List &urls, TreeNode *after, Folder *parent)
called when URLs are dropped into the tree view
void slotFeedAdd()
adds a new feed to the feed tree
bool importFeeds(const TQDomDocument &doc)
Adds the feeds in doc to the "Imported Folder".
void slotUrlClickedInViewer(const KURL &url, Viewer *viewer, bool newTab, bool background)
HACK: part of the url opening hack for 3.5.
void slotSetSelectedArticleRead()
marks the currently selected article as read
void slotFetchCurrentFeed()
fetches the currently selected feed
void slotOpenCurrentArticle()
opens current article in new tab, background/foreground depends on settings TODO: use selected instea...
TQDomDocument feedListToOPML()
void slotMouseOverInfo(const KFileItem *kifi)
displays a URL in the status bar when the user moves the mouse over a link
void slotOpenCurrentArticleExternal()
opens the current article (currentItem) in external browser TODO: use selected instead of current?
void slotSetCurrentArticleReadDelayed()
marks the currenctly selected article as read after a user-set delay
virtual void readProperties(TDEConfig *config)
session management
void slotPrevUnreadArticle()
selects the previous unread article in the article list
void slotFeedTreeContextMenu(TDEListView *, TreeNode *, const TQPoint &)
Shows requested popup menu for feed tree.
void saveSettings()
saves settings.
void slotOpenArticleExternal(const Article &article, const TQPoint &, int)
opens article of item in external browser
void slotNodeSelected(TreeNode *node)
selected tree node has changed
void slotSetSelectedArticleUnread()
marks the currently selected article as unread
void slotArticleToggleKeepFlag(bool enabled)
toggles the keep flag of the currently selected article
View(Akregator::Part *part, TQWidget *parent, ActionManagerImpl *actionManager, const char *name)
constructor
void slotOpenCurrentArticleBackgroundTab()
opens the current article (currentItem) in background tab TODO: use selected instead of current?
void slotCopyLinkAddress()
copies the link of current article to clipboard
void slotSetSelectedArticleNew()
marks the currently selected article as new
void slotArticleDelete()
deletes the currently selected article
void slotCaptionChanged(const TQString &)
sets the window caption after a frame change
void slotNormalView()
switches view mode to normal view
void signalUnreadCountChanged(int)
emitted when the unread count of "All Feeds" was changed
void slotOpenNewTab(const KURL &url, bool background=false)
opens a page viewer in a new tab and loads an URL
void slotFeedRemove()
removes the currently selected feed (ask for confirmation)
~View()
destructor.
void slotOpenURLReply(const KURL &url, Akregator::Viewer *currentViewer, Akregator::BrowserRun::OpeningMode mode)
HACK: receives signal from browserrun when the browserrun detects an HTML mimetype and actually loads...
void addFeedToGroup(const TQString &url, const TQString &group)
Add a feed to a group.
void slotMarkAllRead()
marks all articles in the currently selected feed as read
void slotFrameChanged(Frame *f)
called when another part/frame is activated.
void slotCombinedView()
switches view mode to combined view
void slotSetTotalUnread()
emits signalUnreadCountChanged(int)
void slotStatusText(const TQString &)
sets the status bar text to a given string
void slotToggleShowQuickFilter()
toggles the visibility of the filter bar
void slotFeedModify()
calls the properties dialog for feeds, starts renaming for feed groups
void slotOpenHomepage()
opens the homepage of the currently selected feed
void slotFetchAllFeeds()
starts fetching of all feeds in the tree
void slotWidescreenView()
switches view mode to widescreen view
void slotTextToSpeechRequest()
reads the currently selected articles using KTTSD
void slotArticleSelected(const Article &)
the article selection has changed
void slotFeedFetched(Feed *)
Feed has been fetched, populate article view if needed and update counters.
bool loadFeeds(const TQDomDocument &doc, Folder *parent=0)
Parse OPML presentation of feeds and read in articles archive, if present.
void slotMarkAllFeedsRead()
marks all articles in all feeds in the tree as read
void slotFeedAddGroup()
adds a feed group to the feed tree
void slotNextUnreadArticle()
selects the next unread article in the article list