00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
00267 KActionMenu *actionMenu = qobject_cast<KActionMenu*>( actions[type] );
00268 if ( actionMenu ) {
00269
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
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
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
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
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
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
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
01039 return;
01040 }
01041
01042
01043 const QAbstractItemModel *favModel = favoritesModel;
01044 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( favModel ) ) {
01045 favModel = proxy->sourceModel();
01046 }
01047
01048
01049
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
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";
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');
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
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
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
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"