• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.3 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
standardactionmanager.cpp
1 /*
2  Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "standardactionmanager.h"
21 
22 #include "actionstatemanager_p.h"
23 #include "agentfilterproxymodel.h"
24 #include "agentinstancecreatejob.h"
25 #include "agentmanager.h"
26 #include "agenttypedialog.h"
27 #include "collectioncreatejob.h"
28 #include "collectiondeletejob.h"
29 #include "collectiondialog.h"
30 #include "collectionmodel.h"
31 #include "collectionutils_p.h"
32 #include "entitytreemodel.h"
33 #include "favoritecollectionsmodel.h"
34 #include "itemdeletejob.h"
35 #include "itemmodel.h"
36 #include "metatypes.h"
37 #include "pastehelper_p.h"
38 #include "specialcollectionattribute_p.h"
39 #include "collectionpropertiesdialog.h"
40 #include "subscriptiondialog_p.h"
41 #include "renamefavoritedialog.h"
42 #include "trashjob.h"
43 #include "trashrestorejob.h"
44 #include "entitydeletedattribute.h"
45 #include "recentcollectionaction_p.h"
46 
47 #include <KIcon>
48 #include <KAction>
49 #include <KActionCollection>
50 #include <KActionMenu>
51 #include <KDebug>
52 #include <KInputDialog>
53 #include <KLocalizedString>
54 #include <KMenu>
55 #include <KMessageBox>
56 #include <KToggleAction>
57 
58 #include <QtCore/QMimeData>
59 #include <QApplication>
60 #include <QClipboard>
61 #include <QItemSelectionModel>
62 #include <QPointer>
63 #include <QWeakPointer>
64 
65 #include <boost/static_assert.hpp>
66 
67 using namespace Akonadi;
68 
69 //@cond PRIVATE
70 
71 enum ActionType
72 {
73  NormalAction,
74  ActionWithAlternative, //Normal action, but with an alternative state
75  ActionAlternative, //Alternative state of the ActionWithAlternative
76  MenuAction,
77  ToggleAction
78 };
79 
80 static const struct {
81  const char *name;
82  const char *label;
83  const char *iconLabel;
84  const char *icon;
85  int shortcut;
86  const char *slot;
87  ActionType actionType;
88 } standardActionData[] = {
89  { "akonadi_collection_create", I18N_NOOP("&New Folder..."), I18N_NOOP("New"), "folder-new", 0, SLOT(slotCreateCollection()), NormalAction },
90  { "akonadi_collection_copy", 0, 0, "edit-copy", 0, SLOT(slotCopyCollections()), NormalAction },
91  { "akonadi_collection_delete", I18N_NOOP("&Delete Folder"), I18N_NOOP("Delete"), "edit-delete", 0, SLOT(slotDeleteCollection()), NormalAction },
92  { "akonadi_collection_sync", I18N_NOOP("&Synchronize Folder"), I18N_NOOP("Synchronize"), "view-refresh", Qt::Key_F5, SLOT(slotSynchronizeCollection()), NormalAction },
93  { "akonadi_collection_properties", I18N_NOOP("Folder &Properties"), I18N_NOOP("Properties"), "configure", 0, SLOT(slotCollectionProperties()), NormalAction },
94  { "akonadi_item_copy", 0, 0, "edit-copy", 0, SLOT(slotCopyItems()), NormalAction },
95  { "akonadi_paste", I18N_NOOP("&Paste"), I18N_NOOP("Paste"), "edit-paste", Qt::CTRL + Qt::Key_V, SLOT(slotPaste()), NormalAction },
96  { "akonadi_item_delete", 0, 0, "edit-delete", Qt::Key_Delete, SLOT(slotDeleteItems()), NormalAction },
97  { "akonadi_manage_local_subscriptions", I18N_NOOP("Manage Local &Subscriptions..."), I18N_NOOP("Manage Local Subscriptions"), "folder-bookmarks", 0, SLOT(slotLocalSubscription()), NormalAction },
98  { "akonadi_collection_add_to_favorites", I18N_NOOP("Add to Favorite Folders"), I18N_NOOP("Add to Favorite"), "bookmark-new", 0, SLOT(slotAddToFavorites()), NormalAction },
99  { "akonadi_collection_remove_from_favorites", I18N_NOOP("Remove from Favorite Folders"), I18N_NOOP("Remove from Favorite"), "edit-delete", 0, SLOT(slotRemoveFromFavorites()), NormalAction },
100  { "akonadi_collection_rename_favorite", I18N_NOOP("Rename Favorite..."), I18N_NOOP("Rename"), "edit-rename", 0, SLOT(slotRenameFavorite()), NormalAction },
101  { "akonadi_collection_copy_to_menu", I18N_NOOP("Copy Folder To..."), I18N_NOOP("Copy To"), "edit-copy", 0, SLOT(slotCopyCollectionTo(QAction*)), MenuAction },
102  { "akonadi_item_copy_to_menu", I18N_NOOP("Copy Item To..."), I18N_NOOP("Copy To"), "edit-copy", 0, SLOT(slotCopyItemTo(QAction*)), MenuAction },
103  { "akonadi_item_move_to_menu", I18N_NOOP("Move Item To..."), I18N_NOOP("Move To"), "go-jump", 0, SLOT(slotMoveItemTo(QAction*)), MenuAction },
104  { "akonadi_collection_move_to_menu", I18N_NOOP("Move Folder To..."), I18N_NOOP("Move To"), "go-jump", 0, SLOT(slotMoveCollectionTo(QAction*)), MenuAction },
105  { "akonadi_item_cut", I18N_NOOP("&Cut Item"), I18N_NOOP("Cut"), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT(slotCutItems()), NormalAction },
106  { "akonadi_collection_cut", I18N_NOOP("&Cut Folder"), I18N_NOOP("Cut"), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT(slotCutCollections()), NormalAction },
107  { "akonadi_resource_create", I18N_NOOP("Create Resource"), 0, "folder-new", 0, SLOT(slotCreateResource()), NormalAction },
108  { "akonadi_resource_delete", I18N_NOOP("Delete Resource"), 0, "edit-delete", 0, SLOT(slotDeleteResource()), NormalAction },
109  { "akonadi_resource_properties", I18N_NOOP("&Resource Properties"), I18N_NOOP("Properties"), "configure", 0, SLOT(slotResourceProperties()), NormalAction },
110  { "akonadi_resource_synchronize", I18N_NOOP("Synchronize Resource"), I18N_NOOP("Synchronize"), "view-refresh", 0, SLOT(slotSynchronizeResource()), NormalAction },
111  { "akonadi_work_offline", I18N_NOOP("Work Offline"), 0, "user-offline", 0, SLOT(slotToggleWorkOffline(bool)), ToggleAction },
112  { "akonadi_collection_copy_to_dialog", I18N_NOOP("Copy Folder To..."), I18N_NOOP("Copy To"), "edit-copy", 0, SLOT(slotCopyCollectionTo()), NormalAction },
113  { "akonadi_collection_move_to_dialog", I18N_NOOP("Move Folder To..."), I18N_NOOP("Move To"), "go-jump", 0, SLOT(slotMoveCollectionTo()), NormalAction },
114  { "akonadi_item_copy_to_dialog", I18N_NOOP("Copy Item To..."), I18N_NOOP("Copy To"), "edit-copy", 0, SLOT(slotCopyItemTo()), NormalAction },
115  { "akonadi_item_move_to_dialog", I18N_NOOP("Move Item To..."), I18N_NOOP("Move To"), "go-jump", 0, SLOT(slotMoveItemTo()), NormalAction },
116  { "akonadi_collection_sync_recursive", I18N_NOOP("&Synchronize Folder Recursively"), I18N_NOOP("Synchronize Recursively"), "view-refresh", Qt::CTRL + Qt::Key_F5, SLOT(slotSynchronizeCollectionRecursive()), NormalAction },
117  { "akonadi_move_collection_to_trash", I18N_NOOP("&Move Folder To Trash"), I18N_NOOP("Move Folder To Trash"), "user-trash", 0, SLOT(slotMoveCollectionToTrash()), NormalAction },
118  { "akonadi_move_item_to_trash", I18N_NOOP("&Move Item To Trash"), I18N_NOOP("Move Item To Trash"), "user-trash", 0, SLOT(slotMoveItemToTrash()), NormalAction },
119  { "akonadi_restore_collection_from_trash", I18N_NOOP("&Restore Folder From Trash"), I18N_NOOP("Restore Folder From Trash"), "view-refresh", 0, SLOT(slotRestoreCollectionFromTrash()), NormalAction },
120  { "akonadi_restore_item_from_trash", I18N_NOOP("&Restore Item From Trash"), I18N_NOOP("Restore Item From Trash"), "view-refresh", 0, SLOT(slotRestoreItemFromTrash()), NormalAction },
121  { "akonadi_collection_trash_restore", I18N_NOOP("&Restore Folder From Trash"), I18N_NOOP("Restore Folder From Trash"), "user-trash", 0, SLOT(slotTrashRestoreCollection()), ActionWithAlternative },
122  { 0, I18N_NOOP("&Restore Collection From Trash"), I18N_NOOP("Restore Collection From Trash"), "view-refresh", 0, 0, ActionAlternative },
123  { "akonadi_item_trash_restore", I18N_NOOP("&Restore Item From Trash"), I18N_NOOP("Restore Item From Trash"), "user-trash", 0, SLOT(slotTrashRestoreItem()), ActionWithAlternative },
124  { 0, I18N_NOOP("&Restore Item From Trash"), I18N_NOOP("Restore Item From Trash"), "view-refresh", 0, 0, ActionAlternative },
125  { "akonadi_collection_sync_favorite_folders", I18N_NOOP("&Synchronize Favorite Folders"), I18N_NOOP("Synchronize Favorite Folders"), "view-refresh", Qt::CTRL + Qt::SHIFT + Qt::Key_L , SLOT(slotSynchronizeFavoriteCollections()), NormalAction }
126 
127 };
128 static const int numStandardActionData = sizeof standardActionData / sizeof * standardActionData;
129 
130 BOOST_STATIC_ASSERT(numStandardActionData == StandardActionManager::LastType);
131 
132 static bool canCreateCollection(const Akonadi::Collection &collection)
133 {
134  if (!(collection.rights() & Akonadi::Collection::CanCreateCollection)) {
135  return false;
136  }
137 
138  if (!collection.contentMimeTypes().contains(Akonadi::Collection::mimeType()) &&
139  !collection.contentMimeTypes().contains(Akonadi::Collection::virtualMimeType())) {
140  return false;
141  }
142 
143  return true;
144 }
145 
146 /*
147 static inline bool isRootCollection( const Akonadi::Collection &collection )
148 {
149  return (collection == Akonadi::Collection::root());
150 }
151 */
152 
153 static void setWorkOffline(bool offline)
154 {
155  KConfig config(QLatin1String("akonadikderc"));
156  KConfigGroup group(&config, QLatin1String("Actions"));
157 
158  group.writeEntry("WorkOffline", offline);
159 }
160 
161 static bool workOffline()
162 {
163  KConfig config(QLatin1String("akonadikderc"));
164  const KConfigGroup group(&config, QLatin1String("Actions"));
165 
166  return group.readEntry("WorkOffline", false);
167 }
168 
169 static QModelIndexList safeSelectedRows(QItemSelectionModel *selectionModel)
170 {
171  QModelIndexList selectedRows = selectionModel->selectedRows();
172  if (!selectedRows.isEmpty()) {
173  return selectedRows;
174  }
175 
176  // try harder for selected rows that don't span the full row for some reason (e.g. due to buggy column adding proxy models etc)
177  foreach (const QItemSelectionRange &range, selectionModel->selection()) {
178  if (!range.isValid() || range.isEmpty()) {
179  continue;
180  }
181  const QModelIndex parent = range.parent();
182  for (int row = range.top(); row <= range.bottom(); ++row) {
183  const QModelIndex index = range.model()->index(row, range.left(), parent);
184  const Qt::ItemFlags flags = range.model()->flags(index);
185  if ((flags &Qt::ItemIsSelectable) && (flags &Qt::ItemIsEnabled)) {
186  selectedRows.push_back(index);
187  }
188  }
189  }
190 
191  return selectedRows;
192 }
193 
197 class StandardActionManager::Private
198 {
199 public:
200  Private(StandardActionManager *parent)
201  : q(parent)
202  , actionCollection(0)
203  , parentWidget(0)
204  , collectionSelectionModel(0)
205  , itemSelectionModel(0)
206  , favoritesModel(0)
207  , favoriteSelectionModel(0)
208  , insideSelectionSlot(false)
209  {
210  actions.fill(0, StandardActionManager::LastType);
211 
212  pluralLabels.insert(StandardActionManager::CopyCollections,
213  ki18np("&Copy Folder", "&Copy %1 Folders"));
214  pluralLabels.insert(StandardActionManager::CopyItems,
215  ki18np("&Copy Item", "&Copy %1 Items"));
216  pluralLabels.insert(StandardActionManager::CutItems,
217  ki18np("&Cut Item", "&Cut %1 Items"));
218  pluralLabels.insert(StandardActionManager::CutCollections,
219  ki18np("&Cut Folder", "&Cut %1 Folders"));
220  pluralLabels.insert(StandardActionManager::DeleteItems,
221  ki18np("&Delete Item", "&Delete %1 Items"));
222  pluralLabels.insert(StandardActionManager::DeleteCollections,
223  ki18np("&Delete Folder", "&Delete %1 Folders"));
224  pluralLabels.insert(StandardActionManager::SynchronizeCollections,
225  ki18np("&Synchronize Folder", "&Synchronize %1 Folders"));
226  pluralLabels.insert(StandardActionManager::DeleteResources,
227  ki18np("&Delete Resource", "&Delete %1 Resources"));
228  pluralLabels.insert(StandardActionManager::SynchronizeResources,
229  ki18np("&Synchronize Resource", "&Synchronize %1 Resources"));
230 
231  pluralIconLabels.insert(StandardActionManager::CopyCollections,
232  ki18np("Copy Folder", "Copy %1 Folders"));
233  pluralIconLabels.insert(StandardActionManager::CopyItems,
234  ki18np("Copy Item", "Copy %1 Items"));
235  pluralIconLabels.insert(StandardActionManager::CutItems,
236  ki18np("Cut Item", "Cut %1 Items"));
237  pluralIconLabels.insert(StandardActionManager::CutCollections,
238  ki18np("Cut Folder", "Cut %1 Folders"));
239  pluralIconLabels.insert(StandardActionManager::DeleteItems,
240  ki18np("Delete Item", "Delete %1 Items"));
241  pluralIconLabels.insert(StandardActionManager::DeleteCollections,
242  ki18np("Delete Folder", "Delete %1 Folders"));
243  pluralIconLabels.insert(StandardActionManager::SynchronizeCollections,
244  ki18np("Synchronize Folder", "Synchronize %1 Folders"));
245  pluralIconLabels.insert(StandardActionManager::DeleteResources,
246  ki18np("Delete Resource", "Delete %1 Resources"));
247  pluralIconLabels.insert(StandardActionManager::SynchronizeResources,
248  ki18np("Synchronize Resource", "Synchronize %1 Resources"));
249 
250  setContextText(StandardActionManager::CreateCollection, StandardActionManager::DialogTitle,
251  i18nc("@title:window", "New Folder"));
252  setContextText(StandardActionManager::CreateCollection, StandardActionManager::DialogText,
253  i18nc("@label:textbox name of a thing", "Name"));
254  setContextText(StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText,
255  ki18n("Could not create folder: %1"));
256  setContextText(StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle,
257  i18n("Folder creation failed"));
258 
259  setContextText(StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText,
260  ki18np("Do you really want to delete this folder and all its sub-folders?",
261  "Do you really want to delete %1 folders and all their sub-folders?"));
262  setContextText(StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle,
263  ki18ncp("@title:window", "Delete folder?", "Delete folders?"));
264  setContextText(StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText,
265  ki18n("Could not delete folder: %1"));
266  setContextText(StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle,
267  i18n("Folder deletion failed"));
268 
269  setContextText(StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle,
270  ki18nc("@title:window", "Properties of Folder %1"));
271 
272  setContextText(StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText,
273  ki18np("Do you really want to delete the selected item?",
274  "Do you really want to delete %1 items?"));
275  setContextText(StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle,
276  ki18ncp("@title:window", "Delete item?", "Delete items?"));
277  setContextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText,
278  ki18n("Could not delete item: %1"));
279  setContextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle,
280  i18n("Item deletion failed"));
281 
282  setContextText(StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle,
283  i18nc("@title:window", "Rename Favorite"));
284  setContextText(StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText,
285  i18nc("@label:textbox name of the folder", "Name:"));
286 
287  setContextText(StandardActionManager::CreateResource, StandardActionManager::DialogTitle,
288  i18nc("@title:window", "New Resource"));
289  setContextText(StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText,
290  ki18n("Could not create resource: %1"));
291  setContextText(StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle,
292  i18n("Resource creation failed"));
293 
294  setContextText(StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText,
295  ki18np("Do you really want to delete this resource?",
296  "Do you really want to delete %1 resources?"));
297  setContextText(StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle,
298  ki18ncp("@title:window", "Delete Resource?", "Delete Resources?"));
299 
300  setContextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageText,
301  ki18n("Could not paste data: %1"));
302  setContextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle,
303  i18n("Paste failed"));
304 
305  qRegisterMetaType<Akonadi::Item::List>("Akonadi::Item::List");
306  }
307  void enableAction(int type, bool enable)
308  {
309  enableAction(static_cast<StandardActionManager::Type>(type), enable);
310  }
311 
312  void enableAction(StandardActionManager::Type type, bool enable)
313  {
314  Q_ASSERT(type < StandardActionManager::LastType);
315  if (actions[type]) {
316  actions[type]->setEnabled(enable);
317  }
318 
319  // Update the action menu
320  KActionMenu *actionMenu = qobject_cast<KActionMenu *>(actions[type]);
321  if (actionMenu) {
322  //get rid of the submenus, they are re-created in enableAction. clear() is not enough, doesn't remove the submenu object instances.
323  KMenu *menu = actionMenu->menu();
324  //Not necessary to delete and recreate menu when it was not created
325  if (menu->property("actionType").isValid() && menu->isEmpty()) {
326  return;
327  }
328  mRecentCollectionsMenu.remove(type);
329  delete menu;
330  menu = new KMenu();
331 
332  menu->setProperty("actionType", static_cast<int>(type));
333  q->connect(menu, SIGNAL(aboutToShow()), SLOT(aboutToShowMenu()));
334  q->connect(menu, SIGNAL(triggered(QAction*)), standardActionData[type].slot);
335  actionMenu->setMenu(menu);
336  }
337  }
338 
339  void aboutToShowMenu()
340  {
341  QMenu *menu = qobject_cast<QMenu *>(q->sender());
342  if (!menu) {
343  return;
344  }
345 
346  if (!menu->isEmpty()) {
347  return;
348  }
349  // collect all selected collections
350  const Akonadi::Collection::List selectedCollectionsList = selectedCollections();
351  const StandardActionManager::Type type = static_cast<StandardActionManager::Type>(menu->property("actionType").toInt());
352 
353  QWeakPointer<RecentCollectionAction> recentCollection = new RecentCollectionAction(type, selectedCollectionsList, collectionSelectionModel->model(), menu);
354  mRecentCollectionsMenu.insert(type, recentCollection);
355  const QSet<QString> mimeTypes = mimeTypesOfSelection(type);
356  fillFoldersMenu(selectedCollectionsList,
357  mimeTypes,
358  type,
359  menu,
360  collectionSelectionModel->model(),
361  QModelIndex());
362  }
363 
364  void createActionFolderMenu(QMenu *menu, StandardActionManager::Type type)
365  {
366  if (type == CopyCollectionToMenu ||
367  type == CopyItemToMenu ||
368  type == MoveItemToMenu ||
369  type == MoveCollectionToMenu)
370  {
371  new RecentCollectionAction(type, Akonadi::Collection::List(), collectionSelectionModel->model(), menu);
372  Collection::List selectedCollectionsList = selectedCollections();
373  const QSet<QString> mimeTypes = mimeTypesOfSelection(type);
374  fillFoldersMenu(selectedCollectionsList,
375  mimeTypes,
376  type,
377  menu,
378  collectionSelectionModel->model(),
379  QModelIndex());
380  }
381  }
382 
383  void updateAlternatingAction(int type)
384  {
385  updateAlternatingAction(static_cast<StandardActionManager::Type>(type));
386  }
387 
388  void updateAlternatingAction(StandardActionManager::Type type)
389  {
390  Q_ASSERT(type < StandardActionManager::LastType);
391  if (!actions[type]) {
392  return;
393  }
394 
395  /*
396  * The same action is stored at the ActionWithAlternative indexes as well as the corresponding ActionAlternative indexes in the actions array.
397  * The following simply changes the standardActionData
398  */
399  if ((standardActionData[type].actionType == ActionWithAlternative) || (standardActionData[type].actionType == ActionAlternative)) {
400  actions[type]->setText(i18n(standardActionData[type].label));
401  actions[type]->setIcon(KIcon(QString::fromLatin1(standardActionData[type].icon)));
402 
403  if (pluralLabels.contains(type) && !pluralLabels.value(type).isEmpty()) {
404  actions[type]->setText(pluralLabels.value(type).subs(1).toString());
405  } else if (standardActionData[type].label) {
406  actions[type]->setText(i18n(standardActionData[type].label));
407  }
408 
409  if (pluralIconLabels.contains(type) && !pluralIconLabels.value(type).isEmpty()) {
410  actions[type]->setIconText(pluralIconLabels.value(type).subs(1).toString());
411  } else if (standardActionData[type].iconLabel) {
412  actions[type]->setIconText(i18n(standardActionData[type].iconLabel));
413  }
414 
415  if (standardActionData[type].icon) {
416  actions[type]->setIcon(KIcon(QString::fromLatin1(standardActionData[type].icon)));
417  }
418 
419  //actions[type]->setShortcut( standardActionData[type].shortcut );
420 
421  /*if ( standardActionData[type].slot ) {
422  switch ( standardActionData[type].actionType ) {
423  case NormalAction:
424  case ActionWithAlternative:
425  connect( action, SIGNAL(triggered()), standardActionData[type].slot );
426  break;
427  }
428  }*/
429  }
430  }
431 
432  void updatePluralLabel(int type, int count)
433  {
434  updatePluralLabel(static_cast<StandardActionManager::Type>(type), count);
435  }
436 
437  void updatePluralLabel(StandardActionManager::Type type, int count)
438  {
439  Q_ASSERT(type < StandardActionManager::LastType);
440  if (actions[type] && pluralLabels.contains(type) && !pluralLabels.value(type).isEmpty()) {
441  actions[type]->setText(pluralLabels.value(type).subs(qMax(count, 1)).toString());
442  }
443  }
444 
445  bool isFavoriteCollection(const Akonadi::Collection &collection)
446  {
447  if (!favoritesModel) {
448  return false;
449  }
450 
451  return favoritesModel->collectionIds().contains(collection.id());
452  }
453 
454  void encodeToClipboard(QItemSelectionModel *selectionModel, bool cut = false)
455  {
456  Q_ASSERT(selectionModel);
457  if (safeSelectedRows(selectionModel).count() <= 0) {
458  return;
459  }
460 
461 #ifndef QT_NO_CLIPBOARD
462  QMimeData *mimeData = selectionModel->model()->mimeData(safeSelectedRows(selectionModel));
463  markCutAction(mimeData, cut);
464  QApplication::clipboard()->setMimeData(mimeData);
465 
466  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(selectionModel->model());
467 
468  foreach (const QModelIndex &index, safeSelectedRows(selectionModel)) {
469  model->setData(index, true, EntityTreeModel::PendingCutRole);
470  }
471 #endif
472  }
473 
474  void updateActions()
475  {
476  // collect all selected collections
477  Collection::List selectedCollectionsList;
478  if (collectionSelectionModel) {
479  const QModelIndexList rows = safeSelectedRows(collectionSelectionModel);
480  foreach (const QModelIndex &index, rows) {
481  Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
482  if (!collection.isValid()) {
483  continue;
484  }
485 
486  const Collection parentCollection = index.data(EntityTreeModel::ParentCollectionRole).value<Collection>();
487  collection.setParentCollection(parentCollection);
488 
489  selectedCollectionsList << collection;
490  }
491  }
492 
493  // collect all selected items
494  Item::List selectedItems;
495  if (itemSelectionModel) {
496  const QModelIndexList rows = safeSelectedRows(itemSelectionModel);
497  foreach (const QModelIndex &index, rows) {
498  Item item = index.data(EntityTreeModel::ItemRole).value<Item>();
499  if (!item.isValid()) {
500  continue;
501  }
502 
503  const Collection parentCollection = index.data(EntityTreeModel::ParentCollectionRole).value<Collection>();
504  item.setParentCollection(parentCollection);
505 
506  selectedItems << item;
507  }
508  }
509 
510  mActionStateManager.updateState(selectedCollectionsList, selectedItems);
511  if (favoritesModel) {
512  enableAction(StandardActionManager::SynchronizeFavoriteCollections, (favoritesModel->rowCount() > 0));
513  }
514  emit q->actionStateUpdated();
515  }
516 
517 #ifndef QT_NO_CLIPBOARD
518  void clipboardChanged(QClipboard::Mode mode)
519  {
520  if (mode == QClipboard::Clipboard) {
521  updateActions();
522  }
523  }
524 #endif
525 
526  QItemSelection mapToEntityTreeModel(const QAbstractItemModel *model, const QItemSelection &selection) const
527  {
528  const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model);
529  if (proxy) {
530  return mapToEntityTreeModel(proxy->sourceModel(), proxy->mapSelectionToSource(selection));
531  } else {
532  return selection;
533  }
534  }
535 
536  QItemSelection mapFromEntityTreeModel(const QAbstractItemModel *model, const QItemSelection &selection) const
537  {
538  const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model);
539  if (proxy) {
540  const QItemSelection select = mapFromEntityTreeModel(proxy->sourceModel(), selection);
541  return proxy->mapSelectionFromSource(select);
542  } else {
543  return selection;
544  }
545  }
546 
547  // RAII class for setting insideSelectionSlot to true on entering, and false on exiting, the two slots below.
548  class InsideSelectionSlotBlocker {
549  public:
550  InsideSelectionSlotBlocker(Private *p)
551  : _p(p)
552  {
553  Q_ASSERT(!p->insideSelectionSlot);
554  p->insideSelectionSlot = true;
555  }
556 
557  ~InsideSelectionSlotBlocker()
558  {
559  Q_ASSERT(_p->insideSelectionSlot);
560  _p->insideSelectionSlot = false;
561  }
562  private:
563  Private *_p;
564  };
565 
566  void collectionSelectionChanged()
567  {
568  if (insideSelectionSlot) {
569  return;
570  }
571  InsideSelectionSlotBlocker block(this);
572  QItemSelection selection = collectionSelectionModel->selection();
573  selection = mapToEntityTreeModel(collectionSelectionModel->model(), selection);
574  selection = mapFromEntityTreeModel(favoritesModel, selection);
575 
576  if (favoriteSelectionModel) {
577  favoriteSelectionModel->select(selection, QItemSelectionModel::ClearAndSelect);
578  }
579 
580  updateActions();
581  }
582 
583  void favoriteSelectionChanged()
584  {
585  if (insideSelectionSlot) {
586  return;
587  }
588  QItemSelection selection = favoriteSelectionModel->selection();
589  if (selection.isEmpty()) {
590  return;
591  }
592 
593  selection = mapToEntityTreeModel(favoritesModel, selection);
594  selection = mapFromEntityTreeModel(collectionSelectionModel->model(), selection);
595 
596  InsideSelectionSlotBlocker block(this);
597  collectionSelectionModel->select(selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
598 
599  // Also set the current index. This will trigger KMMainWidget::slotFolderChanged in kmail, which we want.
600  collectionSelectionModel->setCurrentIndex(selection.indexes().first(), QItemSelectionModel::NoUpdate);
601 
602  updateActions();
603  }
604 
605  void slotCreateCollection()
606  {
607  Q_ASSERT(collectionSelectionModel);
608  if (collectionSelectionModel->selection().indexes().isEmpty()) {
609  return;
610  }
611 
612  const QModelIndex index = collectionSelectionModel->selection().indexes().at(0);
613  Q_ASSERT(index.isValid());
614  const Collection parentCollection = index.data(CollectionModel::CollectionRole).value<Collection>();
615  Q_ASSERT(parentCollection.isValid());
616 
617  if (!canCreateCollection(parentCollection)) {
618  return;
619  }
620 
621  QString name = KInputDialog::getText(contextText(StandardActionManager::CreateCollection, StandardActionManager::DialogTitle),
622  contextText(StandardActionManager::CreateCollection, StandardActionManager::DialogText),
623  QString(), 0, parentWidget);
624  name = name.trimmed();
625  if (name.isEmpty()) {
626  return;
627  }
628 
629  if (name.contains(QLatin1Char('/'))) {
630  KMessageBox::error(parentWidget,
631  i18n("We can not add \"/\" in folder name."),
632  i18n("Create new folder error"));
633  return;
634  }
635  if (name.startsWith(QLatin1Char('.')) ||
636  name.endsWith(QLatin1Char('.'))) {
637  KMessageBox::error(parentWidget,
638  i18n("We can not add \".\" at begin or end of folder name."),
639  i18n("Create new folder error"));
640  return;
641  }
642 
643  Collection collection;
644  collection.setName(name);
645  collection.setParentCollection(parentCollection);
646  if (actions[StandardActionManager::CreateCollection]) {
647  const QStringList mts = actions[StandardActionManager::CreateCollection]->property("ContentMimeTypes").toStringList();
648  if (!mts.isEmpty()) {
649  collection.setContentMimeTypes(mts);
650  }
651  }
652  if (parentCollection.contentMimeTypes().contains(Collection::virtualMimeType())) {
653  collection.setVirtual(true);
654  collection.setContentMimeTypes(collection.contentMimeTypes()
655  << Collection::virtualMimeType());
656  }
657 
658  CollectionCreateJob *job = new CollectionCreateJob(collection);
659  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(collectionCreationResult(KJob*)));
660  }
661 
662  void slotCopyCollections()
663  {
664  encodeToClipboard(collectionSelectionModel);
665  }
666 
667  void slotCutCollections()
668  {
669  encodeToClipboard(collectionSelectionModel, true);
670  }
671 
672  Collection::List selectedCollections()
673  {
674  Collection::List collections;
675 
676  Q_ASSERT(collectionSelectionModel);
677 
678  foreach (const QModelIndex &index, safeSelectedRows(collectionSelectionModel)) {
679  Q_ASSERT(index.isValid());
680  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
681  Q_ASSERT(collection.isValid());
682 
683  collections << collection;
684  }
685 
686  return collections;
687  }
688 
689  void slotDeleteCollection()
690  {
691  const Collection::List collections = selectedCollections();
692  if (collections.isEmpty()) {
693  return;
694  }
695 
696  const QString collectionName = collections.first().name();
697  const QString text = contextText(StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText,
698  collections.count(), collectionName);
699 
700  if (KMessageBox::questionYesNo(parentWidget, text,
701  contextText(StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, collections.count(), collectionName),
702  KStandardGuiItem::del(), KStandardGuiItem::cancel(),
703  QString(), KMessageBox::Dangerous) != KMessageBox::Yes) {
704  return;
705  }
706 
707  foreach (const Collection &collection, collections) {
708  CollectionDeleteJob *job = new CollectionDeleteJob(collection, q);
709  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(collectionDeletionResult(KJob*)));
710  }
711  }
712 
713  void slotMoveCollectionToTrash()
714  {
715  const Collection::List collections = selectedCollections();
716  if (collections.isEmpty()) {
717  return;
718  }
719 
720  foreach (const Collection &collection, collections) {
721  TrashJob *job = new TrashJob(collection, q);
722  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveCollectionToTrashResult(KJob*)));
723  }
724  }
725 
726  void slotRestoreCollectionFromTrash()
727  {
728  const Collection::List collections = selectedCollections();
729  if (collections.isEmpty()) {
730  return;
731  }
732 
733  foreach (const Collection &collection, collections) {
734  TrashRestoreJob *job = new TrashRestoreJob(collection, q);
735  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveCollectionToTrashResult(KJob*)));
736  }
737  }
738 
739  Item::List selectedItems() const
740  {
741  Item::List items;
742 
743  Q_ASSERT(itemSelectionModel);
744 
745  foreach (const QModelIndex &index, safeSelectedRows(itemSelectionModel)) {
746  Q_ASSERT(index.isValid());
747  const Item item = index.data(ItemModel::ItemRole).value<Item>();
748  Q_ASSERT(item.isValid());
749 
750  items << item;
751  }
752 
753  return items;
754  }
755 
756  void slotMoveItemToTrash()
757  {
758  const Item::List items = selectedItems();
759  if (items.isEmpty()) {
760  return;
761  }
762 
763  TrashJob *job = new TrashJob(items, q);
764  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveItemToTrashResult(KJob*)));
765  }
766 
767  void slotRestoreItemFromTrash()
768  {
769  const Item::List items = selectedItems();
770  if (items.isEmpty()) {
771  return;
772  }
773 
774  TrashRestoreJob *job = new TrashRestoreJob(items, q);
775  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveItemToTrashResult(KJob*)));
776  }
777 
778  void slotTrashRestoreCollection()
779  {
780  const Collection::List collections = selectedCollections();
781  if (collections.isEmpty()) {
782  return;
783  }
784 
785  bool collectionsAreInTrash = false;
786  foreach (const Collection &collection, collections) {
787  if (collection.hasAttribute<EntityDeletedAttribute>()) {
788  collectionsAreInTrash = true;
789  break;
790  }
791  }
792 
793  if (collectionsAreInTrash) {
794  slotRestoreCollectionFromTrash();
795  } else {
796  slotMoveCollectionToTrash();
797  }
798  }
799 
800  void slotTrashRestoreItem()
801  {
802  const Item::List items = selectedItems();
803  if (items.isEmpty()) {
804  return;
805  }
806 
807  bool itemsAreInTrash = false;
808  foreach (const Item &item, items) {
809  if (item.hasAttribute<EntityDeletedAttribute>()) {
810  itemsAreInTrash = true;
811  break;
812  }
813  }
814 
815  if (itemsAreInTrash) {
816  slotRestoreItemFromTrash();
817  } else {
818  slotMoveItemToTrash();
819  }
820  }
821 
822  void slotSynchronizeCollection()
823  {
824  Q_ASSERT(collectionSelectionModel);
825  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
826  if (list.isEmpty()) {
827  return;
828  }
829 
830  const Collection::List collections = selectedCollections();
831  if (collections.isEmpty()) {
832  return;
833  }
834 
835  foreach (const Collection &collection, collections) {
836  if (!testAndSetOnlineResources(collection)) {
837  break;
838  }
839  AgentManager::self()->synchronizeCollection(collection, false);
840  }
841  }
842 
843  bool testAndSetOnlineResources(const Akonadi::Collection &collection)
844  {
845  // Shortcut for the Search resource, which is a virtual resource and thus
846  // is awlays online (but AgentManager does not know about it, so it returns
847  // an invalid AgentInstance, which is "offline").
848  //
849  // FIXME: AgentManager should return a valid AgentInstance even
850  // for virtual resources, which would be always online.
851  if (collection.resource() == QLatin1String("akonadi_search_resource")) {
852  return true;
853  }
854 
855  Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance(collection.resource());
856  if (!instance.isOnline()) {
857  if (KMessageBox::questionYesNo(parentWidget,
858  i18n("Before syncing folder \"%1\" it is necessary to have the resource online. Do you want to make it online?", collection.displayName()),
859  i18n("Account \"%1\" is offline", instance.name()),
860  KGuiItem(i18nc("@action:button", "Go Online")), KStandardGuiItem::cancel()) != KMessageBox::Yes) {
861  return false;
862  }
863  instance.setIsOnline(true);
864  }
865  return true;
866  }
867 
868  void slotSynchronizeCollectionRecursive()
869  {
870  Q_ASSERT(collectionSelectionModel);
871  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
872  if (list.isEmpty()) {
873  return;
874  }
875 
876  const Collection::List collections = selectedCollections();
877  if (collections.isEmpty()) {
878  return;
879  }
880 
881  foreach (const Collection &collection, collections) {
882  if (!testAndSetOnlineResources(collection)) {
883  break;
884  }
885  AgentManager::self()->synchronizeCollection(collection, true);
886  }
887  }
888 
889  void slotCollectionProperties()
890  {
891  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
892  if (list.isEmpty()) {
893  return;
894  }
895 
896  const QModelIndex index = list.first();
897  Q_ASSERT(index.isValid());
898 
899  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
900  Q_ASSERT(collection.isValid());
901 
902  CollectionPropertiesDialog *dlg = new CollectionPropertiesDialog(collection, mCollectionPropertiesPageNames, parentWidget);
903  dlg->setCaption(contextText(StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle, collection.displayName()));
904  dlg->show();
905  }
906 
907  void slotCopyItems()
908  {
909  encodeToClipboard(itemSelectionModel);
910  }
911 
912  void slotCutItems()
913  {
914  encodeToClipboard(itemSelectionModel, true);
915  }
916 
917  void slotPaste()
918  {
919  Q_ASSERT(collectionSelectionModel);
920 
921  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
922  if (list.isEmpty()) {
923  return;
924  }
925 
926  const QModelIndex index = list.first();
927  Q_ASSERT(index.isValid());
928 
929 #ifndef QT_NO_CLIPBOARD
930  // TODO: Copy or move? We can't seem to cut yet
931  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(collectionSelectionModel->model());
932  const QMimeData *mimeData = QApplication::clipboard()->mimeData();
933  model->dropMimeData(mimeData, isCutAction(mimeData) ? Qt::MoveAction : Qt::CopyAction, -1, -1, index);
934  model->setData(QModelIndex(), false, EntityTreeModel::PendingCutRole);
935  QApplication::clipboard()->clear();
936 #endif
937  }
938 
939  void slotDeleteItems()
940  {
941  Q_ASSERT(itemSelectionModel);
942 
943  Item::List items;
944  foreach (const QModelIndex &index, safeSelectedRows(itemSelectionModel)) {
945  bool ok;
946  const qlonglong id = index.data(ItemModel::IdRole).toLongLong(&ok);
947  Q_ASSERT(ok);
948  items << Item(id);
949  }
950 
951  if (items.isEmpty()) {
952  return;
953  }
954 
955  QMetaObject::invokeMethod(q, "slotDeleteItemsDeferred",
956  Qt::QueuedConnection,
957  Q_ARG(Akonadi::Item::List, items));
958  }
959 
960  void slotDeleteItemsDeferred(const Akonadi::Item::List &items)
961  {
962  Q_ASSERT(itemSelectionModel);
963 
964  if (KMessageBox::questionYesNo(parentWidget,
965  contextText(StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, items.count(), QString()),
966  contextText(StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, items.count(), QString()),
967  KStandardGuiItem::del(), KStandardGuiItem::cancel(),
968  QString(), KMessageBox::Dangerous) != KMessageBox::Yes) {
969  return;
970  }
971 
972  ItemDeleteJob *job = new ItemDeleteJob(items, q);
973  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(itemDeletionResult(KJob*)));
974  }
975 
976  void slotLocalSubscription()
977  {
978  SubscriptionDialog *dlg = new SubscriptionDialog(mMimeTypeFilter, parentWidget);
979  dlg->showHiddenCollection(true);
980  dlg->show();
981  }
982 
983  void slotAddToFavorites()
984  {
985  Q_ASSERT(collectionSelectionModel);
986  Q_ASSERT(favoritesModel);
987  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
988  if (list.isEmpty()) {
989  return;
990  }
991 
992  foreach (const QModelIndex &index, list) {
993  Q_ASSERT(index.isValid());
994  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
995  Q_ASSERT(collection.isValid());
996 
997  favoritesModel->addCollection(collection);
998  }
999 
1000  updateActions();
1001  }
1002 
1003  void slotRemoveFromFavorites()
1004  {
1005  Q_ASSERT(collectionSelectionModel);
1006  Q_ASSERT(favoritesModel);
1007  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
1008  if (list.isEmpty()) {
1009  return;
1010  }
1011 
1012  foreach (const QModelIndex &index, list) {
1013  Q_ASSERT(index.isValid());
1014  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
1015  Q_ASSERT(collection.isValid());
1016 
1017  favoritesModel->removeCollection(collection);
1018  }
1019 
1020  updateActions();
1021  }
1022 
1023  void slotRenameFavorite()
1024  {
1025  Q_ASSERT(collectionSelectionModel);
1026  Q_ASSERT(favoritesModel);
1027  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
1028  if (list.isEmpty()) {
1029  return;
1030  }
1031  const QModelIndex index = list.first();
1032  Q_ASSERT(index.isValid());
1033  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
1034  Q_ASSERT(collection.isValid());
1035 
1036  QPointer<RenameFavoriteDialog> dlg(new RenameFavoriteDialog(contextText(StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle), contextText(StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText) , favoritesModel->favoriteLabel(collection), collection.displayName(), parentWidget));
1037  if (dlg->exec() == QDialog::Accepted && dlg != 0) {
1038  favoritesModel->setFavoriteLabel(collection, dlg->newName());
1039  }
1040  delete dlg;
1041  }
1042 
1043  void slotSynchronizeFavoriteCollections()
1044  {
1045  Q_ASSERT(favoritesModel);
1046  foreach (const Collection &collection, favoritesModel->collections()) {
1047  // there might be virtual collections in favorites which cannot be checked
1048  // so let's be safe here, agentmanager asserts otherwise
1049  if (!collection.resource().isEmpty()) {
1050  AgentManager::self()->synchronizeCollection(collection, false);
1051  }
1052  }
1053  }
1054 
1055  void slotCopyCollectionTo()
1056  {
1057  pasteTo(collectionSelectionModel, collectionSelectionModel->model(), CopyCollectionToMenu, Qt::CopyAction);
1058  }
1059 
1060  void slotCopyItemTo()
1061  {
1062  pasteTo(itemSelectionModel, collectionSelectionModel->model(), CopyItemToMenu, Qt::CopyAction);
1063  }
1064 
1065  void slotMoveCollectionTo()
1066  {
1067  pasteTo(collectionSelectionModel, collectionSelectionModel->model(), MoveCollectionToMenu, Qt::MoveAction);
1068  }
1069 
1070  void slotMoveItemTo()
1071  {
1072  pasteTo(itemSelectionModel, collectionSelectionModel->model(), MoveItemToMenu, Qt::MoveAction);
1073  }
1074 
1075  void slotCopyCollectionTo(QAction *action)
1076  {
1077  pasteTo(collectionSelectionModel, action, Qt::CopyAction);
1078  }
1079 
1080  void slotCopyItemTo(QAction *action)
1081  {
1082  pasteTo(itemSelectionModel, action, Qt::CopyAction);
1083  }
1084 
1085  void slotMoveCollectionTo(QAction *action)
1086  {
1087  pasteTo(collectionSelectionModel, action, Qt::MoveAction);
1088  }
1089 
1090  void slotMoveItemTo(QAction *action)
1091  {
1092  pasteTo(itemSelectionModel, action, Qt::MoveAction);
1093  }
1094 
1095  AgentInstance::List selectedAgentInstances() const
1096  {
1097  AgentInstance::List instances;
1098 
1099  Q_ASSERT(collectionSelectionModel);
1100  if (collectionSelectionModel->selection().indexes().isEmpty()) {
1101  return instances;
1102  }
1103 
1104  foreach (const QModelIndex &index, collectionSelectionModel->selection().indexes()) {
1105  Q_ASSERT(index.isValid());
1106  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
1107  Q_ASSERT(collection.isValid());
1108 
1109  if (collection.isValid()) {
1110  const QString identifier = collection.resource();
1111  instances << AgentManager::self()->instance(identifier);
1112  }
1113  }
1114 
1115  return instances;
1116  }
1117 
1118  AgentInstance selectedAgentInstance() const
1119  {
1120  const AgentInstance::List instances = selectedAgentInstances();
1121 
1122  if (instances.isEmpty()) {
1123  return AgentInstance();
1124  }
1125 
1126  return instances.first();
1127  }
1128 
1129  void slotCreateResource()
1130  {
1131  QPointer<Akonadi::AgentTypeDialog> dlg(new Akonadi::AgentTypeDialog(parentWidget));
1132  dlg->setCaption(contextText(StandardActionManager::CreateResource, StandardActionManager::DialogTitle));
1133 
1134  foreach (const QString &mimeType, mMimeTypeFilter) {
1135  dlg->agentFilterProxyModel()->addMimeTypeFilter(mimeType);
1136  }
1137 
1138  foreach (const QString &capability, mCapabilityFilter) {
1139  dlg->agentFilterProxyModel()->addCapabilityFilter(capability);
1140  }
1141 
1142  if (dlg->exec() == QDialog::Accepted && dlg != 0) {
1143  const AgentType agentType = dlg->agentType();
1144 
1145  if (agentType.isValid()) {
1146  AgentInstanceCreateJob *job = new AgentInstanceCreateJob(agentType, q);
1147  q->connect(job, SIGNAL(result(KJob*)), SLOT(resourceCreationResult(KJob*)));
1148  job->configure(parentWidget);
1149  job->start();
1150  }
1151  }
1152  delete dlg;
1153  }
1154 
1155  void slotDeleteResource()
1156  {
1157  const AgentInstance::List instances = selectedAgentInstances();
1158  if (instances.isEmpty()) {
1159  return;
1160  }
1161 
1162  if (KMessageBox::questionYesNo(parentWidget,
1163  contextText(StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, instances.count(), instances.first().name()),
1164  contextText(StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, instances.count(), instances.first().name()),
1165  KStandardGuiItem::del(), KStandardGuiItem::cancel(),
1166  QString(), KMessageBox::Dangerous) != KMessageBox::Yes) {
1167  return;
1168  }
1169 
1170  foreach (const AgentInstance &instance, instances) {
1171  AgentManager::self()->removeInstance(instance);
1172  }
1173  }
1174 
1175  void slotSynchronizeResource()
1176  {
1177  const AgentInstance::List instances = selectedAgentInstances();
1178  if (instances.isEmpty()) {
1179  return;
1180  }
1181 
1182  foreach (AgentInstance instance, instances) { //krazy:exclude=foreach
1183  instance.synchronize();
1184  }
1185  }
1186 
1187  void slotResourceProperties()
1188  {
1189  AgentInstance instance = selectedAgentInstance();
1190  if (!instance.isValid()) {
1191  return;
1192  }
1193 
1194  instance.configure(parentWidget);
1195  }
1196 
1197  void slotToggleWorkOffline(bool offline)
1198  {
1199  setWorkOffline(offline);
1200 
1201  AgentInstance::List instances = AgentManager::self()->instances();
1202  foreach (AgentInstance instance, instances) { //krazy:exclude=foreach
1203  instance.setIsOnline(!offline);
1204  }
1205  }
1206 
1207  void pasteTo(QItemSelectionModel *selectionModel, const QAbstractItemModel *model, StandardActionManager::Type type, Qt::DropAction dropAction)
1208  {
1209  const QSet<QString> mimeTypes = mimeTypesOfSelection(type);
1210 
1211  QPointer<CollectionDialog> dlg(new CollectionDialog(const_cast<QAbstractItemModel *>(model)));
1212  dlg->setMimeTypeFilter(mimeTypes.toList());
1213 
1214  if (type == CopyItemToMenu || type == MoveItemToMenu) {
1215  dlg->setAccessRightsFilter(Collection::CanCreateItem);
1216  } else if (type == CopyCollectionToMenu || type == MoveCollectionToMenu) {
1217  dlg->setAccessRightsFilter(Collection::CanCreateCollection);
1218  }
1219 
1220  if (dlg->exec() == QDialog::Accepted && dlg != 0) {
1221  const QModelIndex index = EntityTreeModel::modelIndexForCollection(collectionSelectionModel->model(), dlg->selectedCollection());
1222  if (!index.isValid()) {
1223  return;
1224  }
1225 
1226  const QMimeData *mimeData = selectionModel->model()->mimeData(safeSelectedRows(selectionModel));
1227 
1228  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(index.model());
1229  model->dropMimeData(mimeData, dropAction, -1, -1, index);
1230  }
1231  delete dlg;
1232  }
1233 
1234  void pasteTo(QItemSelectionModel *selectionModel, QAction *action, Qt::DropAction dropAction)
1235  {
1236  Q_ASSERT(selectionModel);
1237  Q_ASSERT(action);
1238 
1239  if (safeSelectedRows(selectionModel).count() <= 0) {
1240  return;
1241  }
1242 
1243  const QMimeData *mimeData = selectionModel->model()->mimeData(selectionModel->selectedRows());
1244 
1245  const QModelIndex index = action->data().value<QModelIndex>();
1246  Q_ASSERT(index.isValid());
1247 
1248  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(index.model());
1249  const Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
1250  addRecentCollection(collection.id());
1251  model->dropMimeData(mimeData, dropAction, -1, -1, index);
1252  }
1253 
1254  void addRecentCollection(Akonadi::Collection::Id id)
1255  {
1256  QMapIterator<StandardActionManager::Type, QWeakPointer<RecentCollectionAction> > item(mRecentCollectionsMenu);
1257  while (item.hasNext()) {
1258  item.next();
1259  if (item.value().data()) {
1260  item.value().data()->addRecentCollection(item.key(),id);
1261  }
1262  }
1263  }
1264 
1265  void collectionCreationResult(KJob *job)
1266  {
1267  if (job->error()) {
1268  KMessageBox::error(parentWidget,
1269  contextText(StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText, job->errorString()),
1270  contextText(StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle));
1271  }
1272  }
1273 
1274  void collectionDeletionResult(KJob *job)
1275  {
1276  if (job->error()) {
1277  KMessageBox::error(parentWidget,
1278  contextText(StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText, job->errorString()),
1279  contextText(StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle));
1280  }
1281  }
1282 
1283  void moveCollectionToTrashResult(KJob *job)
1284  {
1285  if (job->error()) {
1286  KMessageBox::error(parentWidget,
1287  contextText(StandardActionManager::MoveCollectionsToTrash, StandardActionManager::ErrorMessageText, job->errorString()),
1288  contextText(StandardActionManager::MoveCollectionsToTrash, StandardActionManager::ErrorMessageTitle));
1289  }
1290  }
1291 
1292  void moveItemToTrashResult(KJob *job)
1293  {
1294  if (job->error()) {
1295  KMessageBox::error(parentWidget,
1296  contextText(StandardActionManager::MoveItemsToTrash, StandardActionManager::ErrorMessageText, job->errorString()),
1297  contextText(StandardActionManager::MoveItemsToTrash, StandardActionManager::ErrorMessageTitle));
1298  }
1299  }
1300 
1301  void itemDeletionResult(KJob *job)
1302  {
1303  if (job->error()) {
1304  KMessageBox::error(parentWidget,
1305  contextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText, job->errorString()),
1306  contextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle));
1307  }
1308  }
1309 
1310  void resourceCreationResult(KJob *job)
1311  {
1312  if (job->error()) {
1313  KMessageBox::error(parentWidget,
1314  contextText(StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText, job->errorString()),
1315  contextText(StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle));
1316  }
1317  }
1318 
1319  void pasteResult(KJob *job)
1320  {
1321  if (job->error()) {
1322  KMessageBox::error(parentWidget,
1323  contextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageText, job->errorString()),
1324  contextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle));
1325  }
1326  }
1327 
1331  QSet<QString> mimeTypesOfSelection(StandardActionManager::Type type) const
1332  {
1333  QModelIndexList list;
1334  QSet<QString> mimeTypes;
1335 
1336  const bool isItemAction = (type == CopyItemToMenu || type == MoveItemToMenu);
1337  const bool isCollectionAction = (type == CopyCollectionToMenu || type == MoveCollectionToMenu);
1338 
1339  if (isItemAction) {
1340  list = safeSelectedRows(itemSelectionModel);
1341  foreach (const QModelIndex &index, list) {
1342  mimeTypes << index.data(EntityTreeModel::MimeTypeRole).toString();
1343  }
1344  }
1345 
1346  if (isCollectionAction) {
1347  list = safeSelectedRows(collectionSelectionModel);
1348  foreach (const QModelIndex &index, list) {
1349  const Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
1350 
1351  // The mimetypes that the selected collection can possibly contain
1352  mimeTypes = AgentManager::self()->instance(collection.resource()).type().mimeTypes().toSet();
1353  }
1354  }
1355 
1356  return mimeTypes;
1357  }
1358 
1362  bool isWritableTargetCollectionForMimeTypes(const Collection &collection, const QSet<QString> &mimeTypes, StandardActionManager::Type type) const
1363  {
1364  if (collection.isVirtual()) {
1365  return false;
1366  }
1367 
1368  const bool isItemAction = (type == CopyItemToMenu || type == MoveItemToMenu);
1369  const bool isCollectionAction = (type == CopyCollectionToMenu || type == MoveCollectionToMenu);
1370 
1371  const bool canContainRequiredMimeTypes = !collection.contentMimeTypes().toSet().intersect(mimeTypes).isEmpty();
1372  const bool canCreateNewItems = (collection.rights() & Collection::CanCreateItem);
1373 
1374  const bool canCreateNewCollections = (collection.rights() & Collection::CanCreateCollection);
1375  const bool canContainCollections = collection.contentMimeTypes().contains(Collection::mimeType()) || collection.contentMimeTypes().contains(Collection::virtualMimeType());
1376  const bool resourceAllowsRequiredMimeTypes = AgentManager::self()->instance(collection.resource()).type().mimeTypes().toSet().contains(mimeTypes);
1377 
1378  const bool isReadOnlyForItems = (isItemAction && (!canCreateNewItems || !canContainRequiredMimeTypes));
1379  const bool isReadOnlyForCollections = (isCollectionAction && (!canCreateNewCollections || !canContainCollections || !resourceAllowsRequiredMimeTypes));
1380 
1381  return !(CollectionUtils::isStructural(collection) || isReadOnlyForItems || isReadOnlyForCollections);
1382  }
1383 
1384  void fillFoldersMenu(const Akonadi::Collection::List &selectedCollectionsList, const QSet<QString> &mimeTypes, StandardActionManager::Type type, QMenu *menu,
1385  const QAbstractItemModel *model, QModelIndex parentIndex)
1386  {
1387  const int rowCount = model->rowCount(parentIndex);
1388 
1389  for (int row = 0; row < rowCount; ++row) {
1390  const QModelIndex index = model->index(row, 0, parentIndex);
1391  const Collection collection = model->data(index, CollectionModel::CollectionRole).value<Collection>();
1392 
1393  if (collection.isVirtual()) {
1394  continue;
1395  }
1396 
1397  const bool readOnly = !isWritableTargetCollectionForMimeTypes( collection, mimeTypes, type );
1398  const bool collectionIsSelected = selectedCollectionsList.contains( collection );
1399  if (type == MoveCollectionToMenu && collectionIsSelected) {
1400  continue;
1401  }
1402 
1403  QString label = model->data(index).toString();
1404  label.replace(QLatin1String("&"), QLatin1String("&&"));
1405 
1406  const QIcon icon = model->data(index, Qt::DecorationRole).value<QIcon>();
1407 
1408  if (model->rowCount(index) > 0) {
1409  // new level
1410  QMenu *popup = new QMenu(menu);
1411  const bool moveAction = (type == MoveCollectionToMenu || type == MoveItemToMenu);
1412  popup->setObjectName(QString::fromUtf8("subMenu"));
1413  popup->setTitle(label);
1414  popup->setIcon(icon);
1415 
1416  fillFoldersMenu(selectedCollectionsList, mimeTypes, type, popup, model, index);
1417 
1418  if (!(type == CopyCollectionToMenu && collectionIsSelected)) {
1419  if ( !readOnly ) {
1420  popup->addSeparator();
1421 
1422  QAction *action = popup->addAction( moveAction ? i18n( "Move to This Folder" ) : i18n( "Copy to This Folder" ) );
1423  action->setData( QVariant::fromValue<QModelIndex>( index ) );
1424  }
1425  }
1426 
1427  menu->addMenu(popup);
1428 
1429  } else {
1430  // insert an item
1431  QAction *action = menu->addAction(icon, label);
1432  action->setData(QVariant::fromValue<QModelIndex>(index));
1433  action->setEnabled(!readOnly && !collectionIsSelected);
1434  }
1435  }
1436  }
1437 
1438  void checkModelsConsistency()
1439  {
1440  if (favoritesModel == 0 || favoriteSelectionModel == 0) {
1441  // No need to check when the favorite collections feature is not used
1442  return;
1443  }
1444 
1445  // find the base ETM of the favourites view
1446  const QAbstractItemModel *favModel = favoritesModel;
1447  while (const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(favModel)) {
1448  favModel = proxy->sourceModel();
1449  }
1450 
1451  // Check that the collection selection model maps to the same
1452  // EntityTreeModel than favoritesModel
1453  if (collectionSelectionModel != 0) {
1454  const QAbstractItemModel *model = collectionSelectionModel->model();
1455  while (const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model)) {
1456  model = proxy->sourceModel();
1457  }
1458 
1459  Q_ASSERT(model == favModel);
1460  }
1461 
1462  // Check that the favorite selection model maps to favoritesModel
1463  const QAbstractItemModel *model = favoriteSelectionModel->model();
1464  while (const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model)) {
1465  model = proxy->sourceModel();
1466  }
1467  Q_ASSERT(model == favModel);
1468  }
1469 
1470  void markCutAction(QMimeData *mimeData, bool cut) const
1471  {
1472  if (!cut) {
1473  return;
1474  }
1475 
1476  const QByteArray cutSelectionData = "1"; //krazy:exclude=doublequote_chars
1477  mimeData->setData(QLatin1String("application/x-kde.akonadi-cutselection"), cutSelectionData);
1478  }
1479 
1480  bool isCutAction(const QMimeData *mimeData) const
1481  {
1482  const QByteArray data = mimeData->data(QLatin1String("application/x-kde.akonadi-cutselection"));
1483  if (data.isEmpty()) {
1484  return false;
1485  } else {
1486  return (data.at(0) == '1'); // true if 1
1487  }
1488  }
1489 
1490  void setContextText(StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &data)
1491  {
1492  ContextTextEntry entry;
1493  entry.text = data;
1494 
1495  contextTexts[type].insert(context, entry);
1496  }
1497 
1498  void setContextText(StandardActionManager::Type type, StandardActionManager::TextContext context, const KLocalizedString &data)
1499  {
1500  ContextTextEntry entry;
1501  entry.localizedText = data;
1502 
1503  contextTexts[type].insert(context, entry);
1504  }
1505 
1506  QString contextText(StandardActionManager::Type type, StandardActionManager::TextContext context) const
1507  {
1508  return contextTexts[type].value(context).text;
1509  }
1510 
1511  QString contextText(StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &value) const
1512  {
1513  KLocalizedString text = contextTexts[type].value(context).localizedText;
1514  if (text.isEmpty()) {
1515  return contextTexts[type].value(context).text;
1516  }
1517 
1518  return text.subs(value).toString();
1519  }
1520 
1521  QString contextText(StandardActionManager::Type type, StandardActionManager::TextContext context, int count, const QString &value) const
1522  {
1523  KLocalizedString text = contextTexts[type].value(context).localizedText;
1524  if (text.isEmpty()) {
1525  return contextTexts[type].value(context).text;
1526  }
1527 
1528  const QString str = text.subs(count).toString();
1529  const int argCount = str.count(QRegExp(QLatin1String("%[0-9]")));
1530  if (argCount > 0) {
1531  return text.subs(count).subs(value).toString();
1532  } else {
1533  return text.subs(count).toString();
1534  }
1535  }
1536 
1537  StandardActionManager *q;
1538  KActionCollection *actionCollection;
1539  QWidget *parentWidget;
1540  QItemSelectionModel *collectionSelectionModel;
1541  QItemSelectionModel *itemSelectionModel;
1542  FavoriteCollectionsModel *favoritesModel;
1543  QItemSelectionModel *favoriteSelectionModel;
1544  bool insideSelectionSlot;
1545  QVector<KAction *> actions;
1546  QHash<StandardActionManager::Type, KLocalizedString> pluralLabels;
1547  QHash<StandardActionManager::Type, KLocalizedString> pluralIconLabels;
1548 
1549  struct ContextTextEntry
1550  {
1551  QString text;
1552  KLocalizedString localizedText;
1553  bool isLocalized;
1554  };
1555 
1556  typedef QHash<StandardActionManager::TextContext, ContextTextEntry> ContextTexts;
1557  QHash<StandardActionManager::Type, ContextTexts> contextTexts;
1558 
1559  ActionStateManager mActionStateManager;
1560 
1561  QStringList mMimeTypeFilter;
1562  QStringList mCapabilityFilter;
1563  QStringList mCollectionPropertiesPageNames;
1564  QMap<StandardActionManager::Type, QWeakPointer<RecentCollectionAction> > mRecentCollectionsMenu;
1565 };
1566 
1567 //@endcond
1568 
1569 StandardActionManager::StandardActionManager(KActionCollection *actionCollection, QWidget *parent)
1570  : QObject(parent)
1571  , d(new Private(this))
1572 {
1573  d->parentWidget = parent;
1574  d->actionCollection = actionCollection;
1575  d->mActionStateManager.setReceiver(this);
1576 #ifndef QT_NO_CLIPBOARD
1577  connect(QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)), SLOT(clipboardChanged(QClipboard::Mode)));
1578 #endif
1579 }
1580 
1581 StandardActionManager::~ StandardActionManager()
1582 {
1583  delete d;
1584 }
1585 
1586 void StandardActionManager::setCollectionSelectionModel(QItemSelectionModel *selectionModel)
1587 {
1588  d->collectionSelectionModel = selectionModel;
1589  connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1590  SLOT(collectionSelectionChanged()));
1591 
1592  d->checkModelsConsistency();
1593 }
1594 
1595 void StandardActionManager::setItemSelectionModel(QItemSelectionModel *selectionModel)
1596 {
1597  d->itemSelectionModel = selectionModel;
1598  connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1599  SLOT(updateActions()));
1600 }
1601 
1602 void StandardActionManager::setFavoriteCollectionsModel(FavoriteCollectionsModel *favoritesModel)
1603 {
1604  d->favoritesModel = favoritesModel;
1605  d->checkModelsConsistency();
1606 }
1607 
1608 void StandardActionManager::setFavoriteSelectionModel(QItemSelectionModel *selectionModel)
1609 {
1610  d->favoriteSelectionModel = selectionModel;
1611  connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1612  SLOT(favoriteSelectionChanged()));
1613  d->checkModelsConsistency();
1614 }
1615 
1616 KAction *StandardActionManager::createAction(Type type)
1617 {
1618  Q_ASSERT(type < LastType);
1619  if (d->actions[type]) {
1620  return d->actions[type];
1621  }
1622  KAction *action = 0;
1623  switch (standardActionData[type].actionType) {
1624  case NormalAction:
1625  case ActionWithAlternative:
1626  action = new KAction(d->parentWidget);
1627  break;
1628  case ActionAlternative:
1629  d->actions[type] = d->actions[type - 1];
1630  Q_ASSERT(d->actions[type]);
1631  if ((LastType > type + 1) && (standardActionData[type + 1].actionType == ActionAlternative)) {
1632  createAction(static_cast<Type>(type + 1)); //ensure that alternative actions are initialized when not created by createAllActions
1633  }
1634  return d->actions[type];
1635  case MenuAction:
1636  action = new KActionMenu(d->parentWidget);
1637  break;
1638  case ToggleAction:
1639  action = new KToggleAction(d->parentWidget);
1640  break;
1641  }
1642 
1643  if (d->pluralLabels.contains(type) && !d->pluralLabels.value(type).isEmpty()) {
1644  action->setText(d->pluralLabels.value(type).subs(1).toString());
1645  } else if (standardActionData[type].label) {
1646  action->setText(i18n(standardActionData[type].label));
1647  }
1648 
1649  if (d->pluralIconLabels.contains(type) && !d->pluralIconLabels.value(type).isEmpty()) {
1650  action->setIconText(d->pluralIconLabels.value(type).subs(1).toString());
1651  } else if (standardActionData[type].iconLabel) {
1652  action->setIconText(i18n(standardActionData[type].iconLabel));
1653  }
1654 
1655  if (standardActionData[type].icon) {
1656  action->setIcon(KIcon(QString::fromLatin1(standardActionData[type].icon)));
1657  }
1658 
1659  action->setShortcut(standardActionData[type].shortcut);
1660 
1661  if (standardActionData[type].slot) {
1662  switch (standardActionData[type].actionType) {
1663  case NormalAction:
1664  case ActionWithAlternative:
1665  connect(action, SIGNAL(triggered()), standardActionData[type].slot);
1666  break;
1667  case MenuAction: {
1668  KActionMenu *actionMenu = qobject_cast<KActionMenu *>(action);
1669  connect(actionMenu->menu(), SIGNAL(triggered(QAction*)), standardActionData[type].slot);
1670  break;
1671  }
1672  case ToggleAction: {
1673  connect(action, SIGNAL(triggered(bool)), standardActionData[type].slot);
1674  break;
1675  }
1676  case ActionAlternative:
1677  Q_ASSERT(0);
1678  }
1679  }
1680 
1681  if (type == ToggleWorkOffline) {
1682  // inititalize the action state with information from config file
1683  disconnect(action, SIGNAL(triggered(bool)), this, standardActionData[type].slot);
1684  action->setChecked(workOffline());
1685  connect(action, SIGNAL(triggered(bool)), this, standardActionData[type].slot);
1686 
1687  //TODO: find a way to check for updates to the config file
1688  }
1689 
1690  Q_ASSERT(standardActionData[type].name);
1691  d->actionCollection->addAction(QString::fromLatin1(standardActionData[type].name), action);
1692  d->actions[type] = action;
1693  if ((standardActionData[type].actionType == ActionWithAlternative) && (standardActionData[type + 1].actionType == ActionAlternative)) {
1694  createAction(static_cast<Type>(type + 1)); //ensure that alternative actions are initialized when not created by createAllActions
1695  }
1696  d->updateActions();
1697  return action;
1698 }
1699 
1700 void StandardActionManager::createAllActions()
1701 {
1702  for (uint i = 0; i < LastType; ++i) {
1703  createAction((Type)i);
1704  }
1705 }
1706 
1707 KAction *StandardActionManager::action(Type type) const
1708 {
1709  Q_ASSERT(type < LastType);
1710  return d->actions[type];
1711 }
1712 
1713 void StandardActionManager::setActionText(Type type, const KLocalizedString &text)
1714 {
1715  Q_ASSERT(type < LastType);
1716  d->pluralLabels.insert(type, text);
1717  d->updateActions();
1718 }
1719 
1720 void StandardActionManager::interceptAction(Type type, bool intercept)
1721 {
1722  Q_ASSERT(type < LastType);
1723 
1724  const KAction *action = d->actions[type];
1725 
1726  if (!action) {
1727  return;
1728  }
1729 
1730  if (intercept) {
1731  disconnect(action, SIGNAL(triggered()), this, standardActionData[type].slot);
1732  } else {
1733  connect(action, SIGNAL(triggered()), standardActionData[type].slot);
1734  }
1735 }
1736 
1737 Akonadi::Collection::List StandardActionManager::selectedCollections() const
1738 {
1739  Collection::List collections;
1740 
1741  if (!d->collectionSelectionModel) {
1742  return collections;
1743  }
1744 
1745  foreach (const QModelIndex &index, safeSelectedRows(d->collectionSelectionModel)) {
1746  const Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
1747  if (collection.isValid()) {
1748  collections << collection;
1749  }
1750  }
1751 
1752  return collections;
1753 }
1754 
1755 Item::List StandardActionManager::selectedItems() const
1756 {
1757  Item::List items;
1758 
1759  if (!d->itemSelectionModel) {
1760  return items;
1761  }
1762 
1763  foreach (const QModelIndex &index, safeSelectedRows(d->itemSelectionModel)) {
1764  const Item item = index.data(EntityTreeModel::ItemRole).value<Item>();
1765  if (item.isValid()) {
1766  items << item;
1767  }
1768  }
1769 
1770  return items;
1771 }
1772 
1773 void StandardActionManager::setContextText(Type type, TextContext context, const QString &text)
1774 {
1775  d->setContextText(type, context, text);
1776 }
1777 
1778 void StandardActionManager::setContextText(Type type, TextContext context, const KLocalizedString &text)
1779 {
1780  d->setContextText(type, context, text);
1781 }
1782 
1783 void StandardActionManager::setMimeTypeFilter(const QStringList &mimeTypes)
1784 {
1785  d->mMimeTypeFilter = mimeTypes;
1786 }
1787 
1788 void StandardActionManager::setCapabilityFilter(const QStringList &capabilities)
1789 {
1790  d->mCapabilityFilter = capabilities;
1791 }
1792 
1793 void StandardActionManager::setCollectionPropertiesPageNames(const QStringList &names)
1794 {
1795  d->mCollectionPropertiesPageNames = names;
1796 }
1797 
1798 void StandardActionManager::createActionFolderMenu(QMenu *menu, Type type)
1799 {
1800  d->createActionFolderMenu(menu, type);
1801 }
1802 
1803 #include "moc_standardactionmanager.cpp"
Akonadi::StandardActionManager::Type
Type
Describes the supported actions.
Definition: standardactionmanager.h:133
Akonadi::StandardActionManager::MoveItemsToTrash
Moves the selected items to trash and marks them as deleted, needs EntityDeletedAttribute.
Definition: standardactionmanager.h:163
Akonadi::StandardActionManager::TextContext
TextContext
Describes the text context that can be customized.
Definition: standardactionmanager.h:177
Akonadi::AgentInstance::configure
void configure(QWidget *parent=0)
Triggers the agent instance to show its configuration dialog.
Definition: agentinstance.cpp:105
Akonadi::AgentManager::synchronizeCollection
void synchronizeCollection(const Collection &collection)
Trigger a synchronization of the given collection by its owning resource agent.
Definition: agentmanager.cpp:415
Akonadi::StandardActionManager::setCapabilityFilter
void setCapabilityFilter(const QStringList &capabilities)
Sets the capability filter that will be used when creating new resources.
Akonadi::StandardActionManager::MoveItemToMenu
Menu allowing to move item into a collection.
Definition: standardactionmanager.h:148
Akonadi::AgentInstance::List
QList< AgentInstance > List
Describes a list of agent instances.
Definition: agentinstance.h:71
Akonadi::AgentManager::instances
AgentInstance::List instances() const
Returns the list of all available agent instances.
Definition: agentmanager.cpp:400
Akonadi::StandardActionManager::CreateCollection
Creates an collection.
Definition: standardactionmanager.h:134
Akonadi::StandardActionManager::MoveCollectionsToTrash
Moves the selected collection to trash and marks it as deleted, needs EntityDeletedAttribute.
Definition: standardactionmanager.h:162
Akonadi::StandardActionManager::ErrorMessageTitle
The window title of an error message.
Definition: standardactionmanager.h:183
Akonadi::Collection::displayName
QString displayName() const
Returns the display name (EntityDisplayAttribute::displayName()) if set, and Collection::name() other...
Definition: collection.cpp:86
Akonadi::StandardActionManager::CopyItems
Copies the selected items.
Definition: standardactionmanager.h:139
Akonadi::StandardActionManager::setCollectionSelectionModel
void setCollectionSelectionModel(QItemSelectionModel *selectionModel)
Sets the collection selection model based on which the collection related actions should operate...
Akonadi::StandardActionManager::createActionFolderMenu
void createActionFolderMenu(QMenu *menu, Type type)
Create a popup menu.
Akonadi::StandardActionManager::setMimeTypeFilter
void setMimeTypeFilter(const QStringList &mimeTypes)
Sets the mime type filter that will be used when creating new resources.
Akonadi::StandardActionManager
Manages generic actions for collection and item views.
Definition: standardactionmanager.h:126
Akonadi::CollectionDialog
A collection selection dialog.
Definition: collectiondialog.h:67
Akonadi::AgentInstance::synchronize
void synchronize()
Triggers the agent instance to start synchronization.
Definition: agentinstance.cpp:110
Akonadi::AgentInstanceCreateJob::configure
void configure(QWidget *parent=0)
Setup the job to show agent configuration dialog once the agent instance has been successfully starte...
Definition: agentinstancecreatejob.cpp:165
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::StandardActionManager::setFavoriteCollectionsModel
void setFavoriteCollectionsModel(FavoriteCollectionsModel *favoritesModel)
Sets the favorite collections model based on which the collection relatedactions should operate...
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition: entity.h:65
Akonadi::Collection::virtualMimeType
static QString virtualMimeType()
Returns the mimetype used for virtual collections.
Definition: collection.cpp:202
Akonadi::StandardActionManager::CutItems
Cuts the selected items.
Definition: standardactionmanager.h:150
Akonadi::StandardActionManager::setItemSelectionModel
void setItemSelectionModel(QItemSelectionModel *selectionModel)
Sets the item selection model based on which the item related actions should operate.
Akonadi::StandardActionManager::selectedItems
Akonadi::Item::List selectedItems() const
Returns the list of items that are currently selected.
Akonadi::AgentType::isValid
bool isValid() const
Returns whether the agent type is valid.
Definition: agenttype.cpp:41
Akonadi::Collection::mimeType
static QString mimeType()
Returns the mimetype used for collections.
Definition: collection.cpp:197
Akonadi::Collection::CanCreateCollection
Can create new subcollections in this collection.
Definition: collection.h:92
Akonadi::AgentManager::removeInstance
void removeInstance(const AgentInstance &instance)
Removes the given agent instance.
Definition: agentmanager.cpp:410
Akonadi::Entity::setParentCollection
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition: entity.cpp:196
Akonadi::StandardActionManager::action
KAction * action(Type type) const
Returns the action of the given type, 0 if it has not been created (yet).
Akonadi::Collection::setName
void setName(const QString &name)
Sets the i18n'ed name of the collection.
Definition: collection.cpp:93
Akonadi::SubscriptionDialog
Definition: subscriptiondialog_p.h:34
Akonadi::StandardActionManager::ToggleWorkOffline
Toggles the work offline state of all resources.
Definition: standardactionmanager.h:156
Akonadi::ItemDeleteJob
Job that deletes items from the Akonadi storage.
Definition: itemdeletejob.h:62
Akonadi::StandardActionManager::Paste
Paste collections or items.
Definition: standardactionmanager.h:140
Akonadi::Collection::setVirtual
void setVirtual(bool isVirtual)
Sets whether the collection is virtual or not.
Definition: collection.cpp:266
Akonadi::AgentType
A representation of an agent type.
Definition: agenttype.h:58
Akonadi::StandardActionManager::interceptAction
void interceptAction(Type type, bool intercept=true)
Sets whether the default implementation for the given action type shall be executed when the action i...
Akonadi::StandardActionManager::createAction
KAction * createAction(Type type)
Creates the action of the given type and adds it to the action collection specified in the constructo...
Akonadi::StandardActionManager::CollectionProperties
Provides collection properties.
Definition: standardactionmanager.h:138
Akonadi::AgentManager::instance
AgentInstance instance(const QString &identifier) const
Returns the agent instance with the given identifier or an invalid agent instance if the identifier d...
Definition: agentmanager.cpp:405
Akonadi::ItemModel::IdRole
The id of the item.
Definition: itemmodel.h:74
Akonadi::SubscriptionDialog::showHiddenCollection
void showHiddenCollection(bool showHidden)
Definition: subscriptiondialog.cpp:186
Akonadi::AgentInstance::setIsOnline
void setIsOnline(bool online)
Sets online status of the agent instance.
Definition: agentinstance.cpp:100
Akonadi::StandardActionManager::setActionText
void setActionText(Type type, const KLocalizedString &text)
Sets the label of the action type to text, which is used during updating the action state and substit...
Akonadi::AgentInstance::isValid
bool isValid() const
Returns whether the agent instance object is valid.
Definition: agentinstance.cpp:45
Akonadi::StandardActionManager::MessageBoxTitle
The window title of a message box.
Definition: standardactionmanager.h:180
Akonadi::AgentInstance::isOnline
bool isOnline() const
Returns whether the agent instance is online currently.
Definition: agentinstance.cpp:95
Akonadi::StandardActionManager::selectedCollections
Akonadi::Collection::List selectedCollections() const
Returns the list of collections that are currently selected.
Akonadi::Collection::CanCreateItem
Can create new items in this collection.
Definition: collection.h:89
Akonadi::StandardActionManager::createAllActions
void createAllActions()
Convenience method to create all standard actions.
Akonadi::StandardActionManager::CopyCollectionToMenu
Menu allowing to quickly copy a collection into another collection.
Definition: standardactionmanager.h:146
Akonadi::CollectionDeleteJob
Job that deletes a collection in the Akonadi storage.
Definition: collectiondeletejob.h:63
Akonadi::EntityTreeModel::CollectionRole
The collection.
Definition: entitytreemodel.h:336
Akonadi::EntityTreeModel::ParentCollectionRole
The parent collection of the entity.
Definition: entitytreemodel.h:341
Akonadi::TrashRestoreJob
Job that restores entites from trash.
Definition: trashrestorejob.h:56
Akonadi::Entity::id
Id id() const
Returns the unique identifier of the entity.
Definition: entity.cpp:72
Akonadi::StandardActionManager::~StandardActionManager
~StandardActionManager()
Destroys the standard action manager.
Akonadi::Collection::rights
Rights rights() const
Returns the rights the user has on the collection.
Definition: collection.cpp:99
Akonadi::EntityTreeModel::modelIndexForCollection
static QModelIndex modelIndexForCollection(const QAbstractItemModel *model, const Collection &collection)
Returns a QModelIndex in model which points to collection.
Definition: entitytreemodel.cpp:1235
Akonadi::StandardActionManager::CutCollections
Cuts the selected collections.
Definition: standardactionmanager.h:151
Akonadi::TrashJob
Job that moves items/collection to trash.
Definition: trashjob.h:66
Akonadi::StandardActionManager::LastType
Marks last action.
Definition: standardactionmanager.h:171
Akonadi::StandardActionManager::setContextText
void setContextText(Type type, TextContext context, const QString &text)
Sets the text of the action type for the given context.
Akonadi::AgentInstanceCreateJob
Job for creating new agent instances.
Definition: agentinstancecreatejob.h:71
Akonadi::StandardActionManager::DialogTitle
The window title of a dialog.
Definition: standardactionmanager.h:178
Akonadi::EntityDeletedAttribute
An Attribute that marks that an entity was marked as deleted.
Definition: entitydeletedattribute.h:49
Akonadi::ItemModel::ItemRole
The item object.
Definition: itemmodel.h:75
Akonadi::StandardActionManager::CopyItemToMenu
Menu allowing to quickly copy an item into a collection.
Definition: standardactionmanager.h:147
Akonadi::ActionStateManager
A helper class to manage action states.
Definition: actionstatemanager_p.h:35
Akonadi::CollectionModel::CollectionRole
The actual collection object.
Definition: collectionmodel.h:66
Akonadi::StandardActionManager::SynchronizeResources
Synchronizes the selected resources.
Definition: standardactionmanager.h:155
Akonadi::StandardActionManager::setFavoriteSelectionModel
void setFavoriteSelectionModel(QItemSelectionModel *selectionModel)
Sets the favorite collection selection model based on which the favorite collection related actions s...
Akonadi::StandardActionManager::DeleteResources
Deletes the selected resources.
Definition: standardactionmanager.h:153
Akonadi::EntityTreeModel::MimeTypeRole
The mimetype of the entity.
Definition: entitytreemodel.h:333
Akonadi::EntityTreeModel::ItemRole
The Item.
Definition: entitytreemodel.h:332
Akonadi::StandardActionManager::CopyCollections
Copies the selected collections.
Definition: standardactionmanager.h:135
Akonadi::AgentInstance::name
QString name() const
Returns the user visible name of the agent instance.
Definition: agentinstance.cpp:65
Akonadi
FreeBusyManager::Singleton.
Definition: actionstatemanager_p.h:28
Akonadi::Entity::hasAttribute
bool hasAttribute(const QByteArray &name) const
Returns true if the entity has an attribute of the given type name, false otherwise.
Definition: entity.cpp:147
Akonadi::EntityTreeModel::PendingCutRole
Definition: entitytreemodel.h:348
Akonadi::AgentTypeDialog
A dialog to select an available agent type.
Definition: agenttypedialog.h:53
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition: collection.cpp:115
Akonadi::AgentManager::self
static AgentManager * self()
Returns the global instance of the agent manager.
Definition: agentmanager.cpp:381
Akonadi::StandardActionManager::MessageBoxText
The text of a message box.
Definition: standardactionmanager.h:181
Akonadi::StandardActionManager::DialogText
The text of a dialog.
Definition: standardactionmanager.h:179
Akonadi::CollectionCreateJob
Job that creates a new collection in the Akonadi storage.
Definition: collectioncreatejob.h:52
Akonadi::AgentInstance
A representation of an agent instance.
Definition: agentinstance.h:62
Akonadi::StandardActionManager::CreateResource
Creates a new resource.
Definition: standardactionmanager.h:152
Akonadi::Collection::resource
QString resource() const
Returns the identifier of the resource owning the collection.
Definition: collection.cpp:207
Akonadi::StandardActionManager::setCollectionPropertiesPageNames
void setCollectionPropertiesPageNames(const QStringList &names)
Sets the page names of the config pages that will be used by the built-in collection properties dialo...
Akonadi::CollectionPropertiesDialog
A generic and extensible dialog for collection properties.
Definition: collectionpropertiesdialog.h:54
Akonadi::StandardActionManager::SynchronizeCollections
Synchronizes collections.
Definition: standardactionmanager.h:137
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition: entity.cpp:97
Akonadi::StandardActionManager::StandardActionManager
StandardActionManager(KActionCollection *actionCollection, QWidget *parent=0)
Creates a new standard action manager.
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition: collection.h:81
Akonadi::StandardActionManager::ErrorMessageText
The text of an error message.
Definition: standardactionmanager.h:184
Akonadi::Collection::setContentMimeTypes
void setContentMimeTypes(const QStringList &types)
Sets the list of possible content mime types.
Definition: collection.cpp:120
Akonadi::StandardActionManager::DeleteItems
Deletes the selected items.
Definition: standardactionmanager.h:141
Akonadi::StandardActionManager::DeleteCollections
Deletes the selected collections.
Definition: standardactionmanager.h:136
Akonadi::Collection::isVirtual
bool isVirtual() const
Returns whether the collection is virtual, for example a search collection.
Definition: collection.cpp:261
Akonadi::AgentInstanceCreateJob::start
void start()
Starts the instance creation.
Definition: agentinstancecreatejob.cpp:176
Akonadi::StandardActionManager::MoveCollectionToMenu
Menu allowing to move a collection into another collection.
Definition: standardactionmanager.h:149
Akonadi::FavoriteCollectionsModel
A model that lists a set of favorite collections.
Definition: favoritecollectionsmodel.h:66
Akonadi::StandardActionManager::RenameFavoriteCollection
Rename the collection of the favorite collections model.
Definition: standardactionmanager.h:145
Akonadi::StandardActionManager::SynchronizeFavoriteCollections
Synchronize favorite collections.
Definition: standardactionmanager.h:170
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Fri Nov 14 2014 05:53:29 by doxygen 1.8.8 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.14.3 API Reference

Skip menu "kdepimlibs-4.14.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal