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

akonadi

  • sources
  • kde-4.14
  • kdepimlibs
  • 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  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(selectionModel->model());
463  QMimeData *mimeData = selectionModel->model()->mimeData(safeSelectedRows(selectionModel));
464  model->setData(QModelIndex(), false, EntityTreeModel::PendingCutRole);
465  markCutAction(mimeData, cut);
466  QApplication::clipboard()->setMimeData(mimeData);
467 
468  foreach (const QModelIndex &index, safeSelectedRows(selectionModel)) {
469  model->setData(index, true, EntityTreeModel::PendingCutRole);
470  }
471 #endif
472  }
473  void updateActions()
474  {
475  // collect all selected collections
476  Collection::List selectedCollectionsList;
477  if (collectionSelectionModel) {
478  const QModelIndexList rows = safeSelectedRows(collectionSelectionModel);
479  foreach (const QModelIndex &index, rows) {
480  Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
481  if (!collection.isValid()) {
482  continue;
483  }
484 
485  const Collection parentCollection = index.data(EntityTreeModel::ParentCollectionRole).value<Collection>();
486  collection.setParentCollection(parentCollection);
487 
488  selectedCollectionsList << collection;
489  }
490  }
491 
492  // collect all selected items
493  Item::List selectedItems;
494  if (itemSelectionModel) {
495  const QModelIndexList rows = safeSelectedRows(itemSelectionModel);
496  foreach (const QModelIndex &index, rows) {
497  Item item = index.data(EntityTreeModel::ItemRole).value<Item>();
498  if (!item.isValid()) {
499  continue;
500  }
501 
502  const Collection parentCollection = index.data(EntityTreeModel::ParentCollectionRole).value<Collection>();
503  item.setParentCollection(parentCollection);
504 
505  selectedItems << item;
506  }
507  }
508 
509  mActionStateManager.updateState(selectedCollectionsList, selectedItems);
510  if (favoritesModel) {
511  enableAction(StandardActionManager::SynchronizeFavoriteCollections, (favoritesModel->rowCount() > 0));
512  }
513  emit q->actionStateUpdated();
514  }
515 
516 #ifndef QT_NO_CLIPBOARD
517  void clipboardChanged(QClipboard::Mode mode)
518  {
519  if (mode == QClipboard::Clipboard) {
520  updateActions();
521  }
522  }
523 #endif
524 
525  QItemSelection mapToEntityTreeModel(const QAbstractItemModel *model, const QItemSelection &selection) const
526  {
527  const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model);
528  if (proxy) {
529  return mapToEntityTreeModel(proxy->sourceModel(), proxy->mapSelectionToSource(selection));
530  } else {
531  return selection;
532  }
533  }
534 
535  QItemSelection mapFromEntityTreeModel(const QAbstractItemModel *model, const QItemSelection &selection) const
536  {
537  const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model);
538  if (proxy) {
539  const QItemSelection select = mapFromEntityTreeModel(proxy->sourceModel(), selection);
540  return proxy->mapSelectionFromSource(select);
541  } else {
542  return selection;
543  }
544  }
545 
546  // RAII class for setting insideSelectionSlot to true on entering, and false on exiting, the two slots below.
547  class InsideSelectionSlotBlocker {
548  public:
549  InsideSelectionSlotBlocker(Private *p)
550  : _p(p)
551  {
552  Q_ASSERT(!p->insideSelectionSlot);
553  p->insideSelectionSlot = true;
554  }
555 
556  ~InsideSelectionSlotBlocker()
557  {
558  Q_ASSERT(_p->insideSelectionSlot);
559  _p->insideSelectionSlot = false;
560  }
561  private:
562  Private *_p;
563  };
564 
565  void collectionSelectionChanged()
566  {
567  if (insideSelectionSlot) {
568  return;
569  }
570  InsideSelectionSlotBlocker block(this);
571  QItemSelection selection = collectionSelectionModel->selection();
572  selection = mapToEntityTreeModel(collectionSelectionModel->model(), selection);
573  selection = mapFromEntityTreeModel(favoritesModel, selection);
574 
575  if (favoriteSelectionModel) {
576  favoriteSelectionModel->select(selection, QItemSelectionModel::ClearAndSelect);
577  }
578 
579  updateActions();
580  }
581 
582  void favoriteSelectionChanged()
583  {
584  if (insideSelectionSlot) {
585  return;
586  }
587  QItemSelection selection = favoriteSelectionModel->selection();
588  if (selection.isEmpty()) {
589  return;
590  }
591 
592  selection = mapToEntityTreeModel(favoritesModel, selection);
593  selection = mapFromEntityTreeModel(collectionSelectionModel->model(), selection);
594 
595  InsideSelectionSlotBlocker block(this);
596  collectionSelectionModel->select(selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
597 
598  // Also set the current index. This will trigger KMMainWidget::slotFolderChanged in kmail, which we want.
599  collectionSelectionModel->setCurrentIndex(selection.indexes().first(), QItemSelectionModel::NoUpdate);
600 
601  updateActions();
602  }
603 
604  void slotCreateCollection()
605  {
606  Q_ASSERT(collectionSelectionModel);
607  if (collectionSelectionModel->selection().indexes().isEmpty()) {
608  return;
609  }
610 
611  const QModelIndex index = collectionSelectionModel->selection().indexes().at(0);
612  Q_ASSERT(index.isValid());
613  const Collection parentCollection = index.data(CollectionModel::CollectionRole).value<Collection>();
614  Q_ASSERT(parentCollection.isValid());
615 
616  if (!canCreateCollection(parentCollection)) {
617  return;
618  }
619 
620  QString name = KInputDialog::getText(contextText(StandardActionManager::CreateCollection, StandardActionManager::DialogTitle),
621  contextText(StandardActionManager::CreateCollection, StandardActionManager::DialogText),
622  QString(), 0, parentWidget);
623  name = name.trimmed();
624  if (name.isEmpty()) {
625  return;
626  }
627 
628  if (name.contains(QLatin1Char('/'))) {
629  KMessageBox::error(parentWidget,
630  i18n("We can not add \"/\" in folder name."),
631  i18n("Create new folder error"));
632  return;
633  }
634  if (name.startsWith(QLatin1Char('.')) ||
635  name.endsWith(QLatin1Char('.'))) {
636  KMessageBox::error(parentWidget,
637  i18n("We can not add \".\" at begin or end of folder name."),
638  i18n("Create new folder error"));
639  return;
640  }
641 
642  Collection collection;
643  collection.setName(name);
644  collection.setParentCollection(parentCollection);
645  if (actions[StandardActionManager::CreateCollection]) {
646  const QStringList mts = actions[StandardActionManager::CreateCollection]->property("ContentMimeTypes").toStringList();
647  if (!mts.isEmpty()) {
648  collection.setContentMimeTypes(mts);
649  }
650  }
651  if (parentCollection.contentMimeTypes().contains(Collection::virtualMimeType())) {
652  collection.setVirtual(true);
653  collection.setContentMimeTypes(collection.contentMimeTypes()
654  << Collection::virtualMimeType());
655  }
656 
657  CollectionCreateJob *job = new CollectionCreateJob(collection);
658  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(collectionCreationResult(KJob*)));
659  }
660 
661  void slotCopyCollections()
662  {
663  encodeToClipboard(collectionSelectionModel);
664  }
665 
666  void slotCutCollections()
667  {
668  encodeToClipboard(collectionSelectionModel, true);
669  }
670 
671  Collection::List selectedCollections()
672  {
673  Collection::List collections;
674 
675  Q_ASSERT(collectionSelectionModel);
676 
677  foreach (const QModelIndex &index, safeSelectedRows(collectionSelectionModel)) {
678  Q_ASSERT(index.isValid());
679  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
680  Q_ASSERT(collection.isValid());
681 
682  collections << collection;
683  }
684 
685  return collections;
686  }
687 
688  void slotDeleteCollection()
689  {
690  const Collection::List collections = selectedCollections();
691  if (collections.isEmpty()) {
692  return;
693  }
694 
695  const QString collectionName = collections.first().name();
696  const QString text = contextText(StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText,
697  collections.count(), collectionName);
698 
699  if (KMessageBox::questionYesNo(parentWidget, text,
700  contextText(StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, collections.count(), collectionName),
701  KStandardGuiItem::del(), KStandardGuiItem::cancel(),
702  QString(), KMessageBox::Dangerous) != KMessageBox::Yes) {
703  return;
704  }
705 
706  foreach (const Collection &collection, collections) {
707  CollectionDeleteJob *job = new CollectionDeleteJob(collection, q);
708  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(collectionDeletionResult(KJob*)));
709  }
710  }
711 
712  void slotMoveCollectionToTrash()
713  {
714  const Collection::List collections = selectedCollections();
715  if (collections.isEmpty()) {
716  return;
717  }
718 
719  foreach (const Collection &collection, collections) {
720  TrashJob *job = new TrashJob(collection, q);
721  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveCollectionToTrashResult(KJob*)));
722  }
723  }
724 
725  void slotRestoreCollectionFromTrash()
726  {
727  const Collection::List collections = selectedCollections();
728  if (collections.isEmpty()) {
729  return;
730  }
731 
732  foreach (const Collection &collection, collections) {
733  TrashRestoreJob *job = new TrashRestoreJob(collection, q);
734  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveCollectionToTrashResult(KJob*)));
735  }
736  }
737 
738  Item::List selectedItems() const
739  {
740  Item::List items;
741 
742  Q_ASSERT(itemSelectionModel);
743 
744  foreach (const QModelIndex &index, safeSelectedRows(itemSelectionModel)) {
745  Q_ASSERT(index.isValid());
746  const Item item = index.data(ItemModel::ItemRole).value<Item>();
747  Q_ASSERT(item.isValid());
748 
749  items << item;
750  }
751 
752  return items;
753  }
754 
755  void slotMoveItemToTrash()
756  {
757  const Item::List items = selectedItems();
758  if (items.isEmpty()) {
759  return;
760  }
761 
762  TrashJob *job = new TrashJob(items, q);
763  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveItemToTrashResult(KJob*)));
764  }
765 
766  void slotRestoreItemFromTrash()
767  {
768  const Item::List items = selectedItems();
769  if (items.isEmpty()) {
770  return;
771  }
772 
773  TrashRestoreJob *job = new TrashRestoreJob(items, q);
774  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(moveItemToTrashResult(KJob*)));
775  }
776 
777  void slotTrashRestoreCollection()
778  {
779  const Collection::List collections = selectedCollections();
780  if (collections.isEmpty()) {
781  return;
782  }
783 
784  bool collectionsAreInTrash = false;
785  foreach (const Collection &collection, collections) {
786  if (collection.hasAttribute<EntityDeletedAttribute>()) {
787  collectionsAreInTrash = true;
788  break;
789  }
790  }
791 
792  if (collectionsAreInTrash) {
793  slotRestoreCollectionFromTrash();
794  } else {
795  slotMoveCollectionToTrash();
796  }
797  }
798 
799  void slotTrashRestoreItem()
800  {
801  const Item::List items = selectedItems();
802  if (items.isEmpty()) {
803  return;
804  }
805 
806  bool itemsAreInTrash = false;
807  foreach (const Item &item, items) {
808  if (item.hasAttribute<EntityDeletedAttribute>()) {
809  itemsAreInTrash = true;
810  break;
811  }
812  }
813 
814  if (itemsAreInTrash) {
815  slotRestoreItemFromTrash();
816  } else {
817  slotMoveItemToTrash();
818  }
819  }
820 
821  void slotSynchronizeCollection()
822  {
823  Q_ASSERT(collectionSelectionModel);
824  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
825  if (list.isEmpty()) {
826  return;
827  }
828 
829  const Collection::List collections = selectedCollections();
830  if (collections.isEmpty()) {
831  return;
832  }
833 
834  foreach (const Collection &collection, collections) {
835  if (!testAndSetOnlineResources(collection)) {
836  break;
837  }
838  AgentManager::self()->synchronizeCollection(collection, false);
839  }
840  }
841 
842  bool testAndSetOnlineResources(const Akonadi::Collection &collection)
843  {
844  // Shortcut for the Search resource, which is a virtual resource and thus
845  // is awlays online (but AgentManager does not know about it, so it returns
846  // an invalid AgentInstance, which is "offline").
847  //
848  // FIXME: AgentManager should return a valid AgentInstance even
849  // for virtual resources, which would be always online.
850  if (collection.resource() == QLatin1String("akonadi_search_resource")) {
851  return true;
852  }
853 
854  Akonadi::AgentInstance instance = Akonadi::AgentManager::self()->instance(collection.resource());
855  if (!instance.isOnline()) {
856  if (KMessageBox::questionYesNo(parentWidget,
857  i18n("Before syncing folder \"%1\" it is necessary to have the resource online. Do you want to make it online?", collection.displayName()),
858  i18n("Account \"%1\" is offline", instance.name()),
859  KGuiItem(i18nc("@action:button", "Go Online")), KStandardGuiItem::cancel()) != KMessageBox::Yes) {
860  return false;
861  }
862  instance.setIsOnline(true);
863  }
864  return true;
865  }
866 
867  void slotSynchronizeCollectionRecursive()
868  {
869  Q_ASSERT(collectionSelectionModel);
870  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
871  if (list.isEmpty()) {
872  return;
873  }
874 
875  const Collection::List collections = selectedCollections();
876  if (collections.isEmpty()) {
877  return;
878  }
879 
880  foreach (const Collection &collection, collections) {
881  if (!testAndSetOnlineResources(collection)) {
882  break;
883  }
884  AgentManager::self()->synchronizeCollection(collection, true);
885  }
886  }
887 
888  void slotCollectionProperties()
889  {
890  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
891  if (list.isEmpty()) {
892  return;
893  }
894 
895  const QModelIndex index = list.first();
896  Q_ASSERT(index.isValid());
897 
898  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
899  Q_ASSERT(collection.isValid());
900 
901  CollectionPropertiesDialog *dlg = new CollectionPropertiesDialog(collection, mCollectionPropertiesPageNames, parentWidget);
902  dlg->setCaption(contextText(StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle, collection.displayName()));
903  dlg->show();
904  }
905 
906  void slotCopyItems()
907  {
908  encodeToClipboard(itemSelectionModel);
909  }
910 
911  void slotCutItems()
912  {
913  encodeToClipboard(itemSelectionModel, true);
914  }
915 
916  void slotPaste()
917  {
918  Q_ASSERT(collectionSelectionModel);
919 
920  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
921  if (list.isEmpty()) {
922  return;
923  }
924 
925  const QModelIndex index = list.first();
926  Q_ASSERT(index.isValid());
927 
928 #ifndef QT_NO_CLIPBOARD
929  // TODO: Copy or move? We can't seem to cut yet
930  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(collectionSelectionModel->model());
931  const QMimeData *mimeData = QApplication::clipboard()->mimeData();
932  model->dropMimeData(mimeData, isCutAction(mimeData) ? Qt::MoveAction : Qt::CopyAction, -1, -1, index);
933  model->setData(QModelIndex(), false, EntityTreeModel::PendingCutRole);
934  QApplication::clipboard()->clear();
935 #endif
936  }
937 
938  void slotDeleteItems()
939  {
940  Q_ASSERT(itemSelectionModel);
941 
942  Item::List items;
943  foreach (const QModelIndex &index, safeSelectedRows(itemSelectionModel)) {
944  bool ok;
945  const qlonglong id = index.data(ItemModel::IdRole).toLongLong(&ok);
946  Q_ASSERT(ok);
947  items << Item(id);
948  }
949 
950  if (items.isEmpty()) {
951  return;
952  }
953 
954  QMetaObject::invokeMethod(q, "slotDeleteItemsDeferred",
955  Qt::QueuedConnection,
956  Q_ARG(Akonadi::Item::List, items));
957  }
958 
959  void slotDeleteItemsDeferred(const Akonadi::Item::List &items)
960  {
961  Q_ASSERT(itemSelectionModel);
962 
963  if (KMessageBox::questionYesNo(parentWidget,
964  contextText(StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, items.count(), QString()),
965  contextText(StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, items.count(), QString()),
966  KStandardGuiItem::del(), KStandardGuiItem::cancel(),
967  QString(), KMessageBox::Dangerous) != KMessageBox::Yes) {
968  return;
969  }
970 
971  ItemDeleteJob *job = new ItemDeleteJob(items, q);
972  q->connect(job, SIGNAL(result(KJob*)), q, SLOT(itemDeletionResult(KJob*)));
973  }
974 
975  void slotLocalSubscription()
976  {
977  SubscriptionDialog *dlg = new SubscriptionDialog(mMimeTypeFilter, parentWidget);
978  dlg->showHiddenCollection(true);
979  dlg->show();
980  }
981 
982  void slotAddToFavorites()
983  {
984  Q_ASSERT(collectionSelectionModel);
985  Q_ASSERT(favoritesModel);
986  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
987  if (list.isEmpty()) {
988  return;
989  }
990 
991  foreach (const QModelIndex &index, list) {
992  Q_ASSERT(index.isValid());
993  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
994  Q_ASSERT(collection.isValid());
995 
996  favoritesModel->addCollection(collection);
997  }
998 
999  updateActions();
1000  }
1001 
1002  void slotRemoveFromFavorites()
1003  {
1004  Q_ASSERT(collectionSelectionModel);
1005  Q_ASSERT(favoritesModel);
1006  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
1007  if (list.isEmpty()) {
1008  return;
1009  }
1010 
1011  foreach (const QModelIndex &index, list) {
1012  Q_ASSERT(index.isValid());
1013  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
1014  Q_ASSERT(collection.isValid());
1015 
1016  favoritesModel->removeCollection(collection);
1017  }
1018 
1019  updateActions();
1020  }
1021 
1022  void slotRenameFavorite()
1023  {
1024  Q_ASSERT(collectionSelectionModel);
1025  Q_ASSERT(favoritesModel);
1026  const QModelIndexList list = safeSelectedRows(collectionSelectionModel);
1027  if (list.isEmpty()) {
1028  return;
1029  }
1030  const QModelIndex index = list.first();
1031  Q_ASSERT(index.isValid());
1032  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
1033  Q_ASSERT(collection.isValid());
1034 
1035  QPointer<RenameFavoriteDialog> dlg(new RenameFavoriteDialog(contextText(StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle), contextText(StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText) , favoritesModel->favoriteLabel(collection), collection.displayName(), parentWidget));
1036  if (dlg->exec() == QDialog::Accepted && dlg != 0) {
1037  favoritesModel->setFavoriteLabel(collection, dlg->newName());
1038  }
1039  delete dlg;
1040  }
1041 
1042  void slotSynchronizeFavoriteCollections()
1043  {
1044  Q_ASSERT(favoritesModel);
1045  foreach (const Collection &collection, favoritesModel->collections()) {
1046  // there might be virtual collections in favorites which cannot be checked
1047  // so let's be safe here, agentmanager asserts otherwise
1048  if (!collection.resource().isEmpty()) {
1049  AgentManager::self()->synchronizeCollection(collection, false);
1050  }
1051  }
1052  }
1053 
1054  void slotCopyCollectionTo()
1055  {
1056  pasteTo(collectionSelectionModel, collectionSelectionModel->model(), CopyCollectionToMenu, Qt::CopyAction);
1057  }
1058 
1059  void slotCopyItemTo()
1060  {
1061  pasteTo(itemSelectionModel, collectionSelectionModel->model(), CopyItemToMenu, Qt::CopyAction);
1062  }
1063 
1064  void slotMoveCollectionTo()
1065  {
1066  pasteTo(collectionSelectionModel, collectionSelectionModel->model(), MoveCollectionToMenu, Qt::MoveAction);
1067  }
1068 
1069  void slotMoveItemTo()
1070  {
1071  pasteTo(itemSelectionModel, collectionSelectionModel->model(), MoveItemToMenu, Qt::MoveAction);
1072  }
1073 
1074  void slotCopyCollectionTo(QAction *action)
1075  {
1076  pasteTo(collectionSelectionModel, action, Qt::CopyAction);
1077  }
1078 
1079  void slotCopyItemTo(QAction *action)
1080  {
1081  pasteTo(itemSelectionModel, action, Qt::CopyAction);
1082  }
1083 
1084  void slotMoveCollectionTo(QAction *action)
1085  {
1086  pasteTo(collectionSelectionModel, action, Qt::MoveAction);
1087  }
1088 
1089  void slotMoveItemTo(QAction *action)
1090  {
1091  pasteTo(itemSelectionModel, action, Qt::MoveAction);
1092  }
1093 
1094  AgentInstance::List selectedAgentInstances() const
1095  {
1096  AgentInstance::List instances;
1097 
1098  Q_ASSERT(collectionSelectionModel);
1099  if (collectionSelectionModel->selection().indexes().isEmpty()) {
1100  return instances;
1101  }
1102 
1103  foreach (const QModelIndex &index, collectionSelectionModel->selection().indexes()) {
1104  Q_ASSERT(index.isValid());
1105  const Collection collection = index.data(CollectionModel::CollectionRole).value<Collection>();
1106  Q_ASSERT(collection.isValid());
1107 
1108  if (collection.isValid()) {
1109  const QString identifier = collection.resource();
1110  instances << AgentManager::self()->instance(identifier);
1111  }
1112  }
1113 
1114  return instances;
1115  }
1116 
1117  AgentInstance selectedAgentInstance() const
1118  {
1119  const AgentInstance::List instances = selectedAgentInstances();
1120 
1121  if (instances.isEmpty()) {
1122  return AgentInstance();
1123  }
1124 
1125  return instances.first();
1126  }
1127 
1128  void slotCreateResource()
1129  {
1130  QPointer<Akonadi::AgentTypeDialog> dlg(new Akonadi::AgentTypeDialog(parentWidget));
1131  dlg->setCaption(contextText(StandardActionManager::CreateResource, StandardActionManager::DialogTitle));
1132 
1133  foreach (const QString &mimeType, mMimeTypeFilter) {
1134  dlg->agentFilterProxyModel()->addMimeTypeFilter(mimeType);
1135  }
1136 
1137  foreach (const QString &capability, mCapabilityFilter) {
1138  dlg->agentFilterProxyModel()->addCapabilityFilter(capability);
1139  }
1140 
1141  if (dlg->exec() == QDialog::Accepted && dlg != 0) {
1142  const AgentType agentType = dlg->agentType();
1143 
1144  if (agentType.isValid()) {
1145  AgentInstanceCreateJob *job = new AgentInstanceCreateJob(agentType, q);
1146  q->connect(job, SIGNAL(result(KJob*)), SLOT(resourceCreationResult(KJob*)));
1147  job->configure(parentWidget);
1148  job->start();
1149  }
1150  }
1151  delete dlg;
1152  }
1153 
1154  void slotDeleteResource()
1155  {
1156  const AgentInstance::List instances = selectedAgentInstances();
1157  if (instances.isEmpty()) {
1158  return;
1159  }
1160 
1161  if (KMessageBox::questionYesNo(parentWidget,
1162  contextText(StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, instances.count(), instances.first().name()),
1163  contextText(StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, instances.count(), instances.first().name()),
1164  KStandardGuiItem::del(), KStandardGuiItem::cancel(),
1165  QString(), KMessageBox::Dangerous) != KMessageBox::Yes) {
1166  return;
1167  }
1168 
1169  foreach (const AgentInstance &instance, instances) {
1170  AgentManager::self()->removeInstance(instance);
1171  }
1172  }
1173 
1174  void slotSynchronizeResource()
1175  {
1176  const AgentInstance::List instances = selectedAgentInstances();
1177  if (instances.isEmpty()) {
1178  return;
1179  }
1180 
1181  foreach (AgentInstance instance, instances) { //krazy:exclude=foreach
1182  instance.synchronize();
1183  }
1184  }
1185 
1186  void slotResourceProperties()
1187  {
1188  AgentInstance instance = selectedAgentInstance();
1189  if (!instance.isValid()) {
1190  return;
1191  }
1192 
1193  instance.configure(parentWidget);
1194  }
1195 
1196  void slotToggleWorkOffline(bool offline)
1197  {
1198  setWorkOffline(offline);
1199 
1200  AgentInstance::List instances = AgentManager::self()->instances();
1201  foreach (AgentInstance instance, instances) { //krazy:exclude=foreach
1202  instance.setIsOnline(!offline);
1203  }
1204  }
1205 
1206  void pasteTo(QItemSelectionModel *selectionModel, const QAbstractItemModel *model, StandardActionManager::Type type, Qt::DropAction dropAction)
1207  {
1208  const QSet<QString> mimeTypes = mimeTypesOfSelection(type);
1209 
1210  QPointer<CollectionDialog> dlg(new CollectionDialog(const_cast<QAbstractItemModel *>(model)));
1211  dlg->setMimeTypeFilter(mimeTypes.toList());
1212 
1213  if (type == CopyItemToMenu || type == MoveItemToMenu) {
1214  dlg->setAccessRightsFilter(Collection::CanCreateItem);
1215  } else if (type == CopyCollectionToMenu || type == MoveCollectionToMenu) {
1216  dlg->setAccessRightsFilter(Collection::CanCreateCollection);
1217  }
1218 
1219  if (dlg->exec() == QDialog::Accepted && dlg != 0) {
1220  const QModelIndex index = EntityTreeModel::modelIndexForCollection(collectionSelectionModel->model(), dlg->selectedCollection());
1221  if (!index.isValid()) {
1222  return;
1223  }
1224 
1225  const QMimeData *mimeData = selectionModel->model()->mimeData(safeSelectedRows(selectionModel));
1226 
1227  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(index.model());
1228  model->dropMimeData(mimeData, dropAction, -1, -1, index);
1229  }
1230  delete dlg;
1231  }
1232 
1233  void pasteTo(QItemSelectionModel *selectionModel, QAction *action, Qt::DropAction dropAction)
1234  {
1235  Q_ASSERT(selectionModel);
1236  Q_ASSERT(action);
1237 
1238  if (safeSelectedRows(selectionModel).count() <= 0) {
1239  return;
1240  }
1241 
1242  const QMimeData *mimeData = selectionModel->model()->mimeData(selectionModel->selectedRows());
1243 
1244  const QModelIndex index = action->data().value<QModelIndex>();
1245  Q_ASSERT(index.isValid());
1246 
1247  QAbstractItemModel *model = const_cast<QAbstractItemModel *>(index.model());
1248  const Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
1249  addRecentCollection(collection.id());
1250  model->dropMimeData(mimeData, dropAction, -1, -1, index);
1251  }
1252 
1253  void addRecentCollection(Akonadi::Collection::Id id)
1254  {
1255  QMapIterator<StandardActionManager::Type, QWeakPointer<RecentCollectionAction> > item(mRecentCollectionsMenu);
1256  while (item.hasNext()) {
1257  item.next();
1258  if (item.value().data()) {
1259  item.value().data()->addRecentCollection(item.key(),id);
1260  }
1261  }
1262  }
1263 
1264  void collectionCreationResult(KJob *job)
1265  {
1266  if (job->error()) {
1267  KMessageBox::error(parentWidget,
1268  contextText(StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText, job->errorString()),
1269  contextText(StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle));
1270  }
1271  }
1272 
1273  void collectionDeletionResult(KJob *job)
1274  {
1275  if (job->error()) {
1276  KMessageBox::error(parentWidget,
1277  contextText(StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText, job->errorString()),
1278  contextText(StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle));
1279  }
1280  }
1281 
1282  void moveCollectionToTrashResult(KJob *job)
1283  {
1284  if (job->error()) {
1285  KMessageBox::error(parentWidget,
1286  contextText(StandardActionManager::MoveCollectionsToTrash, StandardActionManager::ErrorMessageText, job->errorString()),
1287  contextText(StandardActionManager::MoveCollectionsToTrash, StandardActionManager::ErrorMessageTitle));
1288  }
1289  }
1290 
1291  void moveItemToTrashResult(KJob *job)
1292  {
1293  if (job->error()) {
1294  KMessageBox::error(parentWidget,
1295  contextText(StandardActionManager::MoveItemsToTrash, StandardActionManager::ErrorMessageText, job->errorString()),
1296  contextText(StandardActionManager::MoveItemsToTrash, StandardActionManager::ErrorMessageTitle));
1297  }
1298  }
1299 
1300  void itemDeletionResult(KJob *job)
1301  {
1302  if (job->error()) {
1303  KMessageBox::error(parentWidget,
1304  contextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText, job->errorString()),
1305  contextText(StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle));
1306  }
1307  }
1308 
1309  void resourceCreationResult(KJob *job)
1310  {
1311  if (job->error()) {
1312  KMessageBox::error(parentWidget,
1313  contextText(StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText, job->errorString()),
1314  contextText(StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle));
1315  }
1316  }
1317 
1318  void pasteResult(KJob *job)
1319  {
1320  if (job->error()) {
1321  KMessageBox::error(parentWidget,
1322  contextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageText, job->errorString()),
1323  contextText(StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle));
1324  }
1325  }
1326 
1330  QSet<QString> mimeTypesOfSelection(StandardActionManager::Type type) const
1331  {
1332  QModelIndexList list;
1333  QSet<QString> mimeTypes;
1334 
1335  const bool isItemAction = (type == CopyItemToMenu || type == MoveItemToMenu);
1336  const bool isCollectionAction = (type == CopyCollectionToMenu || type == MoveCollectionToMenu);
1337 
1338  if (isItemAction) {
1339  list = safeSelectedRows(itemSelectionModel);
1340  foreach (const QModelIndex &index, list) {
1341  mimeTypes << index.data(EntityTreeModel::MimeTypeRole).toString();
1342  }
1343  }
1344 
1345  if (isCollectionAction) {
1346  list = safeSelectedRows(collectionSelectionModel);
1347  foreach (const QModelIndex &index, list) {
1348  const Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
1349 
1350  // The mimetypes that the selected collection can possibly contain
1351  mimeTypes = AgentManager::self()->instance(collection.resource()).type().mimeTypes().toSet();
1352  }
1353  }
1354 
1355  return mimeTypes;
1356  }
1357 
1361  bool isWritableTargetCollectionForMimeTypes(const Collection &collection, const QSet<QString> &mimeTypes, StandardActionManager::Type type) const
1362  {
1363  if (collection.isVirtual()) {
1364  return false;
1365  }
1366 
1367  const bool isItemAction = (type == CopyItemToMenu || type == MoveItemToMenu);
1368  const bool isCollectionAction = (type == CopyCollectionToMenu || type == MoveCollectionToMenu);
1369 
1370  const bool canContainRequiredMimeTypes = !collection.contentMimeTypes().toSet().intersect(mimeTypes).isEmpty();
1371  const bool canCreateNewItems = (collection.rights() & Collection::CanCreateItem);
1372 
1373  const bool canCreateNewCollections = (collection.rights() & Collection::CanCreateCollection);
1374  const bool canContainCollections = collection.contentMimeTypes().contains(Collection::mimeType()) || collection.contentMimeTypes().contains(Collection::virtualMimeType());
1375  const bool resourceAllowsRequiredMimeTypes = AgentManager::self()->instance(collection.resource()).type().mimeTypes().toSet().contains(mimeTypes);
1376 
1377  const bool isReadOnlyForItems = (isItemAction && (!canCreateNewItems || !canContainRequiredMimeTypes));
1378  const bool isReadOnlyForCollections = (isCollectionAction && (!canCreateNewCollections || !canContainCollections || !resourceAllowsRequiredMimeTypes));
1379 
1380  return !(CollectionUtils::isStructural(collection) || isReadOnlyForItems || isReadOnlyForCollections);
1381  }
1382 
1383  void fillFoldersMenu(const Akonadi::Collection::List &selectedCollectionsList, const QSet<QString> &mimeTypes, StandardActionManager::Type type, QMenu *menu,
1384  const QAbstractItemModel *model, QModelIndex parentIndex)
1385  {
1386  const int rowCount = model->rowCount(parentIndex);
1387 
1388  for (int row = 0; row < rowCount; ++row) {
1389  const QModelIndex index = model->index(row, 0, parentIndex);
1390  const Collection collection = model->data(index, CollectionModel::CollectionRole).value<Collection>();
1391 
1392  if (collection.isVirtual()) {
1393  continue;
1394  }
1395 
1396  const bool readOnly = !isWritableTargetCollectionForMimeTypes( collection, mimeTypes, type );
1397  const bool collectionIsSelected = selectedCollectionsList.contains( collection );
1398  if (type == MoveCollectionToMenu && collectionIsSelected) {
1399  continue;
1400  }
1401 
1402  QString label = model->data(index).toString();
1403  label.replace(QLatin1String("&"), QLatin1String("&&"));
1404 
1405  const QIcon icon = model->data(index, Qt::DecorationRole).value<QIcon>();
1406 
1407  if (model->rowCount(index) > 0) {
1408  // new level
1409  QMenu *popup = new QMenu(menu);
1410  const bool moveAction = (type == MoveCollectionToMenu || type == MoveItemToMenu);
1411  popup->setObjectName(QString::fromUtf8("subMenu"));
1412  popup->setTitle(label);
1413  popup->setIcon(icon);
1414 
1415  fillFoldersMenu(selectedCollectionsList, mimeTypes, type, popup, model, index);
1416 
1417  if (!(type == CopyCollectionToMenu && collectionIsSelected)) {
1418  if ( !readOnly ) {
1419  popup->addSeparator();
1420 
1421  QAction *action = popup->addAction( moveAction ? i18n( "Move to This Folder" ) : i18n( "Copy to This Folder" ) );
1422  action->setData( QVariant::fromValue<QModelIndex>( index ) );
1423  }
1424  }
1425 
1426  menu->addMenu(popup);
1427 
1428  } else {
1429  // insert an item
1430  QAction *action = menu->addAction(icon, label);
1431  action->setData(QVariant::fromValue<QModelIndex>(index));
1432  action->setEnabled(!readOnly && !collectionIsSelected);
1433  }
1434  }
1435  }
1436 
1437  void checkModelsConsistency()
1438  {
1439  if (favoritesModel == 0 || favoriteSelectionModel == 0) {
1440  // No need to check when the favorite collections feature is not used
1441  return;
1442  }
1443 
1444  // find the base ETM of the favourites view
1445  const QAbstractItemModel *favModel = favoritesModel;
1446  while (const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(favModel)) {
1447  favModel = proxy->sourceModel();
1448  }
1449 
1450  // Check that the collection selection model maps to the same
1451  // EntityTreeModel than favoritesModel
1452  if (collectionSelectionModel != 0) {
1453  const QAbstractItemModel *model = collectionSelectionModel->model();
1454  while (const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model)) {
1455  model = proxy->sourceModel();
1456  }
1457 
1458  Q_ASSERT(model == favModel);
1459  }
1460 
1461  // Check that the favorite selection model maps to favoritesModel
1462  const QAbstractItemModel *model = favoriteSelectionModel->model();
1463  while (const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel *>(model)) {
1464  model = proxy->sourceModel();
1465  }
1466  Q_ASSERT(model == favModel);
1467  }
1468 
1469  void markCutAction(QMimeData *mimeData, bool cut) const
1470  {
1471  if (!cut) {
1472  return;
1473  }
1474 
1475  const QByteArray cutSelectionData = "1"; //krazy:exclude=doublequote_chars
1476  mimeData->setData(QLatin1String("application/x-kde.akonadi-cutselection"), cutSelectionData);
1477  }
1478 
1479  bool isCutAction(const QMimeData *mimeData) const
1480  {
1481  const QByteArray data = mimeData->data(QLatin1String("application/x-kde.akonadi-cutselection"));
1482  if (data.isEmpty()) {
1483  return false;
1484  } else {
1485  return (data.at(0) == '1'); // true if 1
1486  }
1487  }
1488 
1489  void setContextText(StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &data)
1490  {
1491  ContextTextEntry entry;
1492  entry.text = data;
1493 
1494  contextTexts[type].insert(context, entry);
1495  }
1496 
1497  void setContextText(StandardActionManager::Type type, StandardActionManager::TextContext context, const KLocalizedString &data)
1498  {
1499  ContextTextEntry entry;
1500  entry.localizedText = data;
1501 
1502  contextTexts[type].insert(context, entry);
1503  }
1504 
1505  QString contextText(StandardActionManager::Type type, StandardActionManager::TextContext context) const
1506  {
1507  return contextTexts[type].value(context).text;
1508  }
1509 
1510  QString contextText(StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &value) const
1511  {
1512  KLocalizedString text = contextTexts[type].value(context).localizedText;
1513  if (text.isEmpty()) {
1514  return contextTexts[type].value(context).text;
1515  }
1516 
1517  return text.subs(value).toString();
1518  }
1519 
1520  QString contextText(StandardActionManager::Type type, StandardActionManager::TextContext context, int count, const QString &value) const
1521  {
1522  KLocalizedString text = contextTexts[type].value(context).localizedText;
1523  if (text.isEmpty()) {
1524  return contextTexts[type].value(context).text;
1525  }
1526 
1527  const QString str = text.subs(count).toString();
1528  const int argCount = str.count(QRegExp(QLatin1String("%[0-9]")));
1529  if (argCount > 0) {
1530  return text.subs(count).subs(value).toString();
1531  } else {
1532  return text.subs(count).toString();
1533  }
1534  }
1535 
1536  StandardActionManager *q;
1537  KActionCollection *actionCollection;
1538  QWidget *parentWidget;
1539  QItemSelectionModel *collectionSelectionModel;
1540  QItemSelectionModel *itemSelectionModel;
1541  FavoriteCollectionsModel *favoritesModel;
1542  QItemSelectionModel *favoriteSelectionModel;
1543  bool insideSelectionSlot;
1544  QVector<KAction *> actions;
1545  QHash<StandardActionManager::Type, KLocalizedString> pluralLabels;
1546  QHash<StandardActionManager::Type, KLocalizedString> pluralIconLabels;
1547 
1548  struct ContextTextEntry
1549  {
1550  QString text;
1551  KLocalizedString localizedText;
1552  bool isLocalized;
1553  };
1554 
1555  typedef QHash<StandardActionManager::TextContext, ContextTextEntry> ContextTexts;
1556  QHash<StandardActionManager::Type, ContextTexts> contextTexts;
1557 
1558  ActionStateManager mActionStateManager;
1559 
1560  QStringList mMimeTypeFilter;
1561  QStringList mCapabilityFilter;
1562  QStringList mCollectionPropertiesPageNames;
1563  QMap<StandardActionManager::Type, QWeakPointer<RecentCollectionAction> > mRecentCollectionsMenu;
1564 };
1565 
1566 //@endcond
1567 
1568 StandardActionManager::StandardActionManager(KActionCollection *actionCollection, QWidget *parent)
1569  : QObject(parent)
1570  , d(new Private(this))
1571 {
1572  d->parentWidget = parent;
1573  d->actionCollection = actionCollection;
1574  d->mActionStateManager.setReceiver(this);
1575 #ifndef QT_NO_CLIPBOARD
1576  connect(QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)), SLOT(clipboardChanged(QClipboard::Mode)));
1577 #endif
1578 }
1579 
1580 StandardActionManager::~ StandardActionManager()
1581 {
1582  delete d;
1583 }
1584 
1585 void StandardActionManager::setCollectionSelectionModel(QItemSelectionModel *selectionModel)
1586 {
1587  d->collectionSelectionModel = selectionModel;
1588  connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1589  SLOT(collectionSelectionChanged()));
1590 
1591  d->checkModelsConsistency();
1592 }
1593 
1594 void StandardActionManager::setItemSelectionModel(QItemSelectionModel *selectionModel)
1595 {
1596  d->itemSelectionModel = selectionModel;
1597  connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1598  SLOT(updateActions()));
1599 }
1600 
1601 void StandardActionManager::setFavoriteCollectionsModel(FavoriteCollectionsModel *favoritesModel)
1602 {
1603  d->favoritesModel = favoritesModel;
1604  d->checkModelsConsistency();
1605 }
1606 
1607 void StandardActionManager::setFavoriteSelectionModel(QItemSelectionModel *selectionModel)
1608 {
1609  d->favoriteSelectionModel = selectionModel;
1610  connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1611  SLOT(favoriteSelectionChanged()));
1612  d->checkModelsConsistency();
1613 }
1614 
1615 KAction *StandardActionManager::createAction(Type type)
1616 {
1617  Q_ASSERT(type < LastType);
1618  if (d->actions[type]) {
1619  return d->actions[type];
1620  }
1621  KAction *action = 0;
1622  switch (standardActionData[type].actionType) {
1623  case NormalAction:
1624  case ActionWithAlternative:
1625  action = new KAction(d->parentWidget);
1626  break;
1627  case ActionAlternative:
1628  d->actions[type] = d->actions[type - 1];
1629  Q_ASSERT(d->actions[type]);
1630  if ((LastType > type + 1) && (standardActionData[type + 1].actionType == ActionAlternative)) {
1631  createAction(static_cast<Type>(type + 1)); //ensure that alternative actions are initialized when not created by createAllActions
1632  }
1633  return d->actions[type];
1634  case MenuAction:
1635  action = new KActionMenu(d->parentWidget);
1636  break;
1637  case ToggleAction:
1638  action = new KToggleAction(d->parentWidget);
1639  break;
1640  }
1641 
1642  if (d->pluralLabels.contains(type) && !d->pluralLabels.value(type).isEmpty()) {
1643  action->setText(d->pluralLabels.value(type).subs(1).toString());
1644  } else if (standardActionData[type].label) {
1645  action->setText(i18n(standardActionData[type].label));
1646  }
1647 
1648  if (d->pluralIconLabels.contains(type) && !d->pluralIconLabels.value(type).isEmpty()) {
1649  action->setIconText(d->pluralIconLabels.value(type).subs(1).toString());
1650  } else if (standardActionData[type].iconLabel) {
1651  action->setIconText(i18n(standardActionData[type].iconLabel));
1652  }
1653 
1654  if (standardActionData[type].icon) {
1655  action->setIcon(KIcon(QString::fromLatin1(standardActionData[type].icon)));
1656  }
1657 
1658  action->setShortcut(standardActionData[type].shortcut);
1659 
1660  if (standardActionData[type].slot) {
1661  switch (standardActionData[type].actionType) {
1662  case NormalAction:
1663  case ActionWithAlternative:
1664  connect(action, SIGNAL(triggered()), standardActionData[type].slot);
1665  break;
1666  case MenuAction: {
1667  KActionMenu *actionMenu = qobject_cast<KActionMenu *>(action);
1668  connect(actionMenu->menu(), SIGNAL(triggered(QAction*)), standardActionData[type].slot);
1669  break;
1670  }
1671  case ToggleAction: {
1672  connect(action, SIGNAL(triggered(bool)), standardActionData[type].slot);
1673  break;
1674  }
1675  case ActionAlternative:
1676  Q_ASSERT(0);
1677  }
1678  }
1679 
1680  if (type == ToggleWorkOffline) {
1681  // inititalize the action state with information from config file
1682  disconnect(action, SIGNAL(triggered(bool)), this, standardActionData[type].slot);
1683  action->setChecked(workOffline());
1684  connect(action, SIGNAL(triggered(bool)), this, standardActionData[type].slot);
1685 
1686  //TODO: find a way to check for updates to the config file
1687  }
1688 
1689  Q_ASSERT(standardActionData[type].name);
1690  d->actionCollection->addAction(QString::fromLatin1(standardActionData[type].name), action);
1691  d->actions[type] = action;
1692  if ((standardActionData[type].actionType == ActionWithAlternative) && (standardActionData[type + 1].actionType == ActionAlternative)) {
1693  createAction(static_cast<Type>(type + 1)); //ensure that alternative actions are initialized when not created by createAllActions
1694  }
1695  d->updateActions();
1696  return action;
1697 }
1698 
1699 void StandardActionManager::createAllActions()
1700 {
1701  for (uint i = 0; i < LastType; ++i) {
1702  createAction((Type)i);
1703  }
1704 }
1705 
1706 KAction *StandardActionManager::action(Type type) const
1707 {
1708  Q_ASSERT(type < LastType);
1709  return d->actions[type];
1710 }
1711 
1712 void StandardActionManager::setActionText(Type type, const KLocalizedString &text)
1713 {
1714  Q_ASSERT(type < LastType);
1715  d->pluralLabels.insert(type, text);
1716  d->updateActions();
1717 }
1718 
1719 void StandardActionManager::interceptAction(Type type, bool intercept)
1720 {
1721  Q_ASSERT(type < LastType);
1722 
1723  const KAction *action = d->actions[type];
1724 
1725  if (!action) {
1726  return;
1727  }
1728 
1729  if (intercept) {
1730  disconnect(action, SIGNAL(triggered()), this, standardActionData[type].slot);
1731  } else {
1732  connect(action, SIGNAL(triggered()), standardActionData[type].slot);
1733  }
1734 }
1735 
1736 Akonadi::Collection::List StandardActionManager::selectedCollections() const
1737 {
1738  Collection::List collections;
1739 
1740  if (!d->collectionSelectionModel) {
1741  return collections;
1742  }
1743 
1744  foreach (const QModelIndex &index, safeSelectedRows(d->collectionSelectionModel)) {
1745  const Collection collection = index.data(EntityTreeModel::CollectionRole).value<Collection>();
1746  if (collection.isValid()) {
1747  collections << collection;
1748  }
1749  }
1750 
1751  return collections;
1752 }
1753 
1754 Item::List StandardActionManager::selectedItems() const
1755 {
1756  Item::List items;
1757 
1758  if (!d->itemSelectionModel) {
1759  return items;
1760  }
1761 
1762  foreach (const QModelIndex &index, safeSelectedRows(d->itemSelectionModel)) {
1763  const Item item = index.data(EntityTreeModel::ItemRole).value<Item>();
1764  if (item.isValid()) {
1765  items << item;
1766  }
1767  }
1768 
1769  return items;
1770 }
1771 
1772 void StandardActionManager::setContextText(Type type, TextContext context, const QString &text)
1773 {
1774  d->setContextText(type, context, text);
1775 }
1776 
1777 void StandardActionManager::setContextText(Type type, TextContext context, const KLocalizedString &text)
1778 {
1779  d->setContextText(type, context, text);
1780 }
1781 
1782 void StandardActionManager::setMimeTypeFilter(const QStringList &mimeTypes)
1783 {
1784  d->mMimeTypeFilter = mimeTypes;
1785 }
1786 
1787 void StandardActionManager::setCapabilityFilter(const QStringList &capabilities)
1788 {
1789  d->mCapabilityFilter = capabilities;
1790 }
1791 
1792 void StandardActionManager::setCollectionPropertiesPageNames(const QStringList &names)
1793 {
1794  d->mCollectionPropertiesPageNames = names;
1795 }
1796 
1797 void StandardActionManager::createActionFolderMenu(QMenu *menu, Type type)
1798 {
1799  d->createActionFolderMenu(menu, type);
1800 }
1801 
1802 #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
QItemSelection::indexes
QModelIndexList indexes() const
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
QVariant::toLongLong
qlonglong toLongLong(bool *ok) const
QModelIndex
Akonadi::AgentManager::synchronizeCollection
void synchronizeCollection(const Collection &collection)
Trigger a synchronization of the given collection by its owning resource agent.
Definition: agentmanager.cpp:411
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
QWidget
QAbstractItemModel::rowCount
virtual int rowCount(const QModelIndex &parent) const =0
QMimeData::data
QByteArray data(const QString &mimeType) const
Akonadi::AgentManager::instances
AgentInstance::List instances() const
Returns the list of all available agent instances.
Definition: agentmanager.cpp:396
Akonadi::StandardActionManager::CreateCollection
Creates an collection.
Definition: standardactionmanager.h:134
QItemSelectionRange::bottom
int bottom() const
QAbstractItemModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const =0
Akonadi::StandardActionManager::MoveCollectionsToTrash
Moves the selected collection to trash and marks it as deleted, needs EntityDeletedAttribute.
Definition: standardactionmanager.h:162
QItemSelectionRange
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...
QClipboard::mimeData
const QMimeData * mimeData(Mode mode) const
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
QAbstractProxyModel
QByteArray
QByteArray::at
char at(int i) const
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
QAction::data
QVariant data() const
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...
QMap
QMenu::addAction
void addAction(QAction *action)
QPointer
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition: entity.h:65
QByteArray::isEmpty
bool isEmpty() const
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
QVariant::value
T value() const
QAbstractProxyModel::mapSelectionFromSource
virtual QItemSelection mapSelectionFromSource(const QItemSelection &sourceSelection) const
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
QList::toSet
QSet< T > toSet() const
Akonadi::AgentManager::removeInstance
void removeInstance(const AgentInstance &instance)
Removes the given agent instance.
Definition: agentmanager.cpp:406
QObject::disconnect
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QAbstractItemModel::dropMimeData
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Akonadi::Entity::setParentCollection
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition: entity.cpp:194
QMimeData
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
QMenu::isEmpty
bool isEmpty() const
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
QRegExp
QObject::name
const char * name() const
QModelIndex::isValid
bool isValid() const
QItemSelectionRange::top
int top() const
QList::count
int count(const T &value) const
Akonadi::AgentType
A representation of an agent type.
Definition: agenttype.h:58
QString::fromUtf8
QString fromUtf8(const char *str, int size)
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...
QMapIterator
QMenu::setIcon
void setIcon(const QIcon &icon)
QString::insert
QString & insert(int position, QChar ch)
QObject::property
QVariant property(const char *name) const
QVariant::toInt
int toInt(bool *ok) const
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...
QApplication::clipboard
QClipboard * clipboard()
QHash
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:401
Akonadi::ItemModel::IdRole
The id of the item.
Definition: itemmodel.h:74
Akonadi::SubscriptionDialog::showHiddenCollection
void showHiddenCollection(bool showHidden)
Definition: subscriptiondialog.cpp:186
QObject
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...
QAbstractProxyModel::mapSelectionToSource
virtual QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const
QItemSelectionModel::selection
const QItemSelection selection() const
QList::isEmpty
bool isEmpty() const
QObject::setObjectName
void setObjectName(const QString &name)
QItemSelectionRange::isEmpty
bool isEmpty() const
Akonadi::AgentInstance::isValid
bool isValid() const
Returns whether the agent instance object is valid.
Definition: agentinstance.cpp:45
QString::isEmpty
bool isEmpty() const
QString::trimmed
QString trimmed() const
QItemSelectionModel::selectedRows
QModelIndexList selectedRows(int column) const
Akonadi::StandardActionManager::MessageBoxTitle
The window title of a message box.
Definition: standardactionmanager.h:180
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
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.
QString::endsWith
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
QItemSelectionRange::parent
QModelIndex parent() const
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
QSet< QString >
QAbstractItemModel::data
virtual QVariant data(const QModelIndex &index, int role) const =0
QMenu::setTitle
void setTitle(const QString &title)
QList::first
T & first()
Akonadi::EntityTreeModel::CollectionRole
The collection.
Definition: entitytreemodel.h:336
QMenu::addSeparator
QAction * addSeparator()
QString
QList
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
QAbstractItemModel::mimeData
virtual QMimeData * mimeData(const QModelIndexList &indexes) const
QClipboard::setMimeData
void setMimeData(QMimeData *src, Mode mode)
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.
QStringList
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:1238
QAction::setData
void setData(const QVariant &userData)
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
QMenu
Akonadi::StandardActionManager::setContextText
void setContextText(Type type, TextContext context, const QString &text)
Sets the text of the action type for the given context.
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QLatin1Char
QList::contains
bool contains(const T &value) const
QMetaObject::invokeMethod
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
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
QItemSelection
QString::replace
QString & replace(int position, int n, QChar after)
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
QAbstractProxyModel::sourceModel
QAbstractItemModel * sourceModel() const
Akonadi::StandardActionManager::setFavoriteSelectionModel
void setFavoriteSelectionModel(QItemSelectionModel *selectionModel)
Sets the favorite collection selection model based on which the favorite collection related actions s...
QModelIndex::model
const QAbstractItemModel * model() const
Akonadi::StandardActionManager::DeleteResources
Deletes the selected resources.
Definition: standardactionmanager.h:153
QVector
Definition: kcolumnfilterproxymodel_p.h:27
QModelIndex::data
QVariant data(int role) const
Akonadi::EntityTreeModel::MimeTypeRole
The mimetype of the entity.
Definition: entitytreemodel.h:333
QItemSelectionRange::left
int left() const
Akonadi::EntityTreeModel::ItemRole
The Item.
Definition: entitytreemodel.h:332
QLatin1String
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
QString::count
int count() const
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:148
QMenu::addMenu
QAction * addMenu(QMenu *menu)
QAction
QClipboard::clear
void clear(Mode mode)
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
QAbstractItemModel
Akonadi::AgentManager::self
static AgentManager * self()
Returns the global instance of the agent manager.
Definition: agentmanager.cpp:377
QWeakPointer
QAbstractItemModel::setData
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
QSet::toList
QList< T > toList() const
QString::fromLatin1
QString fromLatin1(const char *str, int size)
QItemSelectionRange::model
const QAbstractItemModel * model() const
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
QAbstractItemModel::flags
virtual Qt::ItemFlags flags(const QModelIndex &index) const
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
QMimeData::setData
void setData(const QString &mimeType, const QByteArray &data)
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
QItemSelectionRange::isValid
bool isValid() const
Akonadi::StandardActionManager::StandardActionManager
StandardActionManager(KActionCollection *actionCollection, QWidget *parent=0)
Creates a new standard action manager.
QItemSelectionModel
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QVariant::toString
QString toString() const
QItemSelectionModel::model
const QAbstractItemModel * model() const
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
QAction::setEnabled
void setEnabled(bool)
QIcon
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
Qt::ItemFlags
typedef ItemFlags
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:38:03 by doxygen 1.8.7 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 API Reference

Skip menu "kdepimlibs 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

Search



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