akregator/src

actionmanagerimpl.cpp
1 /*
2  This file is part of Akregator.
3 
4  Copyright (C) 2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20  As a special exception, permission is given to link this program
21  with any edition of TQt, and distribute the resulting executable,
22  without including the source code for TQt in the source distribution.
23 */
24 
25 #include <tqwidget.h>
26 #include <tdeaction.h>
27 #include <tdeactioncollection.h>
28 #include <tdelocale.h>
29 #include <tdepopupmenu.h>
30 #include <tdeshortcut.h>
31 #include <kxmlguifactory.h>
32 
33 #include <tqmap.h>
34 #include <tqstring.h>
35 #include <tqvaluelist.h>
36 
37 #include "actionmanagerimpl.h"
38 #include "akregatorconfig.h"
39 #include "akregator_part.h"
40 #include "akregator_view.h"
41 #include "articlelistview.h"
42 #include "articleviewer.h"
43 #include "feed.h"
44 #include "feedlistview.h"
45 #include "fetchqueue.h"
46 #include "folder.h"
47 #include "listtabwidget.h"
48 #include "kernel.h"
49 #include "speechclient.h"
50 #include "tag.h"
51 #include "tagaction.h"
52 #include "tagnode.h"
53 #include "tagset.h"
54 #include "trayicon.h"
55 #include "treenode.h"
56 #include "treenodevisitor.h"
57 #include "tabwidget.h"
58 #include "tdestdaccel.h"
59 
60 
61 
62 #include <kdebug.h>
63 
64 namespace Akregator
65 {
66 
67 class ActionManagerImpl::NodeSelectVisitor : public TreeNodeVisitor
68 {
69  public:
70  NodeSelectVisitor(ActionManagerImpl* manager) : m_manager(manager) {}
71  virtual ~NodeSelectVisitor() {}
72 
73  virtual bool visitFeed(Feed* node)
74  {
75  TDEAction* remove = m_manager->action("feed_remove");
76  if (remove)
77  remove->setEnabled(true);
78  TDEAction* hp = m_manager->action("feed_homepage");
79  if (hp)
80  hp->setEnabled(!node->htmlUrl().isEmpty());
81  m_manager->action("feed_fetch")->setText(i18n("&Fetch Feed"));
82  m_manager->action("feed_remove")->setText(i18n("&Delete Feed"));
83  m_manager->action("feed_modify")->setText(i18n("&Edit Feed..."));
84  m_manager->action("feed_mark_all_as_read")->setText(i18n("&Mark Feed as Read"));
85 
86  return true;
87  }
88 
89  virtual bool visitFolder(Folder* node)
90  {
91  TDEAction* remove = m_manager->action("feed_remove");
92  if (remove)
93  remove->setEnabled(node->parent()); // root nodes must not be deleted
94  TDEAction* hp = m_manager->action("feed_homepage");
95  if (hp)
96  hp->setEnabled(false);
97 
98  m_manager->action("feed_fetch")->setText(i18n("&Fetch Feeds"));
99  m_manager->action("feed_remove")->setText(i18n("&Delete Folder"));
100  m_manager->action("feed_modify")->setText(i18n("&Rename Folder"));
101  m_manager->action("feed_mark_all_as_read")->setText(i18n("&Mark Feeds as Read"));
102 
103  return true;
104  }
105 
106  virtual bool visitTagNode(TagNode* /*node*/)
107  {
108  TDEAction* remove = m_manager->action("feed_remove");
109  if (remove)
110  remove->setEnabled(true);
111  TDEAction* hp = m_manager->action("feed_homepage");
112  if (hp)
113  hp->setEnabled(false);
114  m_manager->action("feed_mark_all_as_read")->setText(i18n("&Mark Articles as Read"));
115  m_manager->action("feed_remove")->setText(i18n("&Delete Tag"));
116  m_manager->action("feed_modify")->setText(i18n("&Edit Tag..."));
117 
118  return true;
119  }
120  private:
121  ActionManagerImpl* m_manager;
122 };
123 
124 class ActionManagerImpl::ActionManagerImplPrivate
125 {
126 public:
127 
128  NodeSelectVisitor* nodeSelectVisitor;
129  ArticleListView* articleList;
130  ListTabWidget* listTabWidget;
131  View* view;
132  ArticleViewer* articleViewer;
133  Part* part;
134  TrayIcon* trayIcon;
135  TDEActionMenu* tagMenu;
136  TDEActionCollection* actionCollection;
137  TagSet* tagSet;
138  TQMap<TQString, TagAction*> tagActions;
139  TabWidget* tabWidget;
140  TDEAction* speakSelectedArticlesAction;
141 };
142 
143 void ActionManagerImpl::slotUpdateTagActions(bool enabled, const TQStringList& tagIds)
144 {
145  if (Settings::showTaggingGUI() && d->tagMenu)
146  {
147  d->tagMenu->setEnabled(enabled);
148  TQValueList<TagAction*> actions = d->tagActions.values();
149 
150  for (TQValueList<TagAction*>::ConstIterator it = actions.begin(); it != actions.end(); ++it)
151  {
152  (*it)->setChecked(tagIds.contains((*it)->tag().id()));
153  }
154  }
155 }
156 
157 void ActionManagerImpl::setTagSet(TagSet* tagSet)
158 {
159  if (tagSet == d->tagSet)
160  return;
161 
162  if (d->tagSet != 0)
163  {
164  disconnect(d->tagSet, TQ_SIGNAL(signalTagAdded(const Tag&)), this, TQ_SLOT(slotTagAdded(const Tag&)));
165  disconnect(d->tagSet, TQ_SIGNAL(signalTagRemoved(const Tag&)), this, TQ_SLOT(slotTagRemoved(const Tag&)));
166  }
167 
168  d->tagSet = tagSet;
169 
170  if (tagSet != 0)
171  {
172  connect(d->tagSet, TQ_SIGNAL(signalTagAdded(const Tag&)), this, TQ_SLOT(slotTagAdded(const Tag&)));
173  connect(d->tagSet, TQ_SIGNAL(signalTagRemoved(const Tag&)), this, TQ_SLOT(slotTagRemoved(const Tag&)));
174  }
175 
176  TQValueList<TagAction*> actions = d->tagActions.values();
177  for (TQValueList<TagAction*>::ConstIterator it = actions.begin(); it != actions.end(); ++it)
178  {
179  d->tagMenu->remove(*it);
180  delete *it;
181  }
182 
183 
184  d->tagActions.clear();
185 
186  //TODO: remove actions from menus, delete actions, clear maps
187 
188  if (tagSet != 0L)
189  {
190  TQValueList<Tag> list = tagSet->toMap().values();
191  for (TQValueList<Tag>::ConstIterator it = list.begin(); it != list.end(); ++it)
192  slotTagAdded(*it);
193  }
194 }
195 
196 void ActionManagerImpl::slotTagAdded(const Tag& tag)
197 {
198  if (!Settings::showTaggingGUI())
199  return;
200 
201  if (!d->tagActions.contains(tag.id()))
202  {
203  d->tagActions[tag.id()] = new TagAction(tag, d->view, TQ_SLOT(slotAssignTag(const Tag&, bool)), d->tagMenu);
204  d->tagMenu->insert(d->tagActions[tag.id()]);
205  }
206 }
207 
208 void ActionManagerImpl::slotTagRemoved(const Tag& tag)
209 {
210  if (!Settings::showTaggingGUI())
211  return;
212 
213  TQString id = tag.id();
214  TagAction* action = d->tagActions[id];
215  d->tagMenu->remove(action);
216  d->tagActions.remove(id);
217  delete action;
218 }
219 
220 void ActionManagerImpl::slotNodeSelected(TreeNode* node)
221 {
222  if (node != 0)
223  d->nodeSelectVisitor->visit(node);
224 }
225 
226 ActionManagerImpl::ActionManagerImpl(Part* part, TQObject* parent, const char* name) : ActionManager(parent, name), d(new ActionManagerImplPrivate)
227 {
228  d->nodeSelectVisitor = new NodeSelectVisitor(this);
229  d->part = part;
230  d->tagSet = 0;
231  d->listTabWidget = 0;
232  d->articleList = 0;
233  d->trayIcon = 0;
234  d->articleViewer = 0;
235  d->view = 0;
236  d->tabWidget = 0;
237  d->tagMenu = 0;
238  d->speakSelectedArticlesAction = 0;
239  d->actionCollection = part->actionCollection();
240  initPart();
241 }
242 
243 ActionManagerImpl::~ActionManagerImpl()
244 {
245  delete d->nodeSelectVisitor;
246  delete d;
247  d = 0;
248 }
249 
250 void ActionManagerImpl::initTrayIcon(TrayIcon* trayIcon)
251 {
252  if (d->trayIcon)
253  return;
254  else d->trayIcon = trayIcon;
255 
256  TDEPopupMenu* traypop = trayIcon->contextMenu();
257 
258  if (actionCollection()->action("feed_fetch_all"))
259  actionCollection()->action("feed_fetch_all")->plug(traypop, 1);
260  if (actionCollection()->action("akregator_configure_akregator"))
261  actionCollection()->action("akregator_configure_akregator")->plug(traypop, 2);
262 }
263 
264 void ActionManagerImpl::initPart()
265 {
266  new TDEAction(i18n("&Import Feeds..."), "", "", d->part, TQ_SLOT(fileImport()), d->actionCollection, "file_import");
267  new TDEAction(i18n("&Export Feeds..."), "", "", d->part, TQ_SLOT(fileExport()), d->actionCollection, "file_export");
268  //new TDEAction(i18n("&Get Feeds From Web..."), "", "", d->part, TQ_SLOT(fileGetFeeds()), d->actionCollection, "file_getfromweb");
269 
270  new TDEAction(i18n("Send &Link Address..."), "mail_generic", "", d->part, TQ_SLOT(fileSendLink()), d->actionCollection, "file_sendlink");
271  new TDEAction(i18n("Send &File..."), "mail_generic", "", d->part, TQ_SLOT(fileSendFile()), d->actionCollection, "file_sendfile");
272 
273  KStdAction::configureNotifications(d->part, TQ_SLOT(showKNotifyOptions()), d->actionCollection); // options_configure_notifications
274  new TDEAction( i18n("Configure &Akregator..."), "configure", "", d->part, TQ_SLOT(showOptions()), d->actionCollection, "akregator_configure_akregator" );
275 }
276 
277 void ActionManagerImpl::initView(View* view)
278 {
279  if (d->view)
280  return;
281  else
282  d->view = view;
283 
284  // tag actions
285  new TDEAction(i18n("&New Tag..."), "", "", d->view, TQ_SLOT(slotNewTag()), actionCollection(), "tag_new");
286 
287  // Feed/Feed Group popup menu
288  new TDEAction(i18n("&Open Homepage"), "", "Ctrl+H", d->view, TQ_SLOT(slotOpenHomepage()), actionCollection(), "feed_homepage");
289  new TDEAction(i18n("&Add Feed..."), "bookmark_add", "Insert", d->view, TQ_SLOT(slotFeedAdd()), actionCollection(), "feed_add");
290  new TDEAction(i18n("Ne&w Folder..."), "folder-new", "Shift+Insert", d->view, TQ_SLOT(slotFeedAddGroup()), actionCollection(), "feed_add_group");
291  new TDEAction(i18n("&Delete Feed"), "edit-delete", "Alt+Delete", d->view, TQ_SLOT(slotFeedRemove()), actionCollection(), "feed_remove");
292  new TDEAction(i18n("&Edit Feed..."), "edit", "F2", d->view, TQ_SLOT(slotFeedModify()), actionCollection(), "feed_modify");
293  TDEActionMenu* vm = new TDEActionMenu( i18n( "&View Mode" ), actionCollection(), "view_mode" );
294 
295  TDERadioAction *ra = new TDERadioAction(i18n("&Normal View"), "view_top_bottom", "Ctrl+Shift+1", d->view, TQ_SLOT(slotNormalView()), actionCollection(), "normal_view");
296  ra->setExclusiveGroup( "ViewMode" );
297  vm->insert(ra);
298 
299  ra = new TDERadioAction(i18n("&Widescreen View"), "view_left_right", "Ctrl+Shift+2", d->view, TQ_SLOT(slotWidescreenView()), actionCollection(), "widescreen_view");
300  ra->setExclusiveGroup( "ViewMode" );
301  vm->insert(ra);
302 
303  ra = new TDERadioAction(i18n("C&ombined View"), "view_text", "Ctrl+Shift+3", d->view, TQ_SLOT(slotCombinedView()), actionCollection(), "combined_view");
304  ra->setExclusiveGroup( "ViewMode" );
305  vm->insert(ra);
306 
307  // toolbar / feed menu
308  new TDEAction(i18n("&Fetch Feed"), "go-down", TDEStdAccel::shortcut(TDEStdAccel::Reload), d->view, TQ_SLOT(slotFetchCurrentFeed()), actionCollection(), "feed_fetch");
309  new TDEAction(i18n("Fe&tch All Feeds"), "go-bottom", "Ctrl+L", d->view, TQ_SLOT(slotFetchAllFeeds()), actionCollection(), "feed_fetch_all");
310 
311  TDEAction* stopAction = new TDEAction(i18n( "&Abort Fetches" ), "process-stop", Key_Escape, Kernel::self()->fetchQueue(), TQ_SLOT(slotAbort()), actionCollection(), "feed_stop");
312  stopAction->setEnabled(false);
313 
314  new TDEAction(i18n("&Mark Feed as Read"), "goto", "Ctrl+R", d->view, TQ_SLOT(slotMarkAllRead()), actionCollection(), "feed_mark_all_as_read");
315  new TDEAction(i18n("Ma&rk All Feeds as Read"), "goto", "Ctrl+Shift+R", d->view, TQ_SLOT(slotMarkAllFeedsRead()), actionCollection(), "feed_mark_all_feeds_as_read");
316 
317  // Settings menu
318  TDEToggleAction* sqf = new TDEToggleAction(i18n("Show Quick Filter"), TQString(), 0, d->view, TQ_SLOT(slotToggleShowQuickFilter()), actionCollection(), "show_quick_filter");
319  sqf->setChecked( Settings::showQuickFilter() );
320 
321  new TDEAction( i18n("Open in Tab"), "tab_new", "Shift+Return", d->view, TQ_SLOT(slotOpenCurrentArticle()), actionCollection(), "article_open" );
322  new TDEAction( i18n("Open in Background Tab"), TQString(), "tab_new", d->view, TQ_SLOT(slotOpenCurrentArticleBackgroundTab()), actionCollection(), "article_open_background_tab" );
323  new TDEAction( i18n("Open in External Browser"), "window-new", "Ctrl+Shift+Return", d->view, TQ_SLOT(slotOpenCurrentArticleExternal()), actionCollection(), "article_open_external" );
324  new TDEAction( i18n("Copy Link Address"), TQString(), TQString(), d->view, TQ_SLOT(slotCopyLinkAddress()), actionCollection(), "article_copy_link_address" );
325 
326  new TDEAction(i18n("Pre&vious Unread Article"), "", Key_Minus, d->view, TQ_SLOT(slotPrevUnreadArticle()),actionCollection(), "go_prev_unread_article");
327  new TDEAction(i18n("Ne&xt Unread Article"), "", Key_Plus, d->view, TQ_SLOT(slotNextUnreadArticle()),actionCollection(), "go_next_unread_article");
328 
329  new TDEAction(i18n("&Delete"), "edit-delete", "Delete", d->view, TQ_SLOT(slotArticleDelete()), actionCollection(), "article_delete");
330 
331  if (Settings::showTaggingGUI())
332  {
333  d->tagMenu = new TDEActionMenu ( i18n( "&Set Tags" ), "rss_tag", actionCollection(), "article_tagmenu" );
334  d->tagMenu->setEnabled(false); // only enabled when articles are selected
335  }
336  TDEActionMenu* statusMenu = new TDEActionMenu ( i18n( "&Mark As" ),
337  actionCollection(), "article_set_status" );
338 
339  d->speakSelectedArticlesAction = new TDEAction(i18n("&Speak Selected Articles"), "kttsd", "", d->view, TQ_SLOT(slotTextToSpeechRequest()), actionCollection(), "akr_texttospeech");
340 
341  TDEAction* abortTTS = new TDEAction(i18n( "&Stop Speaking" ), "media-playback-stop", Key_Escape, SpeechClient::self(), TQ_SLOT(slotAbortJobs()), actionCollection(), "akr_aborttexttospeech");
342  abortTTS->setEnabled(false);
343 
344  connect(SpeechClient::self(), TQ_SIGNAL(signalActivated(bool)),
345  abortTTS, TQ_SLOT(setEnabled(bool)));
346 
347  statusMenu->insert(new TDEAction(KGuiItem(i18n("as in: mark as read","&Read"), "",
348  i18n("Mark selected article as read")),
349  "Ctrl+E", d->view, TQ_SLOT(slotSetSelectedArticleRead()),
350  actionCollection(), "article_set_status_read"));
351 
352  statusMenu->insert(new TDEAction(KGuiItem(i18n("&New"), "",
353  i18n("Mark selected article as new")),
354  "Ctrl+N", d->view, TQ_SLOT(slotSetSelectedArticleNew()),
355  actionCollection(), "article_set_status_new" ));
356 
357 
358  statusMenu->insert(new TDEAction(KGuiItem(i18n("&Unread"), "",
359  i18n("Mark selected article as unread")),
360  "Ctrl+U", d->view, TQ_SLOT(slotSetSelectedArticleUnread()),
361  actionCollection(), "article_set_status_unread"));
362 
363  TDEToggleAction* importantAction = new TDEToggleAction(i18n("&Mark as Important"), "flag", "Ctrl+I", actionCollection(), "article_set_status_important");
364  importantAction->setCheckedState(i18n("Remove &Important Mark"));
365  connect(importantAction, TQ_SIGNAL(toggled(bool)), d->view, TQ_SLOT(slotArticleToggleKeepFlag(bool)));
366 
367 
368  new TDEAction( i18n("Move Node Up"), TQString(), "Shift+Alt+Up", view, TQ_SLOT(slotMoveCurrentNodeUp()), d->actionCollection, "feedstree_move_up" );
369  new TDEAction( i18n("Move Node Down"), TQString(), "Shift+Alt+Down", view, TQ_SLOT(slotMoveCurrentNodeDown()), d->actionCollection, "feedstree_move_down" );
370  new TDEAction( i18n("Move Node Left"), TQString(), "Shift+Alt+Left", view, TQ_SLOT(slotMoveCurrentNodeLeft()), d->actionCollection, "feedstree_move_left" );
371  new TDEAction( i18n("Move Node Right"), TQString(), "Shift+Alt+Right", view, TQ_SLOT(slotMoveCurrentNodeRight()), d->actionCollection, "feedstree_move_right");
372 }
373 
374 void ActionManagerImpl::initArticleViewer(ArticleViewer* articleViewer)
375 {
376  if (d->articleViewer)
377  return;
378  else
379  d->articleViewer = articleViewer;
380 }
381 
382 void ActionManagerImpl::initArticleListView(ArticleListView* articleList)
383 {
384  if (d->articleList)
385  return;
386  else
387  d->articleList = articleList;
388 
389  new TDEAction( i18n("&Previous Article"), TQString(), "Left", articleList, TQ_SLOT(slotPreviousArticle()), actionCollection(), "go_previous_article" );
390  new TDEAction( i18n("&Next Article"), TQString(), "Right", articleList, TQ_SLOT(slotNextArticle()), actionCollection(), "go_next_article" );
391 }
392 
393 void ActionManagerImpl::initListTabWidget(ListTabWidget* listTabWidget)
394 {
395  if (d->listTabWidget)
396  return;
397  else
398  d->listTabWidget = listTabWidget;
399 
400  new TDEAction(i18n("&Previous Feed"), "", "P", listTabWidget, TQ_SLOT(slotPrevFeed()),actionCollection(), "go_prev_feed");
401  new TDEAction(i18n("&Next Feed"), "", "N", listTabWidget, TQ_SLOT(slotNextFeed()),actionCollection(), "go_next_feed");
402  new TDEAction(i18n("N&ext Unread Feed"), "", "Alt+Plus", listTabWidget, TQ_SLOT(slotNextUnreadFeed()),actionCollection(), "go_next_unread_feed");
403  new TDEAction(i18n("Prev&ious Unread Feed"), "", "Alt+Minus", listTabWidget, TQ_SLOT(slotPrevUnreadFeed()),actionCollection(), "go_prev_unread_feed");
404 
405  new TDEAction( i18n("Go to Top of Tree"), TQString(), "Ctrl+Home", listTabWidget, TQ_SLOT(slotItemBegin()), d->actionCollection, "feedstree_home" );
406  new TDEAction( i18n("Go to Bottom of Tree"), TQString(), "Ctrl+End", listTabWidget, TQ_SLOT(slotItemEnd()), d->actionCollection, "feedstree_end" );
407  new TDEAction( i18n("Go Left in Tree"), TQString(), "Ctrl+Left", listTabWidget, TQ_SLOT(slotItemLeft()), d->actionCollection, "feedstree_left" );
408  new TDEAction( i18n("Go Right in Tree"), TQString(), "Ctrl+Right", listTabWidget, TQ_SLOT(slotItemRight()), d->actionCollection, "feedstree_right" );
409  new TDEAction( i18n("Go Up in Tree"), TQString(), "Ctrl+Up", listTabWidget, TQ_SLOT(slotItemUp()), d->actionCollection, "feedstree_up" );
410  new TDEAction( i18n("Go Down in Tree"), TQString(), "Ctrl+Down", listTabWidget, TQ_SLOT(slotItemDown()), d->actionCollection, "feedstree_down" );
411 }
412 
413 void ActionManagerImpl::initTabWidget(TabWidget* tabWidget)
414 {
415  if (d->tabWidget)
416  return;
417  else
418  d->tabWidget = tabWidget;
419 
420  new TDEAction(i18n("Select Next Tab"), "", "Ctrl+Period", d->tabWidget, TQ_SLOT(slotNextTab()),actionCollection(), "select_next_tab");
421  new TDEAction(i18n("Select Previous Tab"), "", "Ctrl+Comma", d->tabWidget, TQ_SLOT(slotPreviousTab()),actionCollection(), "select_previous_tab");
422  new TDEAction( i18n("Detach Tab"), "tab_breakoff", CTRL+SHIFT+Key_B, d->tabWidget, TQ_SLOT(slotDetachTab()), actionCollection(), "tab_detach" );
423  new TDEAction( i18n("Copy Link Address"), TQString(), TQString(), d->tabWidget, TQ_SLOT(slotCopyLinkAddress()), actionCollection(), "tab_copylinkaddress" );
424  new TDEAction( i18n("&Close Tab"), "tab_remove", TDEStdAccel::close(), d->tabWidget, TQ_SLOT(slotCloseTab()), actionCollection(), "tab_remove" );
425 }
426 
427 TQWidget* ActionManagerImpl::container(const char* name)
428 {
429  return d->part->factory()->container(name, d->part);
430 }
431 
432 
433 TDEActionCollection* ActionManagerImpl::actionCollection()
434 {
435  return d->actionCollection;
436 }
437 TDEAction* ActionManagerImpl::action(const char* name, const char* classname)
438 {
439  return d->actionCollection != 0 ? d->actionCollection->action(name, classname) : 0;
440 }
441 
442 } // namespace Akregator
443 
444 #include "actionmanagerimpl.moc"
void slotUpdateTagActions(bool enabled, const TQStringList &tagIds)
fills the remove tag menu with the given tags enables/disables tag menu action according to enabled
represents a set of tags (see Tag) In an application, there is usually one central tag set that is us...
Definition: tagset.h:48
TQMap< TQString, Tag > toMap() const
returns the tag set as map ((id, Tag) pairs)
Definition: tagset.cpp:90