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

akonadi

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

KDE's Doxygen guidelines are available online.

akonadi

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

kdepimlibs-4.11.3 API Reference

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

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