• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.10 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
67using namespace Akonadi;
68
69//@cond PRIVATE
70
71enum 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
80static 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};
128static const int numStandardActionData = sizeof standardActionData / sizeof * standardActionData;
129
130BOOST_STATIC_ASSERT(numStandardActionData == StandardActionManager::LastType);
131
132static 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/*
147static inline bool isRootCollection( const Akonadi::Collection &collection )
148{
149 return (collection == Akonadi::Collection::root());
150}
151*/
152
153static void setWorkOffline(bool offline)
154{
155 KConfig config(QLatin1String("akonadikderc"));
156 KConfigGroup group(&config, QLatin1String("Actions"));
157
158 group.writeEntry("WorkOffline", offline);
159}
160
161static bool workOffline()
162{
163 KConfig config(QLatin1String("akonadikderc"));
164 const KConfigGroup group(&config, QLatin1String("Actions"));
165
166 return group.readEntry("WorkOffline", false);
167}
168
169static 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
197class StandardActionManager::Private
198{
199public:
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
1568StandardActionManager::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
1580StandardActionManager::~ StandardActionManager()
1581{
1582 delete d;
1583}
1584
1585void 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
1594void StandardActionManager::setItemSelectionModel(QItemSelectionModel *selectionModel)
1595{
1596 d->itemSelectionModel = selectionModel;
1597 connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1598 SLOT(updateActions()));
1599}
1600
1601void StandardActionManager::setFavoriteCollectionsModel(FavoriteCollectionsModel *favoritesModel)
1602{
1603 d->favoritesModel = favoritesModel;
1604 d->checkModelsConsistency();
1605}
1606
1607void StandardActionManager::setFavoriteSelectionModel(QItemSelectionModel *selectionModel)
1608{
1609 d->favoriteSelectionModel = selectionModel;
1610 connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
1611 SLOT(favoriteSelectionChanged()));
1612 d->checkModelsConsistency();
1613}
1614
1615KAction *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
1699void StandardActionManager::createAllActions()
1700{
1701 for (uint i = 0; i < LastType; ++i) {
1702 createAction((Type)i);
1703 }
1704}
1705
1706KAction *StandardActionManager::action(Type type) const
1707{
1708 Q_ASSERT(type < LastType);
1709 return d->actions[type];
1710}
1711
1712void StandardActionManager::setActionText(Type type, const KLocalizedString &text)
1713{
1714 Q_ASSERT(type < LastType);
1715 d->pluralLabels.insert(type, text);
1716 d->updateActions();
1717}
1718
1719void 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
1736Akonadi::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
1754Item::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
1772void StandardActionManager::setContextText(Type type, TextContext context, const QString &text)
1773{
1774 d->setContextText(type, context, text);
1775}
1776
1777void StandardActionManager::setContextText(Type type, TextContext context, const KLocalizedString &text)
1778{
1779 d->setContextText(type, context, text);
1780}
1781
1782void StandardActionManager::setMimeTypeFilter(const QStringList &mimeTypes)
1783{
1784 d->mMimeTypeFilter = mimeTypes;
1785}
1786
1787void StandardActionManager::setCapabilityFilter(const QStringList &capabilities)
1788{
1789 d->mCapabilityFilter = capabilities;
1790}
1791
1792void StandardActionManager::setCollectionPropertiesPageNames(const QStringList &names)
1793{
1794 d->mCollectionPropertiesPageNames = names;
1795}
1796
1797void StandardActionManager::createActionFolderMenu(QMenu *menu, Type type)
1798{
1799 d->createActionFolderMenu(menu, type);
1800}
1801
1802#include "moc_standardactionmanager.cpp"
Akonadi::ActionStateManager
A helper class to manage action states.
Definition actionstatemanager_p.h:36
Akonadi::AgentInstanceCreateJob
Job for creating new agent instances.
Definition agentinstancecreatejob.h:72
Akonadi::AgentInstanceCreateJob::start
void start()
Starts the instance creation.
Definition agentinstancecreatejob.cpp:176
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::AgentInstance
A representation of an agent instance.
Definition agentinstance.h:63
Akonadi::AgentInstance::configure
void configure(QWidget *parent=0)
Triggers the agent instance to show its configuration dialog.
Definition agentinstance.cpp:105
Akonadi::AgentInstance::synchronize
void synchronize()
Triggers the agent instance to start synchronization.
Definition agentinstance.cpp:110
Akonadi::AgentInstance::isValid
bool isValid() const
Returns whether the agent instance object is valid.
Definition agentinstance.cpp:45
Akonadi::AgentInstance::setIsOnline
void setIsOnline(bool online)
Sets online status of the agent instance.
Definition agentinstance.cpp:100
Akonadi::AgentInstance::type
AgentType type() const
Returns the agent type of this instance.
Definition agentinstance.cpp:50
Akonadi::AgentInstance::List
QList< AgentInstance > List
Describes a list of agent instances.
Definition agentinstance.h:71
Akonadi::AgentInstance::name
QString name() const
Returns the user visible name of the agent instance.
Definition agentinstance.cpp:65
Akonadi::AgentInstance::isOnline
bool isOnline() const
Returns whether the agent instance is online currently.
Definition agentinstance.cpp:95
Akonadi::AgentManager::self
static AgentManager * self()
Returns the global instance of the agent manager.
Definition agentmanager.cpp:377
Akonadi::AgentManager::removeInstance
void removeInstance(const AgentInstance &instance)
Removes the given agent instance.
Definition agentmanager.cpp:406
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::AgentManager::synchronizeCollection
void synchronizeCollection(const Collection &collection)
Trigger a synchronization of the given collection by its owning resource agent.
Definition agentmanager.cpp:411
Akonadi::AgentManager::instances
AgentInstance::List instances() const
Returns the list of all available agent instances.
Definition agentmanager.cpp:396
Akonadi::AgentTypeDialog
A dialog to select an available agent type.
Definition agenttypedialog.h:54
Akonadi::AgentType
A representation of an agent type.
Definition agenttype.h:59
Akonadi::AgentType::mimeTypes
QStringList mimeTypes() const
Returns the list of supported mime types of the agent type.
Definition agenttype.cpp:71
Akonadi::AgentType::isValid
bool isValid() const
Returns whether the agent type is valid.
Definition agenttype.cpp:41
Akonadi::CollectionCreateJob
Job that creates a new collection in the Akonadi storage.
Definition collectioncreatejob.h:53
Akonadi::CollectionDeleteJob
Job that deletes a collection in the Akonadi storage.
Definition collectiondeletejob.h:64
Akonadi::CollectionDialog
A collection selection dialog.
Definition collectiondialog.h:68
Akonadi::CollectionModel::CollectionRole
@ CollectionRole
The actual collection object.
Definition collectionmodel.h:66
Akonadi::CollectionPropertiesDialog
A generic and extensible dialog for collection properties.
Definition collectionpropertiesdialog.h:55
Akonadi::Collection
Represents a collection of PIM items.
Definition collection.h:76
Akonadi::Collection::contentMimeTypes
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
Definition collection.cpp:115
Akonadi::Collection::mimeType
static QString mimeType()
Returns the mimetype used for collections.
Definition collection.cpp:197
Akonadi::Collection::virtualMimeType
static QString virtualMimeType()
Returns the mimetype used for virtual collections.
Definition collection.cpp:202
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition collection.h:81
Akonadi::Collection::CanCreateItem
@ CanCreateItem
Can create new items in this collection.
Definition collection.h:89
Akonadi::Collection::CanCreateCollection
@ CanCreateCollection
Can create new subcollections in this collection.
Definition collection.h:92
Akonadi::EntityDeletedAttribute
An Attribute that marks that an entity was marked as deleted.
Definition entitydeletedattribute.h:50
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
Akonadi::EntityTreeModel::ParentCollectionRole
@ ParentCollectionRole
The parent collection of the entity.
Definition entitytreemodel.h:341
Akonadi::EntityTreeModel::ItemRole
@ ItemRole
The Item.
Definition entitytreemodel.h:332
Akonadi::EntityTreeModel::CollectionRole
@ CollectionRole
The collection.
Definition entitytreemodel.h:336
Akonadi::EntityTreeModel::PendingCutRole
@ PendingCutRole
Definition entitytreemodel.h:348
Akonadi::EntityTreeModel::MimeTypeRole
@ MimeTypeRole
The mimetype of the entity.
Definition entitytreemodel.h:333
Akonadi::Entity::isValid
bool isValid() const
Returns whether the entity is valid.
Definition entity.cpp:97
Akonadi::Entity::Id
qint64 Id
Describes the unique id type.
Definition entity.h:65
Akonadi::FavoriteCollectionsModel
A model that lists a set of favorite collections.
Definition favoritecollectionsmodel.h:67
Akonadi::ItemDeleteJob
Job that deletes items from the Akonadi storage.
Definition itemdeletejob.h:63
Akonadi::ItemModel::IdRole
@ IdRole
The id of the item.
Definition itemmodel.h:74
Akonadi::ItemModel::ItemRole
@ ItemRole
The item object.
Definition itemmodel.h:75
Akonadi::StandardActionManager
Manages generic actions for collection and item views.
Definition standardactionmanager.h:127
Akonadi::StandardActionManager::setCollectionSelectionModel
void setCollectionSelectionModel(QItemSelectionModel *selectionModel)
Sets the collection selection model based on which the collection related actions should operate.
Akonadi::StandardActionManager::setItemSelectionModel
void setItemSelectionModel(QItemSelectionModel *selectionModel)
Sets the item selection model based on which the item related actions should operate.
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::action
KAction * action(Type type) const
Returns the action of the given type, 0 if it has not been created (yet).
Akonadi::StandardActionManager::setContextText
void setContextText(Type type, TextContext context, const QString &text)
Sets the text of the action type for the given context.
Akonadi::StandardActionManager::Type
Type
Describes the supported actions.
Definition standardactionmanager.h:133
Akonadi::StandardActionManager::CreateResource
@ CreateResource
Creates a new resource.
Definition standardactionmanager.h:152
Akonadi::StandardActionManager::CreateCollection
@ CreateCollection
Creates an collection.
Definition standardactionmanager.h:134
Akonadi::StandardActionManager::SynchronizeResources
@ SynchronizeResources
Synchronizes the selected resources.
Definition standardactionmanager.h:155
Akonadi::StandardActionManager::DeleteItems
@ DeleteItems
Deletes the selected items.
Definition standardactionmanager.h:141
Akonadi::StandardActionManager::SynchronizeCollections
@ SynchronizeCollections
Synchronizes collections.
Definition standardactionmanager.h:137
Akonadi::StandardActionManager::RenameFavoriteCollection
@ RenameFavoriteCollection
Rename the collection of the favorite collections model.
Definition standardactionmanager.h:145
Akonadi::StandardActionManager::SynchronizeFavoriteCollections
@ SynchronizeFavoriteCollections
Synchronize favorite collections.
Definition standardactionmanager.h:170
Akonadi::StandardActionManager::LastType
@ LastType
Marks last action.
Definition standardactionmanager.h:171
Akonadi::StandardActionManager::CutItems
@ CutItems
Cuts the selected items.
Definition standardactionmanager.h:150
Akonadi::StandardActionManager::DeleteCollections
@ DeleteCollections
Deletes the selected collections.
Definition standardactionmanager.h:136
Akonadi::StandardActionManager::ToggleWorkOffline
@ ToggleWorkOffline
Toggles the work offline state of all resources.
Definition standardactionmanager.h:156
Akonadi::StandardActionManager::CutCollections
@ CutCollections
Cuts the selected collections.
Definition standardactionmanager.h:151
Akonadi::StandardActionManager::MoveItemsToTrash
@ MoveItemsToTrash
Moves the selected items to trash and marks them as deleted, needs EntityDeletedAttribute.
Definition standardactionmanager.h:163
Akonadi::StandardActionManager::CopyCollections
@ CopyCollections
Copies the selected collections.
Definition standardactionmanager.h:135
Akonadi::StandardActionManager::Paste
@ Paste
Paste collections or items.
Definition standardactionmanager.h:140
Akonadi::StandardActionManager::CollectionProperties
@ CollectionProperties
Provides collection properties.
Definition standardactionmanager.h:138
Akonadi::StandardActionManager::DeleteResources
@ DeleteResources
Deletes the selected resources.
Definition standardactionmanager.h:153
Akonadi::StandardActionManager::CopyItems
@ CopyItems
Copies the selected items.
Definition standardactionmanager.h:139
Akonadi::StandardActionManager::MoveCollectionsToTrash
@ MoveCollectionsToTrash
Moves the selected collection to trash and marks it as deleted, needs EntityDeletedAttribute.
Definition standardactionmanager.h:162
Akonadi::StandardActionManager::setCapabilityFilter
void setCapabilityFilter(const QStringList &capabilities)
Sets the capability filter that will be used when creating new resources.
Akonadi::StandardActionManager::createActionFolderMenu
void createActionFolderMenu(QMenu *menu, Type type)
Create a popup menu.
Akonadi::StandardActionManager::createAllActions
void createAllActions()
Convenience method to create all standard actions.
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::StandardActionManager::setFavoriteCollectionsModel
void setFavoriteCollectionsModel(FavoriteCollectionsModel *favoritesModel)
Sets the favorite collections model based on which the collection relatedactions should operate.
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::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::StandardActionManager
StandardActionManager(KActionCollection *actionCollection, QWidget *parent=0)
Creates a new standard action manager.
Akonadi::StandardActionManager::setMimeTypeFilter
void setMimeTypeFilter(const QStringList &mimeTypes)
Sets the mime type filter that will be used when creating new resources.
Akonadi::StandardActionManager::selectedCollections
Akonadi::Collection::List selectedCollections() const
Returns the list of collections that are currently selected.
Akonadi::StandardActionManager::selectedItems
Akonadi::Item::List selectedItems() const
Returns the list of items that are currently selected.
Akonadi::StandardActionManager::TextContext
TextContext
Describes the text context that can be customized.
Definition standardactionmanager.h:177
Akonadi::StandardActionManager::MessageBoxText
@ MessageBoxText
The text of a message box.
Definition standardactionmanager.h:181
Akonadi::StandardActionManager::DialogText
@ DialogText
The text of a dialog.
Definition standardactionmanager.h:179
Akonadi::StandardActionManager::ErrorMessageText
@ ErrorMessageText
The text of an error message.
Definition standardactionmanager.h:184
Akonadi::StandardActionManager::MessageBoxTitle
@ MessageBoxTitle
The window title of a message box.
Definition standardactionmanager.h:180
Akonadi::StandardActionManager::DialogTitle
@ DialogTitle
The window title of a dialog.
Definition standardactionmanager.h:178
Akonadi::StandardActionManager::ErrorMessageTitle
@ ErrorMessageTitle
The window title of an error message.
Definition standardactionmanager.h:183
Akonadi::StandardActionManager::setFavoriteSelectionModel
void setFavoriteSelectionModel(QItemSelectionModel *selectionModel)
Sets the favorite collection selection model based on which the favorite collection related actions s...
Akonadi::SubscriptionDialog
Definition subscriptiondialog_p.h:35
Akonadi::SubscriptionDialog::showHiddenCollection
void showHiddenCollection(bool showHidden)
Definition subscriptiondialog.cpp:186
Akonadi::TrashJob
Job that moves items/collection to trash.
Definition trashjob.h:67
Akonadi::TrashRestoreJob
Job that restores entites from trash.
Definition trashrestorejob.h:57
Akonadi
FreeBusyManager::Singleton.
Definition actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 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
  • Related Pages

kdepimlibs-4.14.10 API Reference

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