akonadi
standardactionmanager.cpp
00001 /* 00002 Copyright (c) 2008 Volker Krause <vkrause@kde.org> 00003 00004 This library is free software; you can redistribute it and/or modify it 00005 under the terms of the GNU Library General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or (at your 00007 option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, but WITHOUT 00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00012 License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to the 00016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00017 02110-1301, USA. 00018 */ 00019 00020 #include "standardactionmanager.h" 00021 00022 #include "actionstatemanager_p.h" 00023 #include "agentfilterproxymodel.h" 00024 #include "agentinstancecreatejob.h" 00025 #include "agentmanager.h" 00026 #include "agenttypedialog.h" 00027 #include "collectioncreatejob.h" 00028 #include "collectiondeletejob.h" 00029 #include "collectiondialog.h" 00030 #include "collectionmodel.h" 00031 #include "collectionutils_p.h" 00032 #include "entitytreemodel.h" 00033 #include "favoritecollectionsmodel.h" 00034 #include "itemdeletejob.h" 00035 #include "itemmodel.h" 00036 #include "metatypes.h" 00037 #include "pastehelper_p.h" 00038 #include "specialcollectionattribute_p.h" 00039 #include "collectionpropertiesdialog.h" 00040 #include "subscriptiondialog_p.h" 00041 00042 #include <KAction> 00043 #include <KActionCollection> 00044 #include <KActionMenu> 00045 #include <KDebug> 00046 #include <KInputDialog> 00047 #include <KLocale> 00048 #include <KMenu> 00049 #include <KMessageBox> 00050 #include <KToggleAction> 00051 00052 #include <QtCore/QMimeData> 00053 #include <QtGui/QApplication> 00054 #include <QtGui/QClipboard> 00055 #include <QtGui/QItemSelectionModel> 00056 00057 #include <boost/static_assert.hpp> 00058 00059 using namespace Akonadi; 00060 00061 //@cond PRIVATE 00062 00063 enum ActionType 00064 { 00065 NormalAction, 00066 MenuAction, 00067 ToggleAction 00068 }; 00069 00070 static const struct { 00071 const char *name; 00072 const char *label; 00073 const char *iconLabel; 00074 const char *icon; 00075 int shortcut; 00076 const char* slot; 00077 ActionType actionType; 00078 } standardActionData[] = { 00079 { "akonadi_collection_create", I18N_NOOP( "&New Folder..." ), I18N_NOOP( "New" ), "folder-new", 0, SLOT( slotCreateCollection() ), NormalAction }, 00080 { "akonadi_collection_copy", 0, 0, "edit-copy", 0, SLOT( slotCopyCollections() ), NormalAction }, 00081 { "akonadi_collection_delete", I18N_NOOP( "&Delete Folder" ), I18N_NOOP( "Delete" ), "edit-delete", 0, SLOT( slotDeleteCollection() ), NormalAction }, 00082 { "akonadi_collection_sync", I18N_NOOP( "&Synchronize Folder" ), I18N_NOOP( "Synchronize" ), "view-refresh", Qt::Key_F5, SLOT( slotSynchronizeCollection() ), NormalAction }, 00083 { "akonadi_collection_properties", I18N_NOOP( "Folder &Properties" ), I18N_NOOP( "Properties" ), "configure", 0, SLOT( slotCollectionProperties() ), NormalAction }, 00084 { "akonadi_item_copy", 0, 0, "edit-copy", 0, SLOT( slotCopyItems() ), NormalAction }, 00085 { "akonadi_paste", I18N_NOOP( "&Paste" ), I18N_NOOP( "Paste" ), "edit-paste", Qt::CTRL + Qt::Key_V, SLOT( slotPaste() ), NormalAction }, 00086 { "akonadi_item_delete", 0, 0, "edit-delete", Qt::Key_Delete, SLOT( slotDeleteItems() ), NormalAction }, 00087 { "akonadi_manage_local_subscriptions", I18N_NOOP( "Manage Local &Subscriptions..." ), I18N_NOOP( "Manage Local Subscriptions" ), 0, 0, SLOT( slotLocalSubscription() ), NormalAction }, 00088 { "akonadi_collection_add_to_favorites", I18N_NOOP( "Add to Favorite Folders" ), I18N_NOOP( "Add to Favorite" ), "bookmark-new", 0, SLOT( slotAddToFavorites() ), NormalAction }, 00089 { "akonadi_collection_remove_from_favorites", I18N_NOOP( "Remove from Favorite Folders" ), I18N_NOOP( "Remove from Favorite" ), "edit-delete", 0, SLOT( slotRemoveFromFavorites() ), NormalAction }, 00090 { "akonadi_collection_rename_favorite", I18N_NOOP( "Rename Favorite..." ), I18N_NOOP( "Rename" ), "edit-rename", 0, SLOT( slotRenameFavorite() ), NormalAction }, 00091 { "akonadi_collection_copy_to_menu", I18N_NOOP( "Copy Folder To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyCollectionTo( QAction* ) ), MenuAction }, 00092 { "akonadi_item_copy_to_menu", I18N_NOOP( "Copy Item To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyItemTo( QAction* ) ), MenuAction }, 00093 { "akonadi_item_move_to_menu", I18N_NOOP( "Move Item To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveItemTo( QAction* ) ), MenuAction }, 00094 { "akonadi_collection_move_to_menu", I18N_NOOP( "Move Folder To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveCollectionTo( QAction* ) ), MenuAction }, 00095 { "akonadi_item_cut", I18N_NOOP( "&Cut Item" ), I18N_NOOP( "Cut" ), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT( slotCutItems() ), NormalAction }, 00096 { "akonadi_collection_cut", I18N_NOOP( "&Cut Folder" ), I18N_NOOP( "Cut" ), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT( slotCutCollections() ), NormalAction }, 00097 { "akonadi_resource_create", I18N_NOOP( "Create Resource" ), 0, "folder-new", 0, SLOT( slotCreateResource() ), NormalAction }, 00098 { "akonadi_resource_delete", I18N_NOOP( "Delete Resource" ), 0, "edit-delete", 0, SLOT( slotDeleteResource() ), NormalAction }, 00099 { "akonadi_resource_properties", I18N_NOOP( "&Resource Properties" ), I18N_NOOP( "Properties" ), "configure", 0, SLOT( slotResourceProperties() ), NormalAction }, 00100 { "akonadi_resource_synchronize", I18N_NOOP( "Synchronize Resource" ), I18N_NOOP( "Synchronize" ), "view-refresh", 0, SLOT( slotSynchronizeResource() ), NormalAction }, 00101 { "akonadi_work_offline", I18N_NOOP( "Work Offline" ), 0, "user-offline", 0, SLOT( slotToggleWorkOffline(bool) ), ToggleAction }, 00102 { "akonadi_collection_copy_to_dialog", I18N_NOOP( "Copy Folder To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyCollectionTo() ), NormalAction }, 00103 { "akonadi_collection_move_to_dialog", I18N_NOOP( "Move Folder To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveCollectionTo() ), NormalAction }, 00104 { "akonadi_item_copy_to_dialog", I18N_NOOP( "Copy Item To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyItemTo() ), NormalAction }, 00105 { "akonadi_item_move_to_dialog", I18N_NOOP( "Move Item To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveItemTo() ), NormalAction }, 00106 { "akonadi_collection_sync_recursive", I18N_NOOP( "&Synchronize Folder Recursively" ), I18N_NOOP( "Synchronize Recursively" ), "view-refresh", Qt::CTRL + Qt::Key_F5, SLOT( slotSynchronizeCollectionRecursive() ), NormalAction } 00107 }; 00108 static const int numStandardActionData = sizeof standardActionData / sizeof *standardActionData; 00109 00110 BOOST_STATIC_ASSERT( numStandardActionData == StandardActionManager::LastType ); 00111 00112 static bool canCreateCollection( const Akonadi::Collection &collection ) 00113 { 00114 if ( !( collection.rights() & Akonadi::Collection::CanCreateCollection ) ) 00115 return false; 00116 00117 if ( !collection.contentMimeTypes().contains( Akonadi::Collection::mimeType() ) ) 00118 return false; 00119 00120 return true; 00121 } 00122 00123 static inline bool isRootCollection( const Akonadi::Collection &collection ) 00124 { 00125 return (collection == Akonadi::Collection::root()); 00126 } 00127 00128 static void setWorkOffline( bool offline ) 00129 { 00130 KConfig config( QLatin1String( "akonadikderc" ) ); 00131 KConfigGroup group( &config, QLatin1String( "Actions" ) ); 00132 00133 group.writeEntry( "WorkOffline", offline ); 00134 } 00135 00136 static bool workOffline() 00137 { 00138 KConfig config( QLatin1String( "akonadikderc" ) ); 00139 const KConfigGroup group( &config, QLatin1String( "Actions" ) ); 00140 00141 return group.readEntry( "WorkOffline", false ); 00142 } 00143 00147 class StandardActionManager::Private 00148 { 00149 public: 00150 Private( StandardActionManager *parent ) : 00151 q( parent ), 00152 collectionSelectionModel( 0 ), 00153 itemSelectionModel( 0 ), 00154 favoritesModel( 0 ), 00155 favoriteSelectionModel( 0 ) 00156 { 00157 actions.fill( 0, StandardActionManager::LastType ); 00158 00159 pluralLabels.insert( StandardActionManager::CopyCollections, 00160 ki18np( "&Copy Folder", "&Copy %1 Folders" ) ); 00161 pluralLabels.insert( StandardActionManager::CopyItems, 00162 ki18np( "&Copy Item", "&Copy %1 Items" ) ); 00163 pluralLabels.insert( StandardActionManager::CutItems, 00164 ki18np( "&Cut Item", "&Cut %1 Items" ) ); 00165 pluralLabels.insert( StandardActionManager::CutCollections, 00166 ki18np( "&Cut Folder", "&Cut %1 Folders" ) ); 00167 pluralLabels.insert( StandardActionManager::DeleteItems, 00168 ki18np( "&Delete Item", "&Delete %1 Items" ) ); 00169 pluralLabels.insert( StandardActionManager::DeleteCollections, 00170 ki18np( "&Delete Folder", "&Delete %1 Folders" ) ); 00171 pluralLabels.insert( StandardActionManager::SynchronizeCollections, 00172 ki18np( "&Synchronize Folder", "&Synchronize %1 Folders" ) ); 00173 pluralLabels.insert( StandardActionManager::DeleteResources, 00174 ki18np( "&Delete Resource", "&Delete %1 Resources" ) ); 00175 pluralLabels.insert( StandardActionManager::SynchronizeResources, 00176 ki18np( "&Synchronize Resource", "&Synchronize %1 Resources" ) ); 00177 00178 pluralIconLabels.insert( StandardActionManager::CopyCollections, 00179 ki18np( "Copy Folder", "Copy %1 Folders" ) ); 00180 pluralIconLabels.insert( StandardActionManager::CopyItems, 00181 ki18np( "Copy Item", "Copy %1 Items" ) ); 00182 pluralIconLabels.insert( StandardActionManager::CutItems, 00183 ki18np( "Cut Item", "Cut %1 Items" ) ); 00184 pluralIconLabels.insert( StandardActionManager::CutCollections, 00185 ki18np( "Cut Folder", "Cut %1 Folders" ) ); 00186 pluralIconLabels.insert( StandardActionManager::DeleteItems, 00187 ki18np( "Delete Item", "Delete %1 Items" ) ); 00188 pluralIconLabels.insert( StandardActionManager::DeleteCollections, 00189 ki18np( "Delete Folder", "Delete %1 Folders" ) ); 00190 pluralIconLabels.insert( StandardActionManager::SynchronizeCollections, 00191 ki18np( "Synchronize Folder", "Synchronize %1 Folders" ) ); 00192 pluralIconLabels.insert( StandardActionManager::DeleteResources, 00193 ki18np( "Delete Resource", "Delete %1 Resources" ) ); 00194 pluralIconLabels.insert( StandardActionManager::SynchronizeResources, 00195 ki18np( "Synchronize Resource", "Synchronize %1 Resources" ) ); 00196 00197 setContextText( StandardActionManager::CreateCollection, StandardActionManager::DialogTitle, 00198 i18nc( "@title:window", "New Folder" ) ); 00199 setContextText( StandardActionManager::CreateCollection, StandardActionManager::DialogText, 00200 i18nc( "@label:textbox name of a thing", "Name" ) ); 00201 setContextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText, 00202 i18n( "Could not create folder: %1" ) ); 00203 setContextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle, 00204 i18n( "Folder creation failed" ) ); 00205 00206 setContextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText, 00207 ki18np( "Do you really want to delete this folder and all its sub-folders?", 00208 "Do you really want to delete %1 folders and all their sub-folders?" ) ); 00209 setContextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, 00210 ki18ncp( "@title:window", "Delete folder?", "Delete folders?" ) ); 00211 setContextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText, 00212 i18n( "Could not delete folder: %1" ) ); 00213 setContextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle, 00214 i18n( "Folder deletion failed" ) ); 00215 00216 setContextText( StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle, 00217 i18nc( "@title:window", "Properties of Folder %1" ) ); 00218 00219 setContextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, 00220 ki18np( "Do you really want to delete the selected item?", 00221 "Do you really want to delete %1 items?" ) ); 00222 setContextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, 00223 ki18ncp( "@title:window", "Delete item?", "Delete items?" ) ); 00224 setContextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText, 00225 i18n( "Could not delete item: %1" ) ); 00226 setContextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle, 00227 i18n( "Item deletion failed" ) ); 00228 00229 setContextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle, 00230 i18nc( "@title:window", "Rename Favorite" ) ); 00231 setContextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText, 00232 i18nc( "@label:textbox name of the folder", "Name:" ) ); 00233 00234 setContextText( StandardActionManager::CreateResource, StandardActionManager::DialogTitle, 00235 i18nc( "@title:window", "New Resource" ) ); 00236 setContextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText, 00237 i18n( "Could not create resource: %1" ) ); 00238 setContextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle, 00239 i18n( "Resource creation failed" ) ); 00240 00241 setContextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, 00242 ki18np( "Do you really want to delete this resource?", 00243 "Do you really want to delete %1 resources?" ) ); 00244 setContextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, 00245 ki18ncp( "@title:window", "Delete Resource?", "Delete Resources?" ) ); 00246 00247 setContextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageText, 00248 i18n( "Could not paste data: %1" ) ); 00249 setContextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle, 00250 i18n( "Paste failed" ) ); 00251 00252 qRegisterMetaType<Akonadi::Item::List>("Akonadi::Item::List"); 00253 } 00254 00255 void enableAction( int type, bool enable ) 00256 { 00257 enableAction( static_cast<StandardActionManager::Type>( type ), enable ); 00258 } 00259 00260 void enableAction( StandardActionManager::Type type, bool enable ) 00261 { 00262 Q_ASSERT( type < StandardActionManager::LastType ); 00263 if ( actions[type] ) 00264 actions[type]->setEnabled( enable ); 00265 00266 // Update the action menu 00267 KActionMenu *actionMenu = qobject_cast<KActionMenu*>( actions[type] ); 00268 if ( actionMenu ) { 00269 //get rid of the submenus, they are re-created in enableAction. clear() is not enough, doesn't remove the submenu object instances. 00270 KMenu *menu = actionMenu->menu(); 00271 //Not necessary to delete and recreate menu when it was not created 00272 if ( menu->property( "actionType" ).isValid() && menu->isEmpty() ) 00273 return; 00274 delete menu; 00275 menu = new KMenu(); 00276 00277 menu->setProperty( "actionType", static_cast<int>( type ) ); 00278 q->connect( menu, SIGNAL( aboutToShow() ), SLOT( aboutToShowMenu() ) ); 00279 q->connect( menu, SIGNAL( triggered( QAction* ) ), standardActionData[ type ].slot ); 00280 actionMenu->setMenu( menu ); 00281 } 00282 } 00283 00284 void aboutToShowMenu() 00285 { 00286 QMenu *menu = qobject_cast<QMenu*>( q->sender() ); 00287 if ( !menu ) 00288 return; 00289 00290 if ( !menu->isEmpty() ) 00291 return; 00292 const StandardActionManager::Type type = static_cast<StandardActionManager::Type>( menu->property( "actionType" ).toInt() ); 00293 00294 fillFoldersMenu( type, 00295 menu, 00296 collectionSelectionModel->model(), 00297 QModelIndex() ); 00298 } 00299 00300 void updatePluralLabel( int type, int count ) 00301 { 00302 updatePluralLabel( static_cast<StandardActionManager::Type>( type ), count ); 00303 } 00304 00305 void updatePluralLabel( StandardActionManager::Type type, int count ) 00306 { 00307 Q_ASSERT( type < StandardActionManager::LastType ); 00308 if ( actions[type] && pluralLabels.contains( type ) && !pluralLabels.value( type ).isEmpty() ) { 00309 actions[type]->setText( pluralLabels.value( type ).subs( qMax( count, 1 ) ).toString() ); 00310 } 00311 } 00312 00313 bool isFavoriteCollection( const Akonadi::Collection &collection ) 00314 { 00315 if ( !favoritesModel ) 00316 return false; 00317 00318 return favoritesModel->collections().contains( collection ); 00319 } 00320 00321 void encodeToClipboard( QItemSelectionModel* selectionModel, bool cut = false ) 00322 { 00323 Q_ASSERT( selectionModel ); 00324 if ( selectionModel->selectedRows().count() <= 0 ) 00325 return; 00326 00327 #ifndef QT_NO_CLIPBOARD 00328 QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() ); 00329 markCutAction( mimeData, cut ); 00330 QApplication::clipboard()->setMimeData( mimeData ); 00331 00332 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( selectionModel->model() ); 00333 00334 foreach ( const QModelIndex &index, selectionModel->selectedRows() ) 00335 model->setData( index, true, EntityTreeModel::PendingCutRole ); 00336 #endif 00337 } 00338 00339 void updateActions() 00340 { 00341 // collect all selected collections 00342 Collection::List selectedCollections; 00343 if ( collectionSelectionModel ) { 00344 const QModelIndexList rows = collectionSelectionModel->selectedRows(); 00345 foreach ( const QModelIndex &index, rows ) { 00346 Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>(); 00347 if ( !collection.isValid() ) 00348 continue; 00349 00350 const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>(); 00351 collection.setParentCollection( parentCollection ); 00352 00353 selectedCollections << collection; 00354 } 00355 } 00356 00357 // collect all selected items 00358 Item::List selectedItems; 00359 if ( itemSelectionModel ) { 00360 const QModelIndexList rows = itemSelectionModel->selectedRows(); 00361 foreach ( const QModelIndex &index, rows ) { 00362 Item item = index.data( EntityTreeModel::ItemRole ).value<Item>(); 00363 if ( !item.isValid() ) 00364 continue; 00365 00366 const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>(); 00367 item.setParentCollection( parentCollection ); 00368 00369 selectedItems << item; 00370 } 00371 } 00372 00373 mActionStateManager.updateState( selectedCollections, selectedItems ); 00374 00375 emit q->actionStateUpdated(); 00376 } 00377 00378 #ifndef QT_NO_CLIPBOARD 00379 void clipboardChanged( QClipboard::Mode mode ) 00380 { 00381 if ( mode == QClipboard::Clipboard ) 00382 updateActions(); 00383 } 00384 #endif 00385 00386 QItemSelection mapToEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const 00387 { 00388 const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ); 00389 if ( proxy ) { 00390 return mapToEntityTreeModel( proxy->sourceModel(), proxy->mapSelectionToSource( selection ) ); 00391 } else { 00392 return selection; 00393 } 00394 } 00395 00396 QItemSelection mapFromEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const 00397 { 00398 const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ); 00399 if ( proxy ) { 00400 const QItemSelection select = mapFromEntityTreeModel( proxy->sourceModel(), selection ); 00401 return proxy->mapSelectionFromSource( select ); 00402 } else { 00403 return selection; 00404 } 00405 } 00406 00407 void collectionSelectionChanged() 00408 { 00409 q->blockSignals( true ); 00410 00411 QItemSelection selection = collectionSelectionModel->selection(); 00412 selection = mapToEntityTreeModel( collectionSelectionModel->model(), selection ); 00413 selection = mapFromEntityTreeModel( favoritesModel, selection ); 00414 00415 if ( favoriteSelectionModel ) 00416 favoriteSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect ); 00417 00418 q->blockSignals( false ); 00419 00420 updateActions(); 00421 } 00422 00423 void favoriteSelectionChanged() 00424 { 00425 q->blockSignals( true ); 00426 00427 QItemSelection selection = favoriteSelectionModel->selection(); 00428 if ( selection.indexes().isEmpty() ) 00429 return; 00430 00431 selection = mapToEntityTreeModel( favoritesModel, selection ); 00432 selection = mapFromEntityTreeModel( collectionSelectionModel->model(), selection ); 00433 00434 collectionSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); 00435 q->blockSignals( false ); 00436 00437 updateActions(); 00438 } 00439 00440 void slotCreateCollection() 00441 { 00442 Q_ASSERT( collectionSelectionModel ); 00443 if ( collectionSelectionModel->selection().indexes().isEmpty() ) 00444 return; 00445 00446 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 ); 00447 Q_ASSERT( index.isValid() ); 00448 const Collection parentCollection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00449 Q_ASSERT( parentCollection.isValid() ); 00450 00451 if ( !canCreateCollection( parentCollection ) ) 00452 return; 00453 00454 const QString name = KInputDialog::getText( contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogTitle ), 00455 contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogText ), 00456 QString(), 0, parentWidget ); 00457 if ( name.isEmpty() ) 00458 return; 00459 00460 Collection collection; 00461 collection.setName( name ); 00462 collection.setParentCollection( parentCollection ); 00463 if ( actions[StandardActionManager::CreateCollection] ) { 00464 const QStringList mts = actions[StandardActionManager::CreateCollection]->property( "ContentMimeTypes" ).toStringList(); 00465 if ( !mts.isEmpty() ) 00466 collection.setContentMimeTypes( mts ); 00467 } 00468 CollectionCreateJob *job = new CollectionCreateJob( collection ); 00469 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionCreationResult( KJob* ) ) ); 00470 } 00471 00472 void slotCopyCollections() 00473 { 00474 encodeToClipboard( collectionSelectionModel ); 00475 } 00476 00477 void slotCutCollections() 00478 { 00479 encodeToClipboard( collectionSelectionModel, true ); 00480 } 00481 00482 Collection::List selectedCollections() const 00483 { 00484 Collection::List collections; 00485 00486 Q_ASSERT( collectionSelectionModel ); 00487 00488 foreach ( const QModelIndex &index, collectionSelectionModel->selectedRows() ) { 00489 Q_ASSERT( index.isValid() ); 00490 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00491 Q_ASSERT( collection.isValid() ); 00492 00493 collections << collection; 00494 } 00495 00496 return collections; 00497 } 00498 00499 void slotDeleteCollection() 00500 { 00501 const Collection::List collections = selectedCollections(); 00502 if ( collections.isEmpty() ) 00503 return; 00504 00505 const QString collectionName = collections.first().name(); 00506 const QString text = contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText, 00507 collections.count(), collectionName ); 00508 00509 if ( KMessageBox::questionYesNo( parentWidget, text, 00510 contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, collections.count(), collectionName ), 00511 KStandardGuiItem::del(), KStandardGuiItem::cancel(), 00512 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes ) 00513 return; 00514 00515 foreach ( const Collection &collection, collections ) { 00516 CollectionDeleteJob *job = new CollectionDeleteJob( collection, q ); 00517 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionDeletionResult( KJob* ) ) ); 00518 } 00519 } 00520 00521 void slotSynchronizeCollection() 00522 { 00523 Q_ASSERT( collectionSelectionModel ); 00524 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00525 if ( list.isEmpty() ) 00526 return; 00527 00528 const Collection::List collections = selectedCollections(); 00529 if ( collections.isEmpty() ) 00530 return; 00531 00532 foreach( Collection collection, collections ) { 00533 AgentManager::self()->synchronizeCollection( collection, false ); 00534 } 00535 } 00536 00537 void slotSynchronizeCollectionRecursive() 00538 { 00539 Q_ASSERT( collectionSelectionModel ); 00540 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00541 if ( list.isEmpty() ) 00542 return; 00543 00544 const Collection::List collections = selectedCollections(); 00545 if ( collections.isEmpty() ) 00546 return; 00547 00548 foreach( Collection collection, collections ) { 00549 AgentManager::self()->synchronizeCollection( collection, true ); 00550 } 00551 } 00552 00553 void slotCollectionProperties() 00554 { 00555 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00556 if ( list.isEmpty() ) 00557 return; 00558 00559 const QModelIndex index = list.first(); 00560 Q_ASSERT( index.isValid() ); 00561 00562 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00563 Q_ASSERT( collection.isValid() ); 00564 00565 const QString displayName = collection.hasAttribute<EntityDisplayAttribute>() ? collection.attribute<EntityDisplayAttribute>()->displayName() 00566 : collection.name(); 00567 00568 CollectionPropertiesDialog* dlg = new CollectionPropertiesDialog( collection, mCollectionPropertiesPageNames, parentWidget ); 00569 dlg->setCaption( contextText( StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle ).arg( displayName ) ); 00570 dlg->show(); 00571 } 00572 00573 void slotCopyItems() 00574 { 00575 encodeToClipboard( itemSelectionModel ); 00576 } 00577 00578 void slotCutItems() 00579 { 00580 encodeToClipboard( itemSelectionModel, true ); 00581 } 00582 00583 void slotPaste() 00584 { 00585 Q_ASSERT( collectionSelectionModel ); 00586 00587 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00588 if ( list.isEmpty() ) 00589 return; 00590 00591 const QModelIndex index = list.first(); 00592 Q_ASSERT( index.isValid() ); 00593 00594 #ifndef QT_NO_CLIPBOARD 00595 // TODO: Copy or move? We can't seem to cut yet 00596 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( collectionSelectionModel->model() ); 00597 const QMimeData *mimeData = QApplication::clipboard()->mimeData(); 00598 model->dropMimeData( mimeData, isCutAction( mimeData ) ? Qt::MoveAction : Qt::CopyAction, -1, -1, index ); 00599 model->setData( QModelIndex(), false, EntityTreeModel::PendingCutRole ); 00600 QApplication::clipboard()->clear(); 00601 #endif 00602 } 00603 00604 void slotDeleteItems() 00605 { 00606 Q_ASSERT( itemSelectionModel ); 00607 00608 Item::List items; 00609 foreach ( const QModelIndex &index, itemSelectionModel->selectedRows() ) { 00610 bool ok; 00611 const qlonglong id = index.data( ItemModel::IdRole ).toLongLong( &ok ); 00612 Q_ASSERT( ok ); 00613 items << Item( id ); 00614 } 00615 00616 if ( items.isEmpty() ) 00617 return; 00618 00619 QMetaObject::invokeMethod(q, "slotDeleteItemsDeferred", 00620 Qt::QueuedConnection, 00621 Q_ARG(Akonadi::Item::List, items)); 00622 } 00623 00624 void slotDeleteItemsDeferred(const Akonadi::Item::List &items) 00625 { 00626 Q_ASSERT( itemSelectionModel ); 00627 00628 if ( KMessageBox::questionYesNo( parentWidget, 00629 contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, items.count(), QString() ), 00630 contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, items.count(), QString() ), 00631 KStandardGuiItem::del(), KStandardGuiItem::cancel(), 00632 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes ) 00633 return; 00634 00635 ItemDeleteJob *job = new ItemDeleteJob( items, q ); 00636 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( itemDeletionResult( KJob* ) ) ); 00637 } 00638 00639 void slotLocalSubscription() 00640 { 00641 SubscriptionDialog* dlg = new SubscriptionDialog( mMimeTypeFilter, parentWidget ); 00642 dlg->show(); 00643 } 00644 00645 void slotAddToFavorites() 00646 { 00647 Q_ASSERT( collectionSelectionModel ); 00648 Q_ASSERT( favoritesModel ); 00649 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00650 if ( list.isEmpty() ) 00651 return; 00652 00653 foreach ( const QModelIndex &index, list ) { 00654 Q_ASSERT( index.isValid() ); 00655 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00656 Q_ASSERT( collection.isValid() ); 00657 00658 favoritesModel->addCollection( collection ); 00659 } 00660 00661 updateActions(); 00662 } 00663 00664 void slotRemoveFromFavorites() 00665 { 00666 Q_ASSERT( collectionSelectionModel ); 00667 Q_ASSERT( favoritesModel ); 00668 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00669 if ( list.isEmpty() ) 00670 return; 00671 00672 foreach ( const QModelIndex &index, list ) { 00673 Q_ASSERT( index.isValid() ); 00674 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00675 Q_ASSERT( collection.isValid() ); 00676 00677 favoritesModel->removeCollection( collection ); 00678 } 00679 00680 updateActions(); 00681 } 00682 00683 void slotRenameFavorite() 00684 { 00685 Q_ASSERT( collectionSelectionModel ); 00686 Q_ASSERT( favoritesModel ); 00687 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00688 if ( list.isEmpty() ) 00689 return; 00690 00691 const QModelIndex index = list.first(); 00692 Q_ASSERT( index.isValid() ); 00693 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00694 Q_ASSERT( collection.isValid() ); 00695 00696 bool ok; 00697 const QString label = KInputDialog::getText( contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle ), 00698 contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText ), 00699 favoritesModel->favoriteLabel( collection ), &ok, parentWidget ); 00700 if ( !ok ) 00701 return; 00702 00703 favoritesModel->setFavoriteLabel( collection, label ); 00704 } 00705 00706 void slotCopyCollectionTo() 00707 { 00708 pasteTo( collectionSelectionModel, collectionSelectionModel->model(), CopyCollectionToMenu, Qt::CopyAction ); 00709 } 00710 00711 void slotCopyItemTo() 00712 { 00713 pasteTo( itemSelectionModel, collectionSelectionModel->model(), CopyItemToMenu, Qt::CopyAction ); 00714 } 00715 00716 void slotMoveCollectionTo() 00717 { 00718 pasteTo( collectionSelectionModel, collectionSelectionModel->model(), MoveCollectionToMenu, Qt::MoveAction ); 00719 } 00720 00721 void slotMoveItemTo() 00722 { 00723 pasteTo( itemSelectionModel, collectionSelectionModel->model(), MoveItemToMenu, Qt::MoveAction ); 00724 } 00725 00726 void slotCopyCollectionTo( QAction *action ) 00727 { 00728 pasteTo( collectionSelectionModel, action, Qt::CopyAction ); 00729 } 00730 00731 void slotCopyItemTo( QAction *action ) 00732 { 00733 pasteTo( itemSelectionModel, action, Qt::CopyAction ); 00734 } 00735 00736 void slotMoveCollectionTo( QAction *action ) 00737 { 00738 pasteTo( collectionSelectionModel, action, Qt::MoveAction ); 00739 } 00740 00741 void slotMoveItemTo( QAction *action ) 00742 { 00743 pasteTo( itemSelectionModel, action, Qt::MoveAction ); 00744 } 00745 00746 AgentInstance::List selectedAgentInstances() const 00747 { 00748 AgentInstance::List instances; 00749 00750 Q_ASSERT( collectionSelectionModel ); 00751 if ( collectionSelectionModel->selection().indexes().isEmpty() ) 00752 return instances; 00753 00754 foreach ( const QModelIndex &index, collectionSelectionModel->selection().indexes() ) { 00755 Q_ASSERT( index.isValid() ); 00756 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00757 Q_ASSERT( collection.isValid() ); 00758 00759 if ( collection.isValid() ) { 00760 const QString identifier = collection.resource(); 00761 instances << AgentManager::self()->instance( identifier ); 00762 } 00763 } 00764 00765 return instances; 00766 } 00767 00768 AgentInstance selectedAgentInstance() const 00769 { 00770 const AgentInstance::List instances = selectedAgentInstances(); 00771 00772 if ( instances.isEmpty() ) 00773 return AgentInstance(); 00774 00775 return instances.first(); 00776 } 00777 00778 void slotCreateResource() 00779 { 00780 Akonadi::AgentTypeDialog dlg( parentWidget ); 00781 dlg.setCaption( contextText( StandardActionManager::CreateResource, StandardActionManager::DialogTitle ) ); 00782 00783 foreach ( const QString &mimeType, mMimeTypeFilter ) 00784 dlg.agentFilterProxyModel()->addMimeTypeFilter( mimeType ); 00785 00786 foreach ( const QString &capability, mCapabilityFilter ) 00787 dlg.agentFilterProxyModel()->addCapabilityFilter( capability ); 00788 00789 if ( dlg.exec() ) { 00790 const AgentType agentType = dlg.agentType(); 00791 00792 if ( agentType.isValid() ) { 00793 AgentInstanceCreateJob *job = new AgentInstanceCreateJob( agentType, q ); 00794 q->connect( job, SIGNAL( result( KJob* ) ), SLOT( resourceCreationResult( KJob* ) ) ); 00795 job->configure( parentWidget ); 00796 job->start(); 00797 } 00798 } 00799 } 00800 00801 void slotDeleteResource() 00802 { 00803 const AgentInstance::List instances = selectedAgentInstances(); 00804 if ( instances.isEmpty() ) 00805 return; 00806 00807 if ( KMessageBox::questionYesNo( parentWidget, 00808 contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, instances.count(), instances.first().name() ), 00809 contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, instances.count(), instances.first().name() ), 00810 KStandardGuiItem::del(), KStandardGuiItem::cancel(), 00811 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes ) 00812 return; 00813 00814 foreach ( const AgentInstance &instance, instances ) 00815 AgentManager::self()->removeInstance( instance ); 00816 } 00817 00818 void slotSynchronizeResource() 00819 { 00820 const AgentInstance::List instances = selectedAgentInstances(); 00821 if ( instances.isEmpty() ) 00822 return; 00823 00824 foreach ( AgentInstance instance, instances ) 00825 instance.synchronize(); 00826 } 00827 00828 void slotResourceProperties() 00829 { 00830 AgentInstance instance = selectedAgentInstance(); 00831 if ( !instance.isValid() ) 00832 return; 00833 00834 instance.configure( parentWidget ); 00835 } 00836 00837 void slotToggleWorkOffline( bool offline ) 00838 { 00839 setWorkOffline( offline ); 00840 00841 AgentInstance::List instances = AgentManager::self()->instances(); 00842 foreach ( AgentInstance instance, instances ) { 00843 instance.setIsOnline( !offline ); 00844 } 00845 } 00846 00847 void pasteTo( QItemSelectionModel *selectionModel, const QAbstractItemModel *model, StandardActionManager::Type type, Qt::DropAction dropAction ) 00848 { 00849 const QSet<QString> mimeTypes = mimeTypesOfSelection( type ); 00850 00851 CollectionDialog dlg( const_cast<QAbstractItemModel*>( model ) ); 00852 dlg.setMimeTypeFilter( mimeTypes.toList() ); 00853 00854 if ( type == CopyItemToMenu || type == MoveItemToMenu ) 00855 dlg.setAccessRightsFilter( Collection::CanCreateItem ); 00856 else if ( type == CopyCollectionToMenu || type == MoveCollectionToMenu ) 00857 dlg.setAccessRightsFilter( Collection::CanCreateCollection ); 00858 00859 if ( dlg.exec() ) { 00860 const QModelIndex index = EntityTreeModel::modelIndexForCollection( collectionSelectionModel->model(), dlg.selectedCollection() ); 00861 if ( !index.isValid() ) 00862 return; 00863 00864 const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() ); 00865 00866 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() ); 00867 model->dropMimeData( mimeData, dropAction, -1, -1, index ); 00868 } 00869 } 00870 00871 void pasteTo( QItemSelectionModel *selectionModel, QAction *action, Qt::DropAction dropAction ) 00872 { 00873 Q_ASSERT( selectionModel ); 00874 Q_ASSERT( action ); 00875 00876 if ( selectionModel->selectedRows().count() <= 0 ) 00877 return; 00878 00879 const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() ); 00880 00881 const QModelIndex index = action->data().value<QModelIndex>(); 00882 00883 Q_ASSERT( index.isValid() ); 00884 00885 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() ); 00886 model->dropMimeData( mimeData, dropAction, -1, -1, index ); 00887 } 00888 00889 void collectionCreationResult( KJob *job ) 00890 { 00891 if ( job->error() ) { 00892 KMessageBox::error( parentWidget, 00893 contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00894 contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle ) ); 00895 } 00896 } 00897 00898 void collectionDeletionResult( KJob *job ) 00899 { 00900 if ( job->error() ) { 00901 KMessageBox::error( parentWidget, 00902 contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00903 contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle ) ); 00904 } 00905 } 00906 00907 void itemDeletionResult( KJob *job ) 00908 { 00909 if ( job->error() ) { 00910 KMessageBox::error( parentWidget, 00911 contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00912 contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle ) ); 00913 } 00914 } 00915 00916 void resourceCreationResult( KJob *job ) 00917 { 00918 if ( job->error() ) { 00919 KMessageBox::error( parentWidget, 00920 contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00921 contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle ) ); 00922 } 00923 } 00924 00925 void pasteResult( KJob *job ) 00926 { 00927 if ( job->error() ) { 00928 KMessageBox::error( parentWidget, 00929 contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00930 contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle ) ); 00931 } 00932 } 00933 00937 QSet<QString> mimeTypesOfSelection( StandardActionManager::Type type ) const 00938 { 00939 QModelIndexList list; 00940 QSet<QString> mimeTypes; 00941 00942 const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu ); 00943 const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu ); 00944 00945 if ( isItemAction ) { 00946 list = itemSelectionModel->selectedRows(); 00947 foreach ( const QModelIndex &index, list ) 00948 mimeTypes << index.data( EntityTreeModel::MimeTypeRole ).toString(); 00949 } 00950 00951 if ( isCollectionAction ) { 00952 list = collectionSelectionModel->selectedRows(); 00953 foreach ( const QModelIndex &index, list ) { 00954 const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>(); 00955 00956 // The mimetypes that the selected collection can possibly contain 00957 mimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet(); 00958 } 00959 } 00960 00961 return mimeTypes; 00962 } 00963 00967 bool isWritableTargetCollectionForMimeTypes( const Collection &collection, const QSet<QString> &mimeTypes, StandardActionManager::Type type ) const 00968 { 00969 if ( CollectionUtils::isVirtual( collection ) ) 00970 return false; 00971 00972 const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu ); 00973 const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu ); 00974 00975 const bool canContainRequiredMimeTypes = !collection.contentMimeTypes().toSet().intersect( mimeTypes ).isEmpty(); 00976 const bool canCreateNewItems = (collection.rights() & Collection::CanCreateItem); 00977 00978 const bool canCreateNewCollections = (collection.rights() & Collection::CanCreateCollection); 00979 const bool canContainCollections = collection.contentMimeTypes().contains( Collection::mimeType() ); 00980 const bool resourceAllowsRequiredMimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet().contains( mimeTypes ); 00981 00982 const bool isReadOnlyForItems = (isItemAction && (!canCreateNewItems || !canContainRequiredMimeTypes)); 00983 const bool isReadOnlyForCollections = (isCollectionAction && (!canCreateNewCollections || !canContainCollections || !resourceAllowsRequiredMimeTypes)); 00984 00985 return !(CollectionUtils::isStructural( collection ) || isReadOnlyForItems || isReadOnlyForCollections); 00986 } 00987 00988 void fillFoldersMenu( StandardActionManager::Type type, QMenu *menu, 00989 const QAbstractItemModel *model, QModelIndex parentIndex ) 00990 { 00991 const int rowCount = model->rowCount( parentIndex ); 00992 00993 const QSet<QString> mimeTypes = mimeTypesOfSelection( type ); 00994 00995 for ( int row = 0; row < rowCount; ++row ) { 00996 const QModelIndex index = model->index( row, 0, parentIndex ); 00997 const Collection collection = model->data( index, CollectionModel::CollectionRole ).value<Collection>(); 00998 00999 if ( CollectionUtils::isVirtual( collection ) ) 01000 continue; 01001 01002 const bool readOnly = !isWritableTargetCollectionForMimeTypes( collection, mimeTypes, type ); 01003 01004 QString label = model->data( index ).toString(); 01005 label.replace( QLatin1String( "&" ), QLatin1String( "&&" ) ); 01006 01007 const QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>(); 01008 01009 if ( model->rowCount( index ) > 0 ) { 01010 // new level 01011 QMenu* popup = new QMenu( menu ); 01012 const bool moveAction = (type == MoveCollectionToMenu || type == MoveItemToMenu); 01013 popup->setObjectName( QString::fromUtf8( "subMenu" ) ); 01014 popup->setTitle( label ); 01015 popup->setIcon( icon ); 01016 01017 fillFoldersMenu( type, popup, model, index ); 01018 01019 if ( !readOnly ) { 01020 popup->addSeparator(); 01021 01022 QAction *action = popup->addAction( moveAction ? i18n( "Move to This Folder" ) : i18n( "Copy to This Folder" ) ); 01023 action->setData( QVariant::fromValue<QModelIndex>( index ) ); 01024 } 01025 01026 menu->addMenu( popup ); 01027 01028 } else { 01029 // insert an item 01030 QAction* action = menu->addAction( icon, label ); 01031 action->setData( QVariant::fromValue<QModelIndex>( index ) ); 01032 action->setEnabled( !readOnly ); 01033 } 01034 } 01035 } 01036 01037 void checkModelsConsistency() 01038 { 01039 if ( favoritesModel == 0 || favoriteSelectionModel == 0 ) { 01040 // No need to check when the favorite collections feature is not used 01041 return; 01042 } 01043 01044 // find the base ETM of the favourites view 01045 const QAbstractItemModel *favModel = favoritesModel; 01046 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( favModel ) ) { 01047 favModel = proxy->sourceModel(); 01048 } 01049 01050 // Check that the collection selection model maps to the same 01051 // EntityTreeModel than favoritesModel 01052 if ( collectionSelectionModel != 0 ) { 01053 const QAbstractItemModel *model = collectionSelectionModel->model(); 01054 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) { 01055 model = proxy->sourceModel(); 01056 } 01057 01058 Q_ASSERT( model == favModel ); 01059 } 01060 01061 // Check that the favorite selection model maps to favoritesModel 01062 const QAbstractItemModel *model = favoriteSelectionModel->model(); 01063 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) { 01064 model = proxy->sourceModel(); 01065 } 01066 Q_ASSERT( model == favModel ); 01067 } 01068 01069 void markCutAction( QMimeData *mimeData, bool cut ) const 01070 { 01071 if ( !cut ) 01072 return; 01073 01074 const QByteArray cutSelectionData = "1"; //krazy:exclude=doublequote_chars 01075 mimeData->setData( QLatin1String( "application/x-kde.akonadi-cutselection" ), cutSelectionData); 01076 } 01077 01078 bool isCutAction( const QMimeData *mimeData ) const 01079 { 01080 const QByteArray data = mimeData->data( QLatin1String( "application/x-kde.akonadi-cutselection" ) ); 01081 if ( data.isEmpty() ) 01082 return false; 01083 else 01084 return (data.at( 0 ) == '1'); // true if 1 01085 } 01086 01087 void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &data ) 01088 { 01089 ContextTextEntry entry; 01090 entry.text = data; 01091 01092 contextTexts[ type ].insert( context, entry ); 01093 } 01094 01095 void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const KLocalizedString &data ) 01096 { 01097 ContextTextEntry entry; 01098 entry.localizedText = data; 01099 01100 contextTexts[ type ].insert( context, entry ); 01101 } 01102 01103 QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context ) const 01104 { 01105 return contextTexts[ type ].value( context ).text; 01106 } 01107 01108 QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context, int count, const QString &value ) const 01109 { 01110 if ( contextTexts[ type ].value( context ).localizedText.isEmpty() ) 01111 return contextTexts[ type ].value( context ).text; 01112 01113 KLocalizedString text = contextTexts[ type ].value( context ).localizedText; 01114 const QString str = text.subs( count ).toString(); 01115 const int argCount = str.count( QRegExp( QLatin1String( "%[0-9]" ) ) ); 01116 if ( argCount > 0 ) { 01117 return text.subs( count ).subs( value ).toString(); 01118 } else { 01119 return text.subs( count ).toString(); 01120 } 01121 } 01122 01123 StandardActionManager *q; 01124 KActionCollection *actionCollection; 01125 QWidget *parentWidget; 01126 QItemSelectionModel *collectionSelectionModel; 01127 QItemSelectionModel *itemSelectionModel; 01128 FavoriteCollectionsModel *favoritesModel; 01129 QItemSelectionModel *favoriteSelectionModel; 01130 QVector<KAction*> actions; 01131 QHash<StandardActionManager::Type, KLocalizedString> pluralLabels; 01132 QHash<StandardActionManager::Type, KLocalizedString> pluralIconLabels; 01133 01134 struct ContextTextEntry 01135 { 01136 QString text; 01137 KLocalizedString localizedText; 01138 bool isLocalized; 01139 }; 01140 01141 typedef QHash<StandardActionManager::TextContext, ContextTextEntry> ContextTexts; 01142 QHash<StandardActionManager::Type, ContextTexts> contextTexts; 01143 01144 ActionStateManager mActionStateManager; 01145 01146 QStringList mMimeTypeFilter; 01147 QStringList mCapabilityFilter; 01148 QStringList mCollectionPropertiesPageNames; 01149 }; 01150 01151 //@endcond 01152 01153 StandardActionManager::StandardActionManager( KActionCollection * actionCollection, 01154 QWidget * parent) : 01155 QObject( parent ), 01156 d( new Private( this ) ) 01157 { 01158 d->parentWidget = parent; 01159 d->actionCollection = actionCollection; 01160 d->mActionStateManager.setReceiver( this ); 01161 #ifndef QT_NO_CLIPBOARD 01162 connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ), SLOT( clipboardChanged( QClipboard::Mode ) ) ); 01163 #endif 01164 } 01165 01166 StandardActionManager::~ StandardActionManager() 01167 { 01168 delete d; 01169 } 01170 01171 void StandardActionManager::setCollectionSelectionModel( QItemSelectionModel * selectionModel ) 01172 { 01173 d->collectionSelectionModel = selectionModel; 01174 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), 01175 SLOT( collectionSelectionChanged() ) ); 01176 01177 d->checkModelsConsistency(); 01178 } 01179 01180 void StandardActionManager::setItemSelectionModel( QItemSelectionModel * selectionModel ) 01181 { 01182 d->itemSelectionModel = selectionModel; 01183 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), 01184 SLOT( updateActions() ) ); 01185 } 01186 01187 void StandardActionManager::setFavoriteCollectionsModel( FavoriteCollectionsModel *favoritesModel ) 01188 { 01189 d->favoritesModel = favoritesModel; 01190 d->checkModelsConsistency(); 01191 } 01192 01193 void StandardActionManager::setFavoriteSelectionModel( QItemSelectionModel *selectionModel ) 01194 { 01195 d->favoriteSelectionModel = selectionModel; 01196 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), 01197 SLOT( favoriteSelectionChanged() ) ); 01198 d->checkModelsConsistency(); 01199 } 01200 01201 KAction* StandardActionManager::createAction( Type type ) 01202 { 01203 Q_ASSERT( type < LastType ); 01204 Q_ASSERT( standardActionData[type].name ); 01205 if ( d->actions[type] ) 01206 return d->actions[type]; 01207 KAction *action = 0; 01208 switch ( standardActionData[type].actionType ) { 01209 case NormalAction: 01210 action = new KAction( d->parentWidget ); 01211 break; 01212 case MenuAction: 01213 action = new KActionMenu( d->parentWidget ); 01214 break; 01215 case ToggleAction: 01216 action = new KToggleAction( d->parentWidget ); 01217 break; 01218 } 01219 01220 if ( d->pluralLabels.contains( type ) && !d->pluralLabels.value( type ).isEmpty() ) 01221 action->setText( d->pluralLabels.value( type ).subs( 1 ).toString() ); 01222 else if ( standardActionData[type].label ) 01223 action->setText( i18n( standardActionData[type].label ) ); 01224 01225 if ( d->pluralIconLabels.contains( type ) && !d->pluralIconLabels.value( type ).isEmpty() ) 01226 action->setIconText( d->pluralIconLabels.value( type ).subs( 1 ).toString() ); 01227 else if ( standardActionData[type].iconLabel ) 01228 action->setIconText( i18n( standardActionData[type].iconLabel ) ); 01229 01230 if ( standardActionData[type].icon ) 01231 action->setIcon( KIcon( QString::fromLatin1( standardActionData[type].icon ) ) ); 01232 01233 action->setShortcut( standardActionData[type].shortcut ); 01234 01235 if ( standardActionData[type].slot ) { 01236 switch ( standardActionData[type].actionType ) { 01237 case NormalAction: 01238 connect( action, SIGNAL( triggered() ), standardActionData[type].slot ); 01239 break; 01240 case MenuAction: 01241 { 01242 KActionMenu *actionMenu = qobject_cast<KActionMenu*>( action ); 01243 connect( actionMenu->menu(), SIGNAL( triggered( QAction* ) ), standardActionData[type].slot ); 01244 } 01245 break; 01246 case ToggleAction: 01247 { 01248 connect( action, SIGNAL( triggered( bool ) ), standardActionData[type].slot ); 01249 } 01250 break; 01251 } 01252 } 01253 01254 if ( type == ToggleWorkOffline ) { 01255 // inititalize the action state with information from config file 01256 disconnect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot ); 01257 action->setChecked( workOffline() ); 01258 connect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot ); 01259 01260 //TODO: find a way to check for updates to the config file 01261 } 01262 01263 d->actionCollection->addAction( QString::fromLatin1(standardActionData[type].name), action ); 01264 d->actions[type] = action; 01265 d->updateActions(); 01266 return action; 01267 } 01268 01269 void StandardActionManager::createAllActions() 01270 { 01271 for ( uint i = 0; i < LastType; ++i ) 01272 createAction( (Type)i ); 01273 } 01274 01275 KAction * StandardActionManager::action( Type type ) const 01276 { 01277 Q_ASSERT( type < LastType ); 01278 return d->actions[type]; 01279 } 01280 01281 void StandardActionManager::setActionText( Type type, const KLocalizedString & text ) 01282 { 01283 Q_ASSERT( type < LastType ); 01284 d->pluralLabels.insert( type, text ); 01285 d->updateActions(); 01286 } 01287 01288 void StandardActionManager::interceptAction( Type type, bool intercept ) 01289 { 01290 Q_ASSERT( type < LastType ); 01291 01292 const KAction *action = d->actions[type]; 01293 01294 if ( !action ) 01295 return; 01296 01297 if ( intercept ) 01298 disconnect( action, SIGNAL( triggered() ), this, standardActionData[type].slot ); 01299 else 01300 connect( action, SIGNAL( triggered() ), standardActionData[type].slot ); 01301 } 01302 01303 Akonadi::Collection::List StandardActionManager::selectedCollections() const 01304 { 01305 Collection::List collections; 01306 01307 if ( !d->collectionSelectionModel ) 01308 return collections; 01309 01310 foreach ( const QModelIndex &index, d->collectionSelectionModel->selectedRows() ) { 01311 const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>(); 01312 if ( collection.isValid() ) 01313 collections << collection; 01314 } 01315 01316 return collections; 01317 } 01318 01319 Item::List StandardActionManager::selectedItems() const 01320 { 01321 Item::List items; 01322 01323 if ( !d->itemSelectionModel ) 01324 return items; 01325 01326 foreach ( const QModelIndex &index, d->itemSelectionModel->selectedRows() ) { 01327 const Item item = index.data( EntityTreeModel::ItemRole ).value<Item>(); 01328 if ( item.isValid() ) 01329 items << item; 01330 } 01331 01332 return items; 01333 } 01334 01335 void StandardActionManager::setContextText( Type type, TextContext context, const QString &text ) 01336 { 01337 d->setContextText( type, context, text ); 01338 } 01339 01340 void StandardActionManager::setContextText( Type type, TextContext context, const KLocalizedString &text ) 01341 { 01342 d->setContextText( type, context, text ); 01343 } 01344 01345 void StandardActionManager::setMimeTypeFilter( const QStringList &mimeTypes ) 01346 { 01347 d->mMimeTypeFilter = mimeTypes; 01348 } 01349 01350 void StandardActionManager::setCapabilityFilter( const QStringList &capabilities ) 01351 { 01352 d->mCapabilityFilter = capabilities; 01353 } 01354 01355 void StandardActionManager::setCollectionPropertiesPageNames( const QStringList &names ) 01356 { 01357 d->mCollectionPropertiesPageNames = names; 01358 } 01359 01360 #include "standardactionmanager.moc"