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 delete menu; 00272 menu = new KMenu(); 00273 00274 menu->setProperty( "actionType", static_cast<int>( type ) ); 00275 q->connect( menu, SIGNAL( aboutToShow() ), SLOT( aboutToShowMenu() ) ); 00276 q->connect( menu, SIGNAL( triggered( QAction* ) ), standardActionData[ type ].slot ); 00277 actionMenu->setMenu( menu ); 00278 } 00279 } 00280 00281 void aboutToShowMenu() 00282 { 00283 QMenu *menu = qobject_cast<QMenu*>( q->sender() ); 00284 if ( !menu ) 00285 return; 00286 00287 if ( !menu->isEmpty() ) 00288 return; 00289 00290 const StandardActionManager::Type type = static_cast<StandardActionManager::Type>( menu->property( "actionType" ).toInt() ); 00291 00292 fillFoldersMenu( type, 00293 menu, 00294 collectionSelectionModel->model(), 00295 QModelIndex() ); 00296 } 00297 00298 void updatePluralLabel( int type, int count ) 00299 { 00300 updatePluralLabel( static_cast<StandardActionManager::Type>( type ), count ); 00301 } 00302 00303 void updatePluralLabel( StandardActionManager::Type type, int count ) 00304 { 00305 Q_ASSERT( type < StandardActionManager::LastType ); 00306 if ( actions[type] && pluralLabels.contains( type ) && !pluralLabels.value( type ).isEmpty() ) { 00307 actions[type]->setText( pluralLabels.value( type ).subs( qMax( count, 1 ) ).toString() ); 00308 } 00309 } 00310 00311 bool isFavoriteCollection( const Akonadi::Collection &collection ) 00312 { 00313 if ( !favoritesModel ) 00314 return false; 00315 00316 return favoritesModel->collections().contains( collection ); 00317 } 00318 00319 void encodeToClipboard( QItemSelectionModel* selectionModel, bool cut = false ) 00320 { 00321 Q_ASSERT( selectionModel ); 00322 if ( selectionModel->selectedRows().count() <= 0 ) 00323 return; 00324 00325 #ifndef QT_NO_CLIPBOARD 00326 QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() ); 00327 markCutAction( mimeData, cut ); 00328 QApplication::clipboard()->setMimeData( mimeData ); 00329 00330 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( selectionModel->model() ); 00331 00332 foreach ( const QModelIndex &index, selectionModel->selectedRows() ) 00333 model->setData( index, true, EntityTreeModel::PendingCutRole ); 00334 #endif 00335 } 00336 00337 void updateActions() 00338 { 00339 // collect all selected collections 00340 Collection::List selectedCollections; 00341 if ( collectionSelectionModel ) { 00342 const QModelIndexList rows = collectionSelectionModel->selectedRows(); 00343 foreach ( const QModelIndex &index, rows ) { 00344 Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>(); 00345 if ( !collection.isValid() ) 00346 continue; 00347 00348 const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>(); 00349 collection.setParentCollection( parentCollection ); 00350 00351 selectedCollections << collection; 00352 } 00353 } 00354 00355 // collect all selected items 00356 Item::List selectedItems; 00357 if ( itemSelectionModel ) { 00358 const QModelIndexList rows = itemSelectionModel->selectedRows(); 00359 foreach ( const QModelIndex &index, rows ) { 00360 Item item = index.data( EntityTreeModel::ItemRole ).value<Item>(); 00361 if ( !item.isValid() ) 00362 continue; 00363 00364 const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>(); 00365 item.setParentCollection( parentCollection ); 00366 00367 selectedItems << item; 00368 } 00369 } 00370 00371 mActionStateManager.updateState( selectedCollections, selectedItems ); 00372 00373 emit q->actionStateUpdated(); 00374 } 00375 00376 #ifndef QT_NO_CLIPBOARD 00377 void clipboardChanged( QClipboard::Mode mode ) 00378 { 00379 if ( mode == QClipboard::Clipboard ) 00380 updateActions(); 00381 } 00382 #endif 00383 00384 QItemSelection mapToEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const 00385 { 00386 const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ); 00387 if ( proxy ) { 00388 return mapToEntityTreeModel( proxy->sourceModel(), proxy->mapSelectionToSource( selection ) ); 00389 } else { 00390 return selection; 00391 } 00392 } 00393 00394 QItemSelection mapFromEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const 00395 { 00396 const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ); 00397 if ( proxy ) { 00398 const QItemSelection select = mapFromEntityTreeModel( proxy->sourceModel(), selection ); 00399 return proxy->mapSelectionFromSource( select ); 00400 } else { 00401 return selection; 00402 } 00403 } 00404 00405 void collectionSelectionChanged() 00406 { 00407 q->blockSignals( true ); 00408 00409 QItemSelection selection = collectionSelectionModel->selection(); 00410 selection = mapToEntityTreeModel( collectionSelectionModel->model(), selection ); 00411 selection = mapFromEntityTreeModel( favoritesModel, selection ); 00412 00413 if ( favoriteSelectionModel ) 00414 favoriteSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect ); 00415 00416 q->blockSignals( false ); 00417 00418 updateActions(); 00419 } 00420 00421 void favoriteSelectionChanged() 00422 { 00423 q->blockSignals( true ); 00424 00425 QItemSelection selection = favoriteSelectionModel->selection(); 00426 if ( selection.indexes().isEmpty() ) 00427 return; 00428 00429 selection = mapToEntityTreeModel( favoritesModel, selection ); 00430 selection = mapFromEntityTreeModel( collectionSelectionModel->model(), selection ); 00431 00432 collectionSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); 00433 q->blockSignals( false ); 00434 00435 updateActions(); 00436 } 00437 00438 void slotCreateCollection() 00439 { 00440 Q_ASSERT( collectionSelectionModel ); 00441 if ( collectionSelectionModel->selection().indexes().isEmpty() ) 00442 return; 00443 00444 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 ); 00445 Q_ASSERT( index.isValid() ); 00446 const Collection parentCollection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00447 Q_ASSERT( parentCollection.isValid() ); 00448 00449 if ( !canCreateCollection( parentCollection ) ) 00450 return; 00451 00452 const QString name = KInputDialog::getText( contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogTitle ), 00453 contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogText ), 00454 QString(), 0, parentWidget ); 00455 if ( name.isEmpty() ) 00456 return; 00457 00458 Collection collection; 00459 collection.setName( name ); 00460 collection.setParentCollection( parentCollection ); 00461 if ( actions[StandardActionManager::CreateCollection] ) { 00462 const QStringList mts = actions[StandardActionManager::CreateCollection]->property( "ContentMimeTypes" ).toStringList(); 00463 if ( !mts.isEmpty() ) 00464 collection.setContentMimeTypes( mts ); 00465 } 00466 CollectionCreateJob *job = new CollectionCreateJob( collection ); 00467 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionCreationResult( KJob* ) ) ); 00468 } 00469 00470 void slotCopyCollections() 00471 { 00472 encodeToClipboard( collectionSelectionModel ); 00473 } 00474 00475 void slotCutCollections() 00476 { 00477 encodeToClipboard( collectionSelectionModel, true ); 00478 } 00479 00480 Collection::List selectedCollections() const 00481 { 00482 Collection::List collections; 00483 00484 Q_ASSERT( collectionSelectionModel ); 00485 00486 foreach ( const QModelIndex &index, collectionSelectionModel->selectedRows() ) { 00487 Q_ASSERT( index.isValid() ); 00488 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00489 Q_ASSERT( collection.isValid() ); 00490 00491 collections << collection; 00492 } 00493 00494 return collections; 00495 } 00496 00497 void slotDeleteCollection() 00498 { 00499 const Collection::List collections = selectedCollections(); 00500 if ( collections.isEmpty() ) 00501 return; 00502 00503 const QString collectionName = collections.first().name(); 00504 const QString text = contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText, 00505 collections.count(), collectionName ); 00506 00507 if ( KMessageBox::questionYesNo( parentWidget, text, 00508 contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, collections.count(), collectionName ), 00509 KStandardGuiItem::del(), KStandardGuiItem::cancel(), 00510 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes ) 00511 return; 00512 00513 foreach ( const Collection &collection, collections ) { 00514 CollectionDeleteJob *job = new CollectionDeleteJob( collection, q ); 00515 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionDeletionResult( KJob* ) ) ); 00516 } 00517 } 00518 00519 void slotSynchronizeCollection() 00520 { 00521 Q_ASSERT( collectionSelectionModel ); 00522 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00523 if ( list.isEmpty() ) 00524 return; 00525 00526 const Collection::List collections = selectedCollections(); 00527 if ( collections.isEmpty() ) 00528 return; 00529 00530 foreach( Collection collection, collections ) { 00531 AgentManager::self()->synchronizeCollection( collection, false ); 00532 } 00533 } 00534 00535 void slotSynchronizeCollectionRecursive() 00536 { 00537 Q_ASSERT( collectionSelectionModel ); 00538 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00539 if ( list.isEmpty() ) 00540 return; 00541 00542 const Collection::List collections = selectedCollections(); 00543 if ( collections.isEmpty() ) 00544 return; 00545 00546 foreach( Collection collection, collections ) { 00547 AgentManager::self()->synchronizeCollection( collection, true ); 00548 } 00549 } 00550 00551 void slotCollectionProperties() 00552 { 00553 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00554 if ( list.isEmpty() ) 00555 return; 00556 00557 const QModelIndex index = list.first(); 00558 Q_ASSERT( index.isValid() ); 00559 00560 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00561 Q_ASSERT( collection.isValid() ); 00562 00563 const QString displayName = collection.hasAttribute<EntityDisplayAttribute>() ? collection.attribute<EntityDisplayAttribute>()->displayName() 00564 : collection.name(); 00565 00566 CollectionPropertiesDialog* dlg = new CollectionPropertiesDialog( collection, mCollectionPropertiesPageNames, parentWidget ); 00567 dlg->setCaption( contextText( StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle ).arg( displayName ) ); 00568 dlg->show(); 00569 } 00570 00571 void slotCopyItems() 00572 { 00573 encodeToClipboard( itemSelectionModel ); 00574 } 00575 00576 void slotCutItems() 00577 { 00578 encodeToClipboard( itemSelectionModel, true ); 00579 } 00580 00581 void slotPaste() 00582 { 00583 Q_ASSERT( collectionSelectionModel ); 00584 00585 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00586 if ( list.isEmpty() ) 00587 return; 00588 00589 const QModelIndex index = list.first(); 00590 Q_ASSERT( index.isValid() ); 00591 00592 #ifndef QT_NO_CLIPBOARD 00593 // TODO: Copy or move? We can't seem to cut yet 00594 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( collectionSelectionModel->model() ); 00595 const QMimeData *mimeData = QApplication::clipboard()->mimeData(); 00596 model->dropMimeData( mimeData, isCutAction( mimeData ) ? Qt::MoveAction : Qt::CopyAction, -1, -1, index ); 00597 model->setData( QModelIndex(), false, EntityTreeModel::PendingCutRole ); 00598 QApplication::clipboard()->clear(); 00599 #endif 00600 } 00601 00602 void slotDeleteItems() 00603 { 00604 Q_ASSERT( itemSelectionModel ); 00605 00606 Item::List items; 00607 foreach ( const QModelIndex &index, itemSelectionModel->selectedRows() ) { 00608 bool ok; 00609 const qlonglong id = index.data( ItemModel::IdRole ).toLongLong( &ok ); 00610 Q_ASSERT( ok ); 00611 items << Item( id ); 00612 } 00613 00614 if ( items.isEmpty() ) 00615 return; 00616 00617 QMetaObject::invokeMethod(q, "slotDeleteItemsDeferred", 00618 Qt::QueuedConnection, 00619 Q_ARG(Akonadi::Item::List, items)); 00620 } 00621 00622 void slotDeleteItemsDeferred(const Akonadi::Item::List &items) 00623 { 00624 Q_ASSERT( itemSelectionModel ); 00625 00626 if ( KMessageBox::questionYesNo( parentWidget, 00627 contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, items.count(), QString() ), 00628 contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, items.count(), QString() ), 00629 KStandardGuiItem::del(), KStandardGuiItem::cancel(), 00630 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes ) 00631 return; 00632 00633 ItemDeleteJob *job = new ItemDeleteJob( items, q ); 00634 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( itemDeletionResult( KJob* ) ) ); 00635 } 00636 00637 void slotLocalSubscription() 00638 { 00639 SubscriptionDialog* dlg = new SubscriptionDialog( parentWidget ); 00640 dlg->show(); 00641 } 00642 00643 void slotAddToFavorites() 00644 { 00645 Q_ASSERT( collectionSelectionModel ); 00646 Q_ASSERT( favoritesModel ); 00647 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00648 if ( list.isEmpty() ) 00649 return; 00650 00651 foreach ( const QModelIndex &index, list ) { 00652 Q_ASSERT( index.isValid() ); 00653 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00654 Q_ASSERT( collection.isValid() ); 00655 00656 favoritesModel->addCollection( collection ); 00657 } 00658 00659 updateActions(); 00660 } 00661 00662 void slotRemoveFromFavorites() 00663 { 00664 Q_ASSERT( collectionSelectionModel ); 00665 Q_ASSERT( favoritesModel ); 00666 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00667 if ( list.isEmpty() ) 00668 return; 00669 00670 foreach ( const QModelIndex &index, list ) { 00671 Q_ASSERT( index.isValid() ); 00672 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00673 Q_ASSERT( collection.isValid() ); 00674 00675 favoritesModel->removeCollection( collection ); 00676 } 00677 00678 updateActions(); 00679 } 00680 00681 void slotRenameFavorite() 00682 { 00683 Q_ASSERT( collectionSelectionModel ); 00684 Q_ASSERT( favoritesModel ); 00685 const QModelIndexList list = collectionSelectionModel->selectedRows(); 00686 if ( list.isEmpty() ) 00687 return; 00688 00689 const QModelIndex index = list.first(); 00690 Q_ASSERT( index.isValid() ); 00691 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00692 Q_ASSERT( collection.isValid() ); 00693 00694 bool ok; 00695 const QString label = KInputDialog::getText( contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle ), 00696 contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText ), 00697 favoritesModel->favoriteLabel( collection ), &ok, parentWidget ); 00698 if ( !ok ) 00699 return; 00700 00701 favoritesModel->setFavoriteLabel( collection, label ); 00702 } 00703 00704 void slotCopyCollectionTo() 00705 { 00706 pasteTo( collectionSelectionModel, collectionSelectionModel->model(), CopyCollectionToMenu, Qt::CopyAction ); 00707 } 00708 00709 void slotCopyItemTo() 00710 { 00711 pasteTo( itemSelectionModel, collectionSelectionModel->model(), CopyItemToMenu, Qt::CopyAction ); 00712 } 00713 00714 void slotMoveCollectionTo() 00715 { 00716 pasteTo( collectionSelectionModel, collectionSelectionModel->model(), MoveCollectionToMenu, Qt::MoveAction ); 00717 } 00718 00719 void slotMoveItemTo() 00720 { 00721 pasteTo( itemSelectionModel, collectionSelectionModel->model(), MoveItemToMenu, Qt::MoveAction ); 00722 } 00723 00724 void slotCopyCollectionTo( QAction *action ) 00725 { 00726 pasteTo( collectionSelectionModel, action, Qt::CopyAction ); 00727 } 00728 00729 void slotCopyItemTo( QAction *action ) 00730 { 00731 pasteTo( itemSelectionModel, action, Qt::CopyAction ); 00732 } 00733 00734 void slotMoveCollectionTo( QAction *action ) 00735 { 00736 pasteTo( collectionSelectionModel, action, Qt::MoveAction ); 00737 } 00738 00739 void slotMoveItemTo( QAction *action ) 00740 { 00741 pasteTo( itemSelectionModel, action, Qt::MoveAction ); 00742 } 00743 00744 AgentInstance::List selectedAgentInstances() const 00745 { 00746 AgentInstance::List instances; 00747 00748 Q_ASSERT( collectionSelectionModel ); 00749 if ( collectionSelectionModel->selection().indexes().isEmpty() ) 00750 return instances; 00751 00752 foreach ( const QModelIndex &index, collectionSelectionModel->selection().indexes() ) { 00753 Q_ASSERT( index.isValid() ); 00754 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>(); 00755 Q_ASSERT( collection.isValid() ); 00756 00757 if ( collection.isValid() ) { 00758 const QString identifier = collection.resource(); 00759 instances << AgentManager::self()->instance( identifier ); 00760 } 00761 } 00762 00763 return instances; 00764 } 00765 00766 AgentInstance selectedAgentInstance() const 00767 { 00768 const AgentInstance::List instances = selectedAgentInstances(); 00769 00770 if ( instances.isEmpty() ) 00771 return AgentInstance(); 00772 00773 return instances.first(); 00774 } 00775 00776 void slotCreateResource() 00777 { 00778 Akonadi::AgentTypeDialog dlg( parentWidget ); 00779 dlg.setCaption( contextText( StandardActionManager::CreateResource, StandardActionManager::DialogTitle ) ); 00780 00781 foreach ( const QString &mimeType, mMimeTypeFilter ) 00782 dlg.agentFilterProxyModel()->addMimeTypeFilter( mimeType ); 00783 00784 foreach ( const QString &capability, mCapabilityFilter ) 00785 dlg.agentFilterProxyModel()->addCapabilityFilter( capability ); 00786 00787 if ( dlg.exec() ) { 00788 const AgentType agentType = dlg.agentType(); 00789 00790 if ( agentType.isValid() ) { 00791 AgentInstanceCreateJob *job = new AgentInstanceCreateJob( agentType, q ); 00792 q->connect( job, SIGNAL( result( KJob* ) ), SLOT( resourceCreationResult( KJob* ) ) ); 00793 job->configure( parentWidget ); 00794 job->start(); 00795 } 00796 } 00797 } 00798 00799 void slotDeleteResource() 00800 { 00801 const AgentInstance::List instances = selectedAgentInstances(); 00802 if ( instances.isEmpty() ) 00803 return; 00804 00805 if ( KMessageBox::questionYesNo( parentWidget, 00806 contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, instances.count(), instances.first().name() ), 00807 contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, instances.count(), instances.first().name() ), 00808 KStandardGuiItem::del(), KStandardGuiItem::cancel(), 00809 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes ) 00810 return; 00811 00812 foreach ( const AgentInstance &instance, instances ) 00813 AgentManager::self()->removeInstance( instance ); 00814 } 00815 00816 void slotSynchronizeResource() 00817 { 00818 const AgentInstance::List instances = selectedAgentInstances(); 00819 if ( instances.isEmpty() ) 00820 return; 00821 00822 foreach ( AgentInstance instance, instances ) 00823 instance.synchronize(); 00824 } 00825 00826 void slotResourceProperties() 00827 { 00828 AgentInstance instance = selectedAgentInstance(); 00829 if ( !instance.isValid() ) 00830 return; 00831 00832 instance.configure( parentWidget ); 00833 } 00834 00835 void slotToggleWorkOffline( bool offline ) 00836 { 00837 setWorkOffline( offline ); 00838 00839 AgentInstance::List instances = AgentManager::self()->instances(); 00840 foreach ( AgentInstance instance, instances ) { 00841 instance.setIsOnline( !offline ); 00842 } 00843 } 00844 00845 void pasteTo( QItemSelectionModel *selectionModel, const QAbstractItemModel *model, StandardActionManager::Type type, Qt::DropAction dropAction ) 00846 { 00847 const QSet<QString> mimeTypes = mimeTypesOfSelection( type ); 00848 00849 CollectionDialog dlg( const_cast<QAbstractItemModel*>( model ) ); 00850 dlg.setMimeTypeFilter( mimeTypes.toList() ); 00851 00852 if ( type == CopyItemToMenu || type == MoveItemToMenu ) 00853 dlg.setAccessRightsFilter( Collection::CanCreateItem ); 00854 else if ( type == CopyCollectionToMenu || type == MoveCollectionToMenu ) 00855 dlg.setAccessRightsFilter( Collection::CanCreateCollection ); 00856 00857 if ( dlg.exec() ) { 00858 const QModelIndex index = EntityTreeModel::modelIndexForCollection( collectionSelectionModel->model(), dlg.selectedCollection() ); 00859 if ( !index.isValid() ) 00860 return; 00861 00862 const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() ); 00863 00864 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() ); 00865 model->dropMimeData( mimeData, dropAction, -1, -1, index ); 00866 } 00867 } 00868 00869 void pasteTo( QItemSelectionModel *selectionModel, QAction *action, Qt::DropAction dropAction ) 00870 { 00871 Q_ASSERT( selectionModel ); 00872 Q_ASSERT( action ); 00873 00874 if ( selectionModel->selectedRows().count() <= 0 ) 00875 return; 00876 00877 const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() ); 00878 00879 const QModelIndex index = action->data().value<QModelIndex>(); 00880 00881 Q_ASSERT( index.isValid() ); 00882 00883 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() ); 00884 model->dropMimeData( mimeData, dropAction, -1, -1, index ); 00885 } 00886 00887 void collectionCreationResult( KJob *job ) 00888 { 00889 if ( job->error() ) { 00890 KMessageBox::error( parentWidget, 00891 contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00892 contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle ) ); 00893 } 00894 } 00895 00896 void collectionDeletionResult( KJob *job ) 00897 { 00898 if ( job->error() ) { 00899 KMessageBox::error( parentWidget, 00900 contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00901 contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle ) ); 00902 } 00903 } 00904 00905 void itemDeletionResult( KJob *job ) 00906 { 00907 if ( job->error() ) { 00908 KMessageBox::error( parentWidget, 00909 contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00910 contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle ) ); 00911 } 00912 } 00913 00914 void resourceCreationResult( KJob *job ) 00915 { 00916 if ( job->error() ) { 00917 KMessageBox::error( parentWidget, 00918 contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00919 contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle ) ); 00920 } 00921 } 00922 00923 void pasteResult( KJob *job ) 00924 { 00925 if ( job->error() ) { 00926 KMessageBox::error( parentWidget, 00927 contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageText ).arg( job->errorString() ), 00928 contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle ) ); 00929 } 00930 } 00931 00935 QSet<QString> mimeTypesOfSelection( StandardActionManager::Type type ) const 00936 { 00937 QModelIndexList list; 00938 QSet<QString> mimeTypes; 00939 00940 const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu ); 00941 const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu ); 00942 00943 if ( isItemAction ) { 00944 list = itemSelectionModel->selectedRows(); 00945 foreach ( const QModelIndex &index, list ) 00946 mimeTypes << index.data( EntityTreeModel::MimeTypeRole ).toString(); 00947 } 00948 00949 if ( isCollectionAction ) { 00950 list = collectionSelectionModel->selectedRows(); 00951 foreach ( const QModelIndex &index, list ) { 00952 const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>(); 00953 00954 // The mimetypes that the selected collection can possibly contain 00955 mimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet(); 00956 } 00957 } 00958 00959 return mimeTypes; 00960 } 00961 00965 bool isWritableTargetCollectionForMimeTypes( const Collection &collection, const QSet<QString> &mimeTypes, StandardActionManager::Type type ) const 00966 { 00967 if ( CollectionUtils::isVirtual( collection ) ) 00968 return false; 00969 00970 const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu ); 00971 const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu ); 00972 00973 const bool canContainRequiredMimeTypes = !collection.contentMimeTypes().toSet().intersect( mimeTypes ).isEmpty(); 00974 const bool canCreateNewItems = (collection.rights() & Collection::CanCreateItem); 00975 00976 const bool canCreateNewCollections = (collection.rights() & Collection::CanCreateCollection); 00977 const bool canContainCollections = collection.contentMimeTypes().contains( Collection::mimeType() ); 00978 const bool resourceAllowsRequiredMimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet().contains( mimeTypes ); 00979 00980 const bool isReadOnlyForItems = (isItemAction && (!canCreateNewItems || !canContainRequiredMimeTypes)); 00981 const bool isReadOnlyForCollections = (isCollectionAction && (!canCreateNewCollections || !canContainCollections || !resourceAllowsRequiredMimeTypes)); 00982 00983 return !(CollectionUtils::isStructural( collection ) || isReadOnlyForItems || isReadOnlyForCollections); 00984 } 00985 00986 void fillFoldersMenu( StandardActionManager::Type type, QMenu *menu, 00987 const QAbstractItemModel *model, QModelIndex parentIndex ) 00988 { 00989 const int rowCount = model->rowCount( parentIndex ); 00990 00991 const QSet<QString> mimeTypes = mimeTypesOfSelection( type ); 00992 00993 for ( int row = 0; row < rowCount; ++row ) { 00994 const QModelIndex index = model->index( row, 0, parentIndex ); 00995 const Collection collection = model->data( index, CollectionModel::CollectionRole ).value<Collection>(); 00996 00997 if ( CollectionUtils::isVirtual( collection ) ) 00998 continue; 00999 01000 const bool readOnly = !isWritableTargetCollectionForMimeTypes( collection, mimeTypes, type ); 01001 01002 QString label = model->data( index ).toString(); 01003 label.replace( QLatin1String( "&" ), QLatin1String( "&&" ) ); 01004 01005 const QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>(); 01006 01007 if ( model->rowCount( index ) > 0 ) { 01008 // new level 01009 QMenu* popup = new QMenu( menu ); 01010 const bool moveAction = (type == MoveCollectionToMenu || type == MoveItemToMenu); 01011 popup->setObjectName( QString::fromUtf8( "subMenu" ) ); 01012 popup->setTitle( label ); 01013 popup->setIcon( icon ); 01014 01015 fillFoldersMenu( type, popup, model, index ); 01016 01017 if ( !readOnly ) { 01018 popup->addSeparator(); 01019 01020 QAction *action = popup->addAction( moveAction ? i18n( "Move to This Folder" ) : i18n( "Copy to This Folder" ) ); 01021 action->setData( QVariant::fromValue<QModelIndex>( index ) ); 01022 } 01023 01024 menu->addMenu( popup ); 01025 01026 } else { 01027 // insert an item 01028 QAction* action = menu->addAction( icon, label ); 01029 action->setData( QVariant::fromValue<QModelIndex>( index ) ); 01030 action->setEnabled( !readOnly ); 01031 } 01032 } 01033 } 01034 01035 void checkModelsConsistency() 01036 { 01037 if ( favoritesModel == 0 || favoriteSelectionModel == 0 ) { 01038 // No need to check when the favorite collections feature is not used 01039 return; 01040 } 01041 01042 // find the base ETM of the favourites view 01043 const QAbstractItemModel *favModel = favoritesModel; 01044 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( favModel ) ) { 01045 favModel = proxy->sourceModel(); 01046 } 01047 01048 // Check that the collection selection model maps to the same 01049 // EntityTreeModel than favoritesModel 01050 if ( collectionSelectionModel != 0 ) { 01051 const QAbstractItemModel *model = collectionSelectionModel->model(); 01052 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) { 01053 model = proxy->sourceModel(); 01054 } 01055 01056 Q_ASSERT( model == favModel ); 01057 } 01058 01059 // Check that the favorite selection model maps to favoritesModel 01060 const QAbstractItemModel *model = favoriteSelectionModel->model(); 01061 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) { 01062 model = proxy->sourceModel(); 01063 } 01064 Q_ASSERT( model == favModel ); 01065 } 01066 01067 void markCutAction( QMimeData *mimeData, bool cut ) const 01068 { 01069 if ( !cut ) 01070 return; 01071 01072 const QByteArray cutSelectionData = "1"; //krazy:exclude=doublequote_chars 01073 mimeData->setData( QLatin1String( "application/x-kde.akonadi-cutselection" ), cutSelectionData); 01074 } 01075 01076 bool isCutAction( const QMimeData *mimeData ) const 01077 { 01078 const QByteArray data = mimeData->data( QLatin1String( "application/x-kde.akonadi-cutselection" ) ); 01079 if ( data.isEmpty() ) 01080 return false; 01081 else 01082 return (data.at( 0 ) == '1'); // true if 1 01083 } 01084 01085 void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &data ) 01086 { 01087 ContextTextEntry entry; 01088 entry.text = data; 01089 01090 contextTexts[ type ].insert( context, entry ); 01091 } 01092 01093 void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const KLocalizedString &data ) 01094 { 01095 ContextTextEntry entry; 01096 entry.localizedText = data; 01097 01098 contextTexts[ type ].insert( context, entry ); 01099 } 01100 01101 QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context ) const 01102 { 01103 return contextTexts[ type ].value( context ).text; 01104 } 01105 01106 QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context, int count, const QString &value ) const 01107 { 01108 if ( contextTexts[ type ].value( context ).localizedText.isEmpty() ) 01109 return contextTexts[ type ].value( context ).text; 01110 01111 KLocalizedString text = contextTexts[ type ].value( context ).localizedText; 01112 const QString str = text.subs( count ).toString(); 01113 const int argCount = str.count( QRegExp( QLatin1String( "%[0-9]" ) ) ); 01114 if ( argCount > 0 ) { 01115 return text.subs( count ).subs( value ).toString(); 01116 } else { 01117 return text.subs( count ).toString(); 01118 } 01119 } 01120 01121 StandardActionManager *q; 01122 KActionCollection *actionCollection; 01123 QWidget *parentWidget; 01124 QItemSelectionModel *collectionSelectionModel; 01125 QItemSelectionModel *itemSelectionModel; 01126 FavoriteCollectionsModel *favoritesModel; 01127 QItemSelectionModel *favoriteSelectionModel; 01128 QVector<KAction*> actions; 01129 QHash<StandardActionManager::Type, KLocalizedString> pluralLabels; 01130 QHash<StandardActionManager::Type, KLocalizedString> pluralIconLabels; 01131 01132 struct ContextTextEntry 01133 { 01134 QString text; 01135 KLocalizedString localizedText; 01136 bool isLocalized; 01137 }; 01138 01139 typedef QHash<StandardActionManager::TextContext, ContextTextEntry> ContextTexts; 01140 QHash<StandardActionManager::Type, ContextTexts> contextTexts; 01141 01142 ActionStateManager mActionStateManager; 01143 01144 QStringList mMimeTypeFilter; 01145 QStringList mCapabilityFilter; 01146 QStringList mCollectionPropertiesPageNames; 01147 }; 01148 01149 //@endcond 01150 01151 StandardActionManager::StandardActionManager( KActionCollection * actionCollection, 01152 QWidget * parent) : 01153 QObject( parent ), 01154 d( new Private( this ) ) 01155 { 01156 d->parentWidget = parent; 01157 d->actionCollection = actionCollection; 01158 d->mActionStateManager.setReceiver( this ); 01159 #ifndef QT_NO_CLIPBOARD 01160 connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ), SLOT( clipboardChanged( QClipboard::Mode ) ) ); 01161 #endif 01162 } 01163 01164 StandardActionManager::~ StandardActionManager() 01165 { 01166 delete d; 01167 } 01168 01169 void StandardActionManager::setCollectionSelectionModel( QItemSelectionModel * selectionModel ) 01170 { 01171 d->collectionSelectionModel = selectionModel; 01172 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), 01173 SLOT( collectionSelectionChanged() ) ); 01174 01175 d->checkModelsConsistency(); 01176 } 01177 01178 void StandardActionManager::setItemSelectionModel( QItemSelectionModel * selectionModel ) 01179 { 01180 d->itemSelectionModel = selectionModel; 01181 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), 01182 SLOT( updateActions() ) ); 01183 } 01184 01185 void StandardActionManager::setFavoriteCollectionsModel( FavoriteCollectionsModel *favoritesModel ) 01186 { 01187 d->favoritesModel = favoritesModel; 01188 d->checkModelsConsistency(); 01189 } 01190 01191 void StandardActionManager::setFavoriteSelectionModel( QItemSelectionModel *selectionModel ) 01192 { 01193 d->favoriteSelectionModel = selectionModel; 01194 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ), 01195 SLOT( favoriteSelectionChanged() ) ); 01196 d->checkModelsConsistency(); 01197 } 01198 01199 KAction* StandardActionManager::createAction( Type type ) 01200 { 01201 Q_ASSERT( type < LastType ); 01202 Q_ASSERT( standardActionData[type].name ); 01203 if ( d->actions[type] ) 01204 return d->actions[type]; 01205 KAction *action = 0; 01206 switch ( standardActionData[type].actionType ) { 01207 case NormalAction: 01208 action = new KAction( d->parentWidget ); 01209 break; 01210 case MenuAction: 01211 action = new KActionMenu( d->parentWidget ); 01212 break; 01213 case ToggleAction: 01214 action = new KToggleAction( d->parentWidget ); 01215 break; 01216 } 01217 01218 if ( d->pluralLabels.contains( type ) && !d->pluralLabels.value( type ).isEmpty() ) 01219 action->setText( d->pluralLabels.value( type ).subs( 1 ).toString() ); 01220 else if ( standardActionData[type].label ) 01221 action->setText( i18n( standardActionData[type].label ) ); 01222 01223 if ( d->pluralIconLabels.contains( type ) && !d->pluralIconLabels.value( type ).isEmpty() ) 01224 action->setIconText( d->pluralIconLabels.value( type ).subs( 1 ).toString() ); 01225 else if ( standardActionData[type].iconLabel ) 01226 action->setIconText( i18n( standardActionData[type].iconLabel ) ); 01227 01228 if ( standardActionData[type].icon ) 01229 action->setIcon( KIcon( QString::fromLatin1( standardActionData[type].icon ) ) ); 01230 01231 action->setShortcut( standardActionData[type].shortcut ); 01232 01233 if ( standardActionData[type].slot ) { 01234 switch ( standardActionData[type].actionType ) { 01235 case NormalAction: 01236 connect( action, SIGNAL( triggered() ), standardActionData[type].slot ); 01237 break; 01238 case MenuAction: 01239 { 01240 KActionMenu *actionMenu = qobject_cast<KActionMenu*>( action ); 01241 connect( actionMenu->menu(), SIGNAL( triggered( QAction* ) ), standardActionData[type].slot ); 01242 } 01243 break; 01244 case ToggleAction: 01245 { 01246 connect( action, SIGNAL( triggered( bool ) ), standardActionData[type].slot ); 01247 } 01248 break; 01249 } 01250 } 01251 01252 if ( type == ToggleWorkOffline ) { 01253 // inititalize the action state with information from config file 01254 disconnect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot ); 01255 action->setChecked( workOffline() ); 01256 connect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot ); 01257 01258 //TODO: find a way to check for updates to the config file 01259 } 01260 01261 d->actionCollection->addAction( QString::fromLatin1(standardActionData[type].name), action ); 01262 d->actions[type] = action; 01263 d->updateActions(); 01264 return action; 01265 } 01266 01267 void StandardActionManager::createAllActions() 01268 { 01269 for ( uint i = 0; i < LastType; ++i ) 01270 createAction( (Type)i ); 01271 } 01272 01273 KAction * StandardActionManager::action( Type type ) const 01274 { 01275 Q_ASSERT( type < LastType ); 01276 return d->actions[type]; 01277 } 01278 01279 void StandardActionManager::setActionText( Type type, const KLocalizedString & text ) 01280 { 01281 Q_ASSERT( type < LastType ); 01282 d->pluralLabels.insert( type, text ); 01283 d->updateActions(); 01284 } 01285 01286 void StandardActionManager::interceptAction( Type type, bool intercept ) 01287 { 01288 Q_ASSERT( type < LastType ); 01289 01290 const KAction *action = d->actions[type]; 01291 01292 if ( !action ) 01293 return; 01294 01295 if ( intercept ) 01296 disconnect( action, SIGNAL( triggered() ), this, standardActionData[type].slot ); 01297 else 01298 connect( action, SIGNAL( triggered() ), standardActionData[type].slot ); 01299 } 01300 01301 Akonadi::Collection::List StandardActionManager::selectedCollections() const 01302 { 01303 Collection::List collections; 01304 01305 if ( !d->collectionSelectionModel ) 01306 return collections; 01307 01308 foreach ( const QModelIndex &index, d->collectionSelectionModel->selectedRows() ) { 01309 const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>(); 01310 if ( collection.isValid() ) 01311 collections << collection; 01312 } 01313 01314 return collections; 01315 } 01316 01317 Item::List StandardActionManager::selectedItems() const 01318 { 01319 Item::List items; 01320 01321 if ( !d->itemSelectionModel ) 01322 return items; 01323 01324 foreach ( const QModelIndex &index, d->itemSelectionModel->selectedRows() ) { 01325 const Item item = index.data( EntityTreeModel::ItemRole ).value<Item>(); 01326 if ( item.isValid() ) 01327 items << item; 01328 } 01329 01330 return items; 01331 } 01332 01333 void StandardActionManager::setContextText( Type type, TextContext context, const QString &text ) 01334 { 01335 d->setContextText( type, context, text ); 01336 } 01337 01338 void StandardActionManager::setContextText( Type type, TextContext context, const KLocalizedString &text ) 01339 { 01340 d->setContextText( type, context, text ); 01341 } 01342 01343 void StandardActionManager::setMimeTypeFilter( const QStringList &mimeTypes ) 01344 { 01345 d->mMimeTypeFilter = mimeTypes; 01346 } 01347 01348 void StandardActionManager::setCapabilityFilter( const QStringList &capabilities ) 01349 { 01350 d->mCapabilityFilter = capabilities; 01351 } 01352 01353 void StandardActionManager::setCollectionPropertiesPageNames( const QStringList &names ) 01354 { 01355 d->mCollectionPropertiesPageNames = names; 01356 } 01357 01358 #include "standardactionmanager.moc"