akregator/src

actionmanagerimpl.cpp

00001 /*
00002     This file is part of Akregator.
00003 
00004     Copyright (C) 2005 Frank Osterfeld <frank.osterfeld at kdemail.net>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qwidget.h>
00026 #include <kaction.h>
00027 #include <kactioncollection.h>
00028 #include <klocale.h>
00029 #include <kpopupmenu.h>
00030 #include <kshortcut.h>
00031 #include <kxmlguifactory.h>
00032 
00033 #include <qmap.h>
00034 #include <qstring.h>
00035 #include <qvaluelist.h>
00036 
00037 #include "actionmanagerimpl.h"
00038 #include "akregatorconfig.h"
00039 #include "akregator_part.h"
00040 #include "akregator_view.h"
00041 #include "articlelistview.h"
00042 #include "articleviewer.h"
00043 #include "feed.h"
00044 #include "feedlistview.h"
00045 #include "fetchqueue.h"
00046 #include "folder.h"
00047 #include "listtabwidget.h"
00048 #include "kernel.h"
00049 #include "speechclient.h"
00050 #include "tag.h"
00051 #include "tagaction.h"
00052 #include "tagnode.h"
00053 #include "tagset.h"
00054 #include "trayicon.h"
00055 #include "treenode.h"
00056 #include "treenodevisitor.h"
00057 #include "tabwidget.h"
00058 #include "kstdaccel.h"
00059 
00060 
00061 
00062 #include <kdebug.h>
00063 
00064 namespace Akregator
00065 {
00066 
00067 class ActionManagerImpl::NodeSelectVisitor : public TreeNodeVisitor
00068 {
00069     public:
00070     NodeSelectVisitor(ActionManagerImpl* manager) : m_manager(manager) {}
00071 
00072     virtual bool visitFeed(Feed* node)
00073     {
00074         KAction* remove = m_manager->action("feed_remove");
00075         if (remove)
00076             remove->setEnabled(true);
00077         KAction* hp = m_manager->action("feed_homepage");
00078         if (hp)
00079             hp->setEnabled(!node->htmlUrl().isEmpty());
00080         m_manager->action("feed_fetch")->setText(i18n("&Fetch Feed"));
00081         m_manager->action("feed_remove")->setText(i18n("&Delete Feed"));
00082         m_manager->action("feed_modify")->setText(i18n("&Edit Feed..."));
00083         m_manager->action("feed_mark_all_as_read")->setText(i18n("&Mark Feed as Read"));
00084 
00085         return true;
00086     }
00087 
00088     virtual bool visitFolder(Folder* node)
00089     {
00090         KAction* remove = m_manager->action("feed_remove");
00091         if (remove)
00092             remove->setEnabled(node->parent()); // root nodes must not be deleted
00093         KAction* hp = m_manager->action("feed_homepage");
00094         if (hp)
00095             hp->setEnabled(false);
00096 
00097         m_manager->action("feed_fetch")->setText(i18n("&Fetch Feeds"));
00098         m_manager->action("feed_remove")->setText(i18n("&Delete Folder"));
00099         m_manager->action("feed_modify")->setText(i18n("&Rename Folder"));
00100         m_manager->action("feed_mark_all_as_read")->setText(i18n("&Mark Feeds as Read"));
00101 
00102         return true;
00103     }
00104 
00105     virtual bool visitTagNode(TagNode* /*node*/)
00106     {
00107         KAction* remove = m_manager->action("feed_remove");
00108         if (remove)
00109             remove->setEnabled(true);
00110         KAction* hp = m_manager->action("feed_homepage");
00111         if (hp)
00112             hp->setEnabled(false);
00113         m_manager->action("feed_mark_all_as_read")->setText(i18n("&Mark Articles as Read"));
00114         m_manager->action("feed_remove")->setText(i18n("&Delete Tag"));
00115         m_manager->action("feed_modify")->setText(i18n("&Edit Tag..."));
00116 
00117         return true;
00118     }
00119     private:
00120     ActionManagerImpl* m_manager;
00121 };
00122 
00123 class ActionManagerImpl::ActionManagerImplPrivate
00124 {
00125 public:
00126 
00127     NodeSelectVisitor* nodeSelectVisitor;
00128     ArticleListView* articleList;
00129     ListTabWidget* listTabWidget;
00130     View* view;
00131     ArticleViewer* articleViewer;
00132     Part* part;
00133     TrayIcon* trayIcon;
00134     KActionMenu* tagMenu;
00135     KActionCollection* actionCollection;
00136     TagSet* tagSet;
00137     QMap<QString, TagAction*> tagActions;
00138     TabWidget* tabWidget;
00139     KAction* speakSelectedArticlesAction;
00140 };
00141 
00142 void ActionManagerImpl::slotUpdateTagActions(bool enabled, const QStringList& tagIds)
00143 {
00144     if (Settings::showTaggingGUI() && d->tagMenu)
00145     {
00146         d->tagMenu->setEnabled(enabled);
00147         QValueList<TagAction*> actions = d->tagActions.values();
00148 
00149         for (QValueList<TagAction*>::ConstIterator it = actions.begin(); it != actions.end(); ++it)
00150         {
00151             (*it)->setChecked(tagIds.contains((*it)->tag().id()));
00152         }
00153     }
00154 }
00155 
00156 void ActionManagerImpl::setTagSet(TagSet* tagSet)
00157 {
00158     if (tagSet == d->tagSet)
00159         return;
00160 
00161     if (d->tagSet != 0)
00162     {
00163         disconnect(d->tagSet, SIGNAL(signalTagAdded(const Tag&)), this, SLOT(slotTagAdded(const Tag&)));
00164         disconnect(d->tagSet, SIGNAL(signalTagRemoved(const Tag&)), this, SLOT(slotTagRemoved(const Tag&)));
00165     }
00166 
00167     d->tagSet = tagSet;
00168 
00169     if (tagSet != 0)
00170     {
00171         connect(d->tagSet, SIGNAL(signalTagAdded(const Tag&)), this, SLOT(slotTagAdded(const Tag&)));
00172         connect(d->tagSet, SIGNAL(signalTagRemoved(const Tag&)), this, SLOT(slotTagRemoved(const Tag&)));
00173     }
00174 
00175     QValueList<TagAction*> actions = d->tagActions.values();
00176     for (QValueList<TagAction*>::ConstIterator it = actions.begin(); it != actions.end(); ++it)
00177     {
00178         d->tagMenu->remove(*it);
00179         delete *it;
00180     }
00181 
00182 
00183     d->tagActions.clear();
00184 
00185     //TODO: remove actions from menus, delete actions, clear maps
00186 
00187     if (tagSet != 0L)
00188     {
00189         QValueList<Tag> list = tagSet->toMap().values();
00190         for (QValueList<Tag>::ConstIterator it = list.begin(); it != list.end(); ++it)
00191             slotTagAdded(*it);
00192     }
00193 }
00194 
00195 void ActionManagerImpl::slotTagAdded(const Tag& tag)
00196 {
00197     if (!Settings::showTaggingGUI())
00198         return;
00199 
00200     if (!d->tagActions.contains(tag.id()))
00201     {
00202         d->tagActions[tag.id()] = new TagAction(tag, d->view, SLOT(slotAssignTag(const Tag&, bool)), d->tagMenu);
00203         d->tagMenu->insert(d->tagActions[tag.id()]);
00204     }
00205 }
00206 
00207 void ActionManagerImpl::slotTagRemoved(const Tag& tag)
00208 {
00209     if (!Settings::showTaggingGUI())
00210         return;
00211 
00212     QString id = tag.id();
00213     TagAction* action = d->tagActions[id];
00214     d->tagMenu->remove(action);
00215     d->tagActions.remove(id);
00216     delete action;
00217 }
00218 
00219 void ActionManagerImpl::slotNodeSelected(TreeNode* node)
00220 {
00221     if (node != 0)
00222         d->nodeSelectVisitor->visit(node);
00223 }
00224 
00225 ActionManagerImpl::ActionManagerImpl(Part* part, QObject* parent, const char* name) : ActionManager(parent, name), d(new ActionManagerImplPrivate)
00226 {
00227     d->nodeSelectVisitor = new NodeSelectVisitor(this);
00228     d->part = part;
00229     d->tagSet = 0;
00230     d->listTabWidget = 0;
00231     d->articleList = 0;
00232     d->trayIcon = 0;
00233     d->articleViewer = 0;
00234     d->view = 0;
00235     d->tabWidget = 0;
00236     d->tagMenu = 0;
00237     d->speakSelectedArticlesAction = 0;
00238     d->actionCollection = part->actionCollection();
00239     initPart();
00240 }
00241 
00242 ActionManagerImpl::~ActionManagerImpl()
00243 {
00244     delete d->nodeSelectVisitor;
00245     delete d;
00246     d = 0;
00247 }
00248 
00249 void ActionManagerImpl::initTrayIcon(TrayIcon* trayIcon)
00250 {
00251     if (d->trayIcon)
00252         return;
00253     else d->trayIcon = trayIcon;
00254 
00255     KPopupMenu* traypop = trayIcon->contextMenu();
00256 
00257     if (actionCollection()->action("feed_fetch_all"))
00258         actionCollection()->action("feed_fetch_all")->plug(traypop, 1);
00259     if (actionCollection()->action("akregator_configure_akregator"))
00260         actionCollection()->action("akregator_configure_akregator")->plug(traypop, 2);
00261 }
00262 
00263 void ActionManagerImpl::initPart()
00264 {
00265     new KAction(i18n("&Import Feeds..."), "", "", d->part, SLOT(fileImport()), d->actionCollection, "file_import");
00266     new KAction(i18n("&Export Feeds..."), "", "", d->part, SLOT(fileExport()), d->actionCollection, "file_export");
00267     //new KAction(i18n("&Get Feeds From Web..."), "", "", d->part, SLOT(fileGetFeeds()), d->actionCollection, "file_getfromweb");
00268 
00269     new KAction(i18n("Send &Link Address..."), "mail_generic", "", d->part, SLOT(fileSendLink()), d->actionCollection, "file_sendlink");
00270     new KAction(i18n("Send &File..."), "mail_generic", "", d->part, SLOT(fileSendFile()), d->actionCollection, "file_sendfile");
00271 
00272     KStdAction::configureNotifications(d->part, SLOT(showKNotifyOptions()), d->actionCollection); // options_configure_notifications
00273     new KAction( i18n("Configure &Akregator..."), "configure", "", d->part, SLOT(showOptions()), d->actionCollection, "akregator_configure_akregator" );
00274 }
00275 
00276 void ActionManagerImpl::initView(View* view)
00277 {
00278     if (d->view)
00279         return;
00280     else
00281         d->view = view;
00282 
00283     // tag actions
00284     new KAction(i18n("&New Tag..."), "", "", d->view, SLOT(slotNewTag()), actionCollection(), "tag_new");
00285 
00286     // Feed/Feed Group popup menu
00287     new KAction(i18n("&Open Homepage"), "", "Ctrl+H", d->view, SLOT(slotOpenHomepage()), actionCollection(), "feed_homepage");
00288     new KAction(i18n("&Add Feed..."), "bookmark_add", "Insert", d->view, SLOT(slotFeedAdd()), actionCollection(), "feed_add");
00289     new KAction(i18n("Ne&w Folder..."), "folder_new", "Shift+Insert", d->view, SLOT(slotFeedAddGroup()), actionCollection(), "feed_add_group");
00290     new KAction(i18n("&Delete Feed"), "editdelete", "Alt+Delete", d->view, SLOT(slotFeedRemove()), actionCollection(), "feed_remove");
00291     new KAction(i18n("&Edit Feed..."), "edit", "F2", d->view, SLOT(slotFeedModify()), actionCollection(), "feed_modify");
00292         KActionMenu* vm = new KActionMenu( i18n( "&View Mode" ), actionCollection(), "view_mode" );
00293 
00294     KRadioAction *ra = new KRadioAction(i18n("&Normal View"), "view_top_bottom", "Ctrl+Shift+1", d->view, SLOT(slotNormalView()), actionCollection(), "normal_view");
00295     ra->setExclusiveGroup( "ViewMode" );
00296     vm->insert(ra);
00297 
00298     ra = new KRadioAction(i18n("&Widescreen View"), "view_left_right", "Ctrl+Shift+2", d->view, SLOT(slotWidescreenView()), actionCollection(), "widescreen_view");
00299     ra->setExclusiveGroup( "ViewMode" );
00300     vm->insert(ra);
00301 
00302     ra = new KRadioAction(i18n("C&ombined View"), "view_text", "Ctrl+Shift+3", d->view, SLOT(slotCombinedView()), actionCollection(), "combined_view");
00303     ra->setExclusiveGroup( "ViewMode" );
00304     vm->insert(ra);
00305 
00306     // toolbar / feed menu
00307     new KAction(i18n("&Fetch Feed"), "down", KStdAccel::shortcut(KStdAccel::Reload), d->view, SLOT(slotFetchCurrentFeed()), actionCollection(), "feed_fetch");
00308     new KAction(i18n("Fe&tch All Feeds"), "bottom", "Ctrl+L", d->view, SLOT(slotFetchAllFeeds()), actionCollection(), "feed_fetch_all");
00309 
00310     KAction* stopAction = new KAction(i18n( "&Abort Fetches" ), "stop", Key_Escape, Kernel::self()->fetchQueue(), SLOT(slotAbort()), actionCollection(), "feed_stop");
00311     stopAction->setEnabled(false);
00312 
00313     new KAction(i18n("&Mark Feed as Read"), "goto", "Ctrl+R", d->view, SLOT(slotMarkAllRead()), actionCollection(), "feed_mark_all_as_read");
00314     new KAction(i18n("Ma&rk All Feeds as Read"), "goto", "Ctrl+Shift+R", d->view, SLOT(slotMarkAllFeedsRead()), actionCollection(), "feed_mark_all_feeds_as_read");
00315 
00316     // Settings menu
00317     KToggleAction* sqf = new KToggleAction(i18n("Show Quick Filter"), QString::null, 0, d->view, SLOT(slotToggleShowQuickFilter()), actionCollection(), "show_quick_filter");
00318     sqf->setChecked( Settings::showQuickFilter() );
00319 
00320     new KAction( i18n("Open in Tab"), "tab_new", "Shift+Return", d->view, SLOT(slotOpenCurrentArticle()), actionCollection(), "article_open" );
00321     new KAction( i18n("Open in Background Tab"), QString::null, "tab_new", d->view, SLOT(slotOpenCurrentArticleBackgroundTab()), actionCollection(), "article_open_background_tab" );
00322     new KAction( i18n("Open in External Browser"), "window_new", "Ctrl+Shift+Return", d->view, SLOT(slotOpenCurrentArticleExternal()), actionCollection(), "article_open_external" );
00323     new KAction( i18n("Copy Link Address"), QString::null, QString::null, d->view, SLOT(slotCopyLinkAddress()), actionCollection(), "article_copy_link_address" );
00324 
00325     new KAction(i18n("Pre&vious Unread Article"), "", Key_Minus, d->view, SLOT(slotPrevUnreadArticle()),actionCollection(), "go_prev_unread_article");
00326     new KAction(i18n("Ne&xt Unread Article"), "", Key_Plus, d->view, SLOT(slotNextUnreadArticle()),actionCollection(), "go_next_unread_article");
00327 
00328     new KAction(i18n("&Delete"), "editdelete", "Delete", d->view, SLOT(slotArticleDelete()), actionCollection(), "article_delete");
00329 
00330     if (Settings::showTaggingGUI())
00331     {
00332         d->tagMenu = new KActionMenu ( i18n( "&Set Tags" ), "rss_tag",  actionCollection(), "article_tagmenu" );
00333         d->tagMenu->setEnabled(false); // only enabled when articles are selected
00334     }
00335     KActionMenu* statusMenu = new KActionMenu ( i18n( "&Mark As" ),
00336                                     actionCollection(), "article_set_status" );
00337 
00338     d->speakSelectedArticlesAction = new KAction(i18n("&Speak Selected Articles"), "kttsd", "", d->view, SLOT(slotTextToSpeechRequest()), actionCollection(), "akr_texttospeech");
00339 
00340     KAction* abortTTS = new KAction(i18n( "&Stop Speaking" ), "player_stop", Key_Escape, SpeechClient::self(), SLOT(slotAbortJobs()), actionCollection(), "akr_aborttexttospeech");
00341     abortTTS->setEnabled(false);
00342 
00343     connect(SpeechClient::self(), SIGNAL(signalActivated(bool)),
00344     abortTTS, SLOT(setEnabled(bool)));
00345 
00346     statusMenu->insert(new KAction(KGuiItem(i18n("as in: mark as read","&Read"), "",
00347                        i18n("Mark selected article as read")),
00348     "Ctrl+E", d->view, SLOT(slotSetSelectedArticleRead()),
00349     actionCollection(), "article_set_status_read"));
00350 
00351     statusMenu->insert(new KAction(KGuiItem(i18n("&New"), "",
00352                         i18n("Mark selected article as new")),
00353     "Ctrl+N", d->view, SLOT(slotSetSelectedArticleNew()),
00354     actionCollection(), "article_set_status_new" ));
00355 
00356 
00357     statusMenu->insert(new KAction(KGuiItem(i18n("&Unread"), "",
00358                        i18n("Mark selected article as unread")),
00359     "Ctrl+U", d->view, SLOT(slotSetSelectedArticleUnread()),
00360     actionCollection(), "article_set_status_unread"));
00361 
00362     KToggleAction* importantAction = new KToggleAction(i18n("&Mark as Important"), "flag", "Ctrl+I", actionCollection(), "article_set_status_important");
00363     importantAction->setCheckedState(i18n("Remove &Important Mark"));
00364     connect(importantAction, SIGNAL(toggled(bool)), d->view, SLOT(slotArticleToggleKeepFlag(bool)));
00365 
00366 
00367     new KAction( i18n("Move Node Up"), QString::null, "Shift+Alt+Up", view, SLOT(slotMoveCurrentNodeUp()), d->actionCollection, "feedstree_move_up" );
00368     new KAction( i18n("Move Node Down"), QString::null,  "Shift+Alt+Down", view, SLOT(slotMoveCurrentNodeDown()), d->actionCollection, "feedstree_move_down" );
00369     new KAction( i18n("Move Node Left"), QString::null, "Shift+Alt+Left", view, SLOT(slotMoveCurrentNodeLeft()), d->actionCollection, "feedstree_move_left" );
00370     new KAction( i18n("Move Node Right"), QString::null, "Shift+Alt+Right", view, SLOT(slotMoveCurrentNodeRight()), d->actionCollection, "feedstree_move_right");
00371 }
00372 
00373 void ActionManagerImpl::initArticleViewer(ArticleViewer* articleViewer)
00374 {
00375     if (d->articleViewer)
00376         return;
00377     else
00378         d->articleViewer = articleViewer;
00379 }
00380 
00381 void ActionManagerImpl::initArticleListView(ArticleListView* articleList)
00382 {
00383     if (d->articleList)
00384         return;
00385     else
00386         d->articleList = articleList;
00387 
00388     new KAction( i18n("&Previous Article"), QString::null, "Left", articleList, SLOT(slotPreviousArticle()), actionCollection(), "go_previous_article" );
00389     new KAction( i18n("&Next Article"), QString::null, "Right", articleList, SLOT(slotNextArticle()), actionCollection(), "go_next_article" );
00390 }
00391 
00392 void ActionManagerImpl::initListTabWidget(ListTabWidget* listTabWidget)
00393 {
00394     if (d->listTabWidget)
00395         return;
00396     else
00397         d->listTabWidget = listTabWidget;
00398 
00399     new KAction(i18n("&Previous Feed"), "", "P", listTabWidget,  SLOT(slotPrevFeed()),actionCollection(), "go_prev_feed");
00400     new KAction(i18n("&Next Feed"), "", "N", listTabWidget, SLOT(slotNextFeed()),actionCollection(), "go_next_feed");
00401     new KAction(i18n("N&ext Unread Feed"), "", "Alt+Plus", listTabWidget, SLOT(slotNextUnreadFeed()),actionCollection(), "go_next_unread_feed");
00402     new KAction(i18n("Prev&ious Unread Feed"), "", "Alt+Minus", listTabWidget, SLOT(slotPrevUnreadFeed()),actionCollection(), "go_prev_unread_feed");
00403 
00404     new KAction( i18n("Go to Top of Tree"), QString::null, "Ctrl+Home", listTabWidget, SLOT(slotItemBegin()), d->actionCollection, "feedstree_home" );
00405     new KAction( i18n("Go to Bottom of Tree"), QString::null, "Ctrl+End", listTabWidget, SLOT(slotItemEnd()), d->actionCollection, "feedstree_end" );
00406     new KAction( i18n("Go Left in Tree"), QString::null, "Ctrl+Left", listTabWidget, SLOT(slotItemLeft()), d->actionCollection, "feedstree_left" );
00407     new KAction( i18n("Go Right in Tree"), QString::null, "Ctrl+Right", listTabWidget, SLOT(slotItemRight()), d->actionCollection, "feedstree_right" );
00408     new KAction( i18n("Go Up in Tree"), QString::null, "Ctrl+Up", listTabWidget, SLOT(slotItemUp()), d->actionCollection, "feedstree_up" );
00409     new KAction( i18n("Go Down in Tree"), QString::null, "Ctrl+Down", listTabWidget, SLOT(slotItemDown()), d->actionCollection, "feedstree_down" );
00410 }
00411 
00412 void ActionManagerImpl::initTabWidget(TabWidget* tabWidget)
00413 {
00414     if (d->tabWidget)
00415         return;
00416     else
00417         d->tabWidget = tabWidget;
00418 
00419     new KAction(i18n("Select Next Tab"), "", "Ctrl+Period", d->tabWidget, SLOT(slotNextTab()),actionCollection(), "select_next_tab");
00420     new KAction(i18n("Select Previous Tab"), "", "Ctrl+Comma", d->tabWidget, SLOT(slotPreviousTab()),actionCollection(), "select_previous_tab");
00421     new KAction( i18n("Detach Tab"), "tab_breakoff", CTRL+SHIFT+Key_B, d->tabWidget, SLOT(slotDetachTab()), actionCollection(), "tab_detach" );
00422     new KAction( i18n("Copy Link Address"), QString::null, QString::null, d->tabWidget, SLOT(slotCopyLinkAddress()), actionCollection(), "tab_copylinkaddress" );
00423     new KAction( i18n("&Close Tab"), "tab_remove", KStdAccel::close(), d->tabWidget, SLOT(slotCloseTab()), actionCollection(), "tab_remove" );
00424 }
00425 
00426 QWidget* ActionManagerImpl::container(const char* name)
00427 {
00428     return d->part->factory()->container(name, d->part);
00429 }
00430 
00431 
00432 KActionCollection* ActionManagerImpl::actionCollection()
00433 {
00434     return d->actionCollection;
00435 }
00436 KAction* ActionManagerImpl::action(const char* name, const char* classname)
00437 {
00438     return d->actionCollection != 0 ? d->actionCollection->action(name, classname) : 0;
00439 }
00440 
00441 } // namespace Akregator
00442 
00443 #include "actionmanagerimpl.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys