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

akonadi

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

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