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 "agentmanager.h"
00023 #include "collectioncreatejob.h"
00024 #include "collectiondeletejob.h"
00025 #include "collectionmodel.h"
00026 #include "collectionutils_p.h"
00027 #include "collectionpropertiesdialog.h"
00028 #include "entitytreemodel.h"
00029 #include "favoritecollectionsmodel.h"
00030 #include "itemdeletejob.h"
00031 #include "itemmodel.h"
00032 #include "pastehelper_p.h"
00033 #include "subscriptiondialog_p.h"
00034 #include "specialcollectionattribute_p.h"
00035
00036 #include <KAction>
00037 #include <KActionCollection>
00038 #include <KActionMenu>
00039 #include <KDebug>
00040 #include <KInputDialog>
00041 #include <KLocale>
00042 #include <KMenu>
00043 #include <KMessageBox>
00044
00045 #include <QtCore/QMimeData>
00046 #include <QtGui/QApplication>
00047 #include <QtGui/QClipboard>
00048 #include <QtGui/QItemSelectionModel>
00049
00050 #include <boost/static_assert.hpp>
00051
00052 Q_DECLARE_METATYPE(QModelIndex)
00053
00054 using namespace Akonadi;
00055
00056
00057
00058 static const struct {
00059 const char *name;
00060 const char *label;
00061 const char *icon;
00062 int shortcut;
00063 const char* slot;
00064 bool isActionMenu;
00065 } actionData[] = {
00066 { "akonadi_collection_create", I18N_NOOP( "&New Folder..." ), "folder-new", 0, SLOT( slotCreateCollection() ), false },
00067 { "akonadi_collection_copy", 0, "edit-copy", 0, SLOT( slotCopyCollections() ), false },
00068 { "akonadi_collection_delete", I18N_NOOP( "&Delete Folder" ), "edit-delete", 0, SLOT( slotDeleteCollection() ), false },
00069 { "akonadi_collection_sync", I18N_NOOP( "&Synchronize Folder" ), "view-refresh", Qt::Key_F5, SLOT( slotSynchronizeCollection() ), false },
00070 { "akonadi_collection_properties", I18N_NOOP( "Folder &Properties" ), "configure", 0, SLOT( slotCollectionProperties() ), false },
00071 { "akonadi_item_copy", 0, "edit-copy", 0, SLOT( slotCopyItems() ), false },
00072 { "akonadi_paste", I18N_NOOP( "&Paste" ), "edit-paste", Qt::CTRL + Qt::Key_V, SLOT( slotPaste() ), false },
00073 { "akonadi_item_delete", 0, "edit-delete", Qt::Key_Delete, SLOT( slotDeleteItems() ), false },
00074 { "akonadi_manage_local_subscriptions", I18N_NOOP( "Manage Local &Subscriptions..." ), 0, 0, SLOT( slotLocalSubscription() ), false },
00075 { "akonadi_collection_add_to_favorites", I18N_NOOP( "Add to Favorite Folders" ), "bookmark-new", 0, SLOT( slotAddToFavorites() ), false },
00076 { "akonadi_collection_remove_from_favorites", I18N_NOOP( "Remove from Favorite Folders" ), "edit-delete", 0, SLOT( slotRemoveFromFavorites() ), false },
00077 { "akonadi_collection_rename_favorite", I18N_NOOP( "Rename Favorite..." ), "edit-rename", 0, SLOT( slotRenameFavorite() ), false },
00078 { "akonadi_collection_copy_to_menu", I18N_NOOP( "Copy Folder To..." ), "edit-copy", 0, SLOT( slotCopyCollectionTo( QAction* ) ), true },
00079 { "akonadi_item_copy_to_menu", I18N_NOOP( "Copy Item To..." ), "edit-copy", 0, SLOT( slotCopyItemTo( QAction* ) ), true },
00080 { "akonadi_item_move_to_menu", I18N_NOOP( "Move Item To..." ), "go-jump", 0, SLOT( slotMoveItemTo( QAction* ) ), true },
00081 { "akonadi_collection_move_to_menu", I18N_NOOP( "Move Folder To..." ), "go-jump", 0, SLOT( slotMoveCollectionTo( QAction* ) ), true },
00082 { "akonadi_item_cut", I18N_NOOP( "&Cut Item" ), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT( slotCutItems() ), false },
00083 { "akonadi_collection_cut", I18N_NOOP( "&Cut Folder" ), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT( slotCutCollections() ), false }
00084 };
00085 static const int numActionData = sizeof actionData / sizeof *actionData;
00086
00087 BOOST_STATIC_ASSERT( numActionData == StandardActionManager::LastType );
00088
00089 static bool canCreateCollection( const Collection &collection )
00090 {
00091 if ( !( collection.rights() & Collection::CanCreateCollection ) )
00092 return false;
00093
00094 if ( !collection.contentMimeTypes().contains( Collection::mimeType() ) )
00095 return false;
00096
00097 return true;
00098 }
00099
00100 static inline bool isRootCollection( const Collection &collection )
00101 {
00102 return (collection == Collection::root());
00103 }
00104
00108 class StandardActionManager::Private
00109 {
00110 public:
00111 Private( StandardActionManager *parent ) :
00112 q( parent ),
00113 collectionSelectionModel( 0 ),
00114 itemSelectionModel( 0 ),
00115 favoritesModel( 0 ),
00116 favoriteSelectionModel( 0 )
00117 {
00118 actions.fill( 0, StandardActionManager::LastType );
00119
00120 pluralLabels.insert( StandardActionManager::CopyCollections, ki18np( "&Copy Folder", "&Copy %1 Folders" ) );
00121 pluralLabels.insert( StandardActionManager::CopyItems, ki18np( "&Copy Item", "&Copy %1 Items" ) );
00122 pluralLabels.insert( StandardActionManager::CutItems, ki18np( "&Cut Item", "&Cut %1 Items" ) );
00123 pluralLabels.insert( StandardActionManager::CutCollections, ki18np( "&Cut Folder", "&Cut %1 Folders" ) );
00124 pluralLabels.insert( StandardActionManager::DeleteItems, ki18np( "&Delete Item", "&Delete %1 Items" ) );
00125 }
00126
00127 void enableAction( StandardActionManager::Type type, bool enable )
00128 {
00129 Q_ASSERT( type >= 0 && type < StandardActionManager::LastType );
00130 if ( actions[type] )
00131 actions[type]->setEnabled( enable );
00132
00133
00134 KActionMenu *actionMenu = qobject_cast<KActionMenu*>( actions[type] );
00135 if ( actionMenu ) {
00136 actionMenu->menu()->clear();
00137 if ( enable ) {
00138 fillFoldersMenu( type,
00139 actionMenu->menu(),
00140 collectionSelectionModel->model(),
00141 QModelIndex() );
00142 }
00143 }
00144 }
00145
00146 void updatePluralLabel( StandardActionManager::Type type, int count )
00147 {
00148 Q_ASSERT( type >= 0 && type < StandardActionManager::LastType );
00149 if ( actions[type] && pluralLabels.contains( type ) && !pluralLabels.value( type ).isEmpty() ) {
00150 actions[type]->setText( pluralLabels.value( type ).subs( qMax( count, 1 ) ).toString() );
00151 }
00152 }
00153
00154 void encodeToClipboard( QItemSelectionModel* selectionModel, bool cut = false )
00155 {
00156 Q_ASSERT( selectionModel );
00157 if ( selectionModel->selectedRows().count() <= 0 )
00158 return;
00159
00160 QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00161 markCutAction( mimeData, cut );
00162 QApplication::clipboard()->setMimeData( mimeData );
00163
00164 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( selectionModel->model() );
00165
00166 foreach ( const QModelIndex &index, selectionModel->selectedRows() )
00167 model->setData( index, true, EntityTreeModel::PendingCutRole );
00168 }
00169
00170 void updateActions()
00171 {
00172 bool singleCollectionSelected = false;
00173 bool multipleCollectionsSelected = false;
00174 bool canDeleteCollections = true;
00175 int collectionCount = 0;
00176 QModelIndex selectedIndex;
00177 if ( !collectionSelectionModel ) {
00178 canDeleteCollections = false;
00179 } else {
00180 collectionCount = collectionSelectionModel->selectedRows().count();
00181 singleCollectionSelected = collectionCount == 1;
00182 multipleCollectionsSelected = collectionCount > 1;
00183 canDeleteCollections = collectionCount > 0;
00184
00185 if ( singleCollectionSelected )
00186 selectedIndex = collectionSelectionModel->selectedRows().first();
00187 if ( itemSelectionModel ) {
00188 const QModelIndexList rows = itemSelectionModel->selectedRows();
00189 foreach ( const QModelIndex &itemIndex, rows ) {
00190 const Collection collection = itemIndex.data( EntityTreeModel::CollectionRole ).value<Collection>();
00191 if ( !collection.isValid() )
00192 continue;
00193 if ( collection == collection.root() )
00194
00195 return;
00196 canDeleteCollections = canDeleteCollections && ( collection.rights() & Collection::CanDeleteCollection );
00197 }
00198 }
00199 }
00200 const Collection collection = selectedIndex.data( CollectionModel::CollectionRole ).value<Collection>();
00201
00202 enableAction( CopyCollections, (singleCollectionSelected || multipleCollectionsSelected) && !isRootCollection( collection ) );
00203 enableAction( CollectionProperties, singleCollectionSelected && !isRootCollection( collection ) );
00204
00205 enableAction( CreateCollection, singleCollectionSelected && canCreateCollection( collection ) );
00206 enableAction( DeleteCollections, singleCollectionSelected && (collection.rights() & Collection::CanDeleteCollection) && !CollectionUtils::isResource( collection ) );
00207 enableAction( CutCollections, canDeleteCollections && !isRootCollection( collection ) && !CollectionUtils::isResource( collection ) && CollectionUtils::isFolder( collection ) && !collection.hasAttribute<SpecialCollectionAttribute>() );
00208 enableAction( SynchronizeCollections, singleCollectionSelected && (CollectionUtils::isResource( collection ) || CollectionUtils::isFolder( collection ) ) );
00209 enableAction( Paste, singleCollectionSelected && PasteHelper::canPaste( QApplication::clipboard()->mimeData(), collection ) );
00210 enableAction( AddToFavoriteCollections, singleCollectionSelected && ( favoritesModel != 0 ) && ( !favoritesModel->collections().contains( collection ) ) && !isRootCollection( collection ) && !CollectionUtils::isResource( collection ) && CollectionUtils::isFolder( collection ) );
00211 enableAction( RemoveFromFavoriteCollections, singleCollectionSelected && ( favoritesModel != 0 ) && ( favoritesModel->collections().contains( collection ) ) );
00212 enableAction( RenameFavoriteCollection, singleCollectionSelected && ( favoritesModel != 0 ) && ( favoritesModel->collections().contains( collection ) ) );
00213 enableAction( CopyCollectionToMenu, (singleCollectionSelected || multipleCollectionsSelected) && !isRootCollection( collection ) );
00214 enableAction( MoveCollectionToMenu, canDeleteCollections && !isRootCollection( collection ) && !CollectionUtils::isResource( collection ) && CollectionUtils::isFolder( collection ) && !collection.hasAttribute<SpecialCollectionAttribute>() );
00215
00216 bool multipleItemsSelected = false;
00217 bool canDeleteItems = true;
00218 int itemCount = 0;
00219 if ( !itemSelectionModel ) {
00220 canDeleteItems = false;
00221 } else {
00222 const QModelIndexList rows = itemSelectionModel->selectedRows();
00223
00224 itemCount = rows.count();
00225 multipleItemsSelected = itemCount > 0;
00226 canDeleteItems = itemCount > 0;
00227
00228 foreach ( const QModelIndex &itemIndex, rows ) {
00229 const Collection parentCollection = itemIndex.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00230 if ( !parentCollection.isValid() )
00231 continue;
00232
00233 canDeleteItems = canDeleteItems && (parentCollection.rights() & Collection::CanDeleteItem);
00234 }
00235 }
00236
00237 enableAction( CopyItems, multipleItemsSelected );
00238 enableAction( CutItems, canDeleteItems );
00239
00240 enableAction( DeleteItems, multipleItemsSelected && canDeleteItems );
00241
00242 enableAction( CopyItemToMenu, multipleItemsSelected );
00243 enableAction( MoveItemToMenu, multipleItemsSelected && canDeleteItems );
00244
00245 updatePluralLabel( CopyCollections, collectionCount );
00246 updatePluralLabel( CopyItems, itemCount );
00247 updatePluralLabel( DeleteItems, itemCount );
00248 updatePluralLabel( CutItems, itemCount );
00249 updatePluralLabel( CutCollections, itemCount );
00250
00251 emit q->actionStateUpdated();
00252 }
00253
00254 void clipboardChanged( QClipboard::Mode mode )
00255 {
00256 if ( mode == QClipboard::Clipboard )
00257 updateActions();
00258 }
00259
00260 QItemSelection mapToEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const
00261 {
00262 const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model );
00263 if ( proxy ) {
00264 return mapToEntityTreeModel( proxy->sourceModel(), proxy->mapSelectionToSource( selection ) );
00265 } else {
00266 return selection;
00267 }
00268 }
00269
00270 QItemSelection mapFromEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const
00271 {
00272 const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model );
00273 if ( proxy ) {
00274 const QItemSelection select = mapFromEntityTreeModel( proxy->sourceModel(), selection );
00275 return proxy->mapSelectionFromSource( select );
00276 } else {
00277 return selection;
00278 }
00279 }
00280
00281 void collectionSelectionChanged()
00282 {
00283 q->blockSignals( true );
00284
00285 QItemSelection selection = collectionSelectionModel->selection();
00286 selection = mapToEntityTreeModel( collectionSelectionModel->model(), selection );
00287 selection = mapFromEntityTreeModel( favoritesModel, selection );
00288
00289 if ( favoriteSelectionModel )
00290 favoriteSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect );
00291
00292 q->blockSignals( false );
00293
00294 updateActions();
00295 }
00296
00297 void favoriteSelectionChanged()
00298 {
00299 q->blockSignals( true );
00300
00301 QItemSelection selection = favoriteSelectionModel->selection();
00302 if ( selection.indexes().isEmpty() )
00303 return;
00304
00305 selection = mapToEntityTreeModel( favoritesModel, selection );
00306 selection = mapFromEntityTreeModel( collectionSelectionModel->model(), selection );
00307
00308 collectionSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
00309 q->blockSignals( false );
00310
00311 updateActions();
00312 }
00313
00314 void slotCreateCollection()
00315 {
00316 Q_ASSERT( collectionSelectionModel );
00317 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00318 return;
00319
00320 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00321 Q_ASSERT( index.isValid() );
00322 const Collection parentCollection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00323 Q_ASSERT( parentCollection.isValid() );
00324
00325 if ( !canCreateCollection( parentCollection ) )
00326 return;
00327
00328 const QString name = KInputDialog::getText( i18nc( "@title:window", "New Folder" ),
00329 i18nc( "@label:textbox name of a thing", "Name" ),
00330 QString(), 0, parentWidget );
00331 if ( name.isEmpty() )
00332 return;
00333
00334 Collection collection;
00335 collection.setName( name );
00336 collection.setParentCollection( parentCollection );
00337 CollectionCreateJob *job = new CollectionCreateJob( collection );
00338 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionCreationResult( KJob* ) ) );
00339 }
00340
00341 void slotCopyCollections()
00342 {
00343 encodeToClipboard( collectionSelectionModel );
00344 }
00345
00346 void slotCutCollections()
00347 {
00348 encodeToClipboard( collectionSelectionModel, true );
00349 }
00350
00351 void slotDeleteCollection()
00352 {
00353 Q_ASSERT( collectionSelectionModel );
00354 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00355 return;
00356
00357 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00358 Q_ASSERT( index.isValid() );
00359 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00360 Q_ASSERT( collection.isValid() );
00361
00362 QString text = i18n( "Do you really want to delete folder '%1' and all its sub-folders?", index.data().toString() );
00363 if ( CollectionUtils::isVirtual( collection ) )
00364 text = i18n( "Do you really want to delete the search view '%1'?", index.data().toString() );
00365
00366 if ( KMessageBox::questionYesNo( parentWidget, text,
00367 i18n( "Delete folder?" ), KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00368 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00369 return;
00370
00371 const Collection::Id collectionId = index.data( CollectionModel::CollectionIdRole ).toLongLong();
00372 if ( collectionId <= 0 )
00373 return;
00374
00375 CollectionDeleteJob *job = new CollectionDeleteJob( Collection( collectionId ), q );
00376 q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionDeletionResult( KJob* ) ) );
00377 }
00378
00379 void slotSynchronizeCollection()
00380 {
00381 Q_ASSERT( collectionSelectionModel );
00382 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00383 return;
00384
00385 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00386 Q_ASSERT( index.isValid() );
00387 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00388 Q_ASSERT( collection.isValid() );
00389
00390 AgentManager::self()->synchronizeCollection( collection );
00391 }
00392
00393 void slotCollectionProperties()
00394 {
00395 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00396 return;
00397 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00398 Q_ASSERT( index.isValid() );
00399 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00400 Q_ASSERT( collection.isValid() );
00401
00402 CollectionPropertiesDialog* dlg = new CollectionPropertiesDialog( collection, parentWidget );
00403 dlg->setCaption( i18n( "Properties of Folder %1", collection.name() ) );
00404 dlg->show();
00405 }
00406
00407 void slotCopyItems()
00408 {
00409 encodeToClipboard( itemSelectionModel );
00410 }
00411
00412 void slotCutItems()
00413 {
00414 encodeToClipboard( itemSelectionModel, true );
00415 }
00416
00417 void slotPaste()
00418 {
00419 Q_ASSERT( collectionSelectionModel );
00420 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00421 return;
00422
00423 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00424 Q_ASSERT( index.isValid() );
00425
00426
00427 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( collectionSelectionModel->model() );
00428 const QMimeData *mimeData = QApplication::clipboard()->mimeData();
00429 model->dropMimeData( mimeData, isCutAction( mimeData ) ? Qt::MoveAction : Qt::CopyAction, -1, -1, index );
00430 model->setData( QModelIndex(), false, EntityTreeModel::PendingCutRole );
00431 QApplication::clipboard()->clear();
00432 }
00433
00434 void slotDeleteItems()
00435 {
00436 if ( KMessageBox::questionYesNo( parentWidget,
00437 i18n( "Do you really want to delete all selected items?" ),
00438 i18n( "Delete?" ), KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00439 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00440 return;
00441
00442 Q_ASSERT( itemSelectionModel );
00443
00444
00445 Item::List items;
00446 foreach ( const QModelIndex &index, itemSelectionModel->selectedRows() ) {
00447 bool ok;
00448 const qlonglong id = index.data( ItemModel::IdRole ).toLongLong( &ok );
00449 Q_ASSERT( ok );
00450 items << Item( id );
00451 }
00452
00453 new ItemDeleteJob( items, q );
00454 }
00455
00456 void slotLocalSubscription()
00457 {
00458 SubscriptionDialog* dlg = new SubscriptionDialog( parentWidget );
00459 dlg->show();
00460 }
00461
00462 void slotAddToFavorites()
00463 {
00464 Q_ASSERT( collectionSelectionModel );
00465 Q_ASSERT( favoritesModel );
00466 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00467 return;
00468
00469 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00470 Q_ASSERT( index.isValid() );
00471 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00472 Q_ASSERT( collection.isValid() );
00473
00474 favoritesModel->addCollection( collection );
00475 enableAction( AddToFavoriteCollections, false );
00476 }
00477
00478 void slotRemoveFromFavorites()
00479 {
00480 Q_ASSERT( collectionSelectionModel );
00481 Q_ASSERT( favoritesModel );
00482 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00483 return;
00484
00485 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00486 Q_ASSERT( index.isValid() );
00487 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00488 Q_ASSERT( collection.isValid() );
00489
00490 favoritesModel->removeCollection( collection );
00491 if ( favoritesModel->collections().count() <= 1 )
00492 enableAction( AddToFavoriteCollections, true );
00493 }
00494
00495 void slotRenameFavorite()
00496 {
00497 Q_ASSERT( collectionSelectionModel );
00498 Q_ASSERT( favoritesModel );
00499 if ( collectionSelectionModel->selection().indexes().isEmpty() )
00500 return;
00501
00502 const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00503 Q_ASSERT( index.isValid() );
00504 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00505 Q_ASSERT( collection.isValid() );
00506
00507 bool ok;
00508 const QString label = KInputDialog::getText( i18n( "Rename Favorite" ),
00509 i18nc( "@label:textbox New name of the folder.", "Name:" ),
00510 favoritesModel->favoriteLabel( collection ), &ok, parentWidget );
00511 if ( !ok )
00512 return;
00513
00514 favoritesModel->setFavoriteLabel( collection, label );
00515 }
00516
00517 void slotCopyCollectionTo( QAction *action )
00518 {
00519 pasteTo( collectionSelectionModel, action, Qt::CopyAction );
00520 }
00521
00522 void slotCopyItemTo( QAction *action )
00523 {
00524 pasteTo( itemSelectionModel, action, Qt::CopyAction );
00525 }
00526
00527 void slotMoveCollectionTo( QAction *action )
00528 {
00529 pasteTo( collectionSelectionModel, action, Qt::MoveAction );
00530 }
00531
00532 void slotMoveItemTo( QAction *action )
00533 {
00534 pasteTo( itemSelectionModel, action, Qt::MoveAction );
00535 }
00536
00537 void pasteTo( QItemSelectionModel *selectionModel, QAction *action, Qt::DropAction dropAction )
00538 {
00539 Q_ASSERT( selectionModel );
00540 Q_ASSERT( action );
00541
00542 if ( selectionModel->selectedRows().count() <= 0 )
00543 return;
00544
00545 const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00546
00547 const QModelIndex index = action->data().value<QModelIndex>();
00548
00549 Q_ASSERT( index.isValid() );
00550
00551 QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() );
00552 model->dropMimeData( mimeData, dropAction, -1, -1, index );
00553 }
00554
00555 void collectionCreationResult( KJob *job )
00556 {
00557 if ( job->error() ) {
00558 KMessageBox::error( parentWidget, i18n( "Could not create folder: %1", job->errorString()),
00559 i18n( "Folder creation failed" ) );
00560 }
00561 }
00562
00563 void collectionDeletionResult( KJob *job )
00564 {
00565 if ( job->error() ) {
00566 KMessageBox::error( parentWidget, i18n( "Could not delete folder: %1", job->errorString()),
00567 i18n( "Folder deletion failed" ) );
00568 }
00569 }
00570
00571 void pasteResult( KJob *job )
00572 {
00573 if ( job->error() ) {
00574 KMessageBox::error( parentWidget, i18n( "Could not paste data: %1", job->errorString()),
00575 i18n( "Paste failed" ) );
00576 }
00577 }
00578
00579 void fillFoldersMenu( StandardActionManager::Type type, QMenu *menu,
00580 const QAbstractItemModel *model, QModelIndex parentIndex )
00581 {
00582 const int rowCount = model->rowCount( parentIndex );
00583
00584 QModelIndexList list;
00585 QSet<QString> mimeTypes;
00586
00587 const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu );
00588 const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu );
00589
00590 if ( isItemAction ) {
00591 list = itemSelectionModel->selectedRows();
00592 foreach ( const QModelIndex &index, list )
00593 mimeTypes << index.data( EntityTreeModel::MimeTypeRole ).toString();
00594 }
00595
00596 if ( isCollectionAction ) {
00597 list = collectionSelectionModel->selectedRows();
00598 foreach ( const QModelIndex &index, list ) {
00599 const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00600
00601
00602 mimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet();
00603 }
00604 }
00605
00606 for ( int row = 0; row < rowCount; ++row ) {
00607 const QModelIndex index = model->index( row, 0, parentIndex );
00608 const Collection collection = model->data( index, CollectionModel::CollectionRole ).value<Collection>();
00609
00610 if ( CollectionUtils::isVirtual( collection ) ) {
00611 continue;
00612 }
00613
00614 QString label = model->data( index ).toString();
00615 label.replace( QLatin1String( "&" ), QLatin1String( "&&" ) );
00616
00617 const QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>();
00618
00619 const bool canContainRequiredMimeTypes = !collection.contentMimeTypes().toSet().intersect( mimeTypes ).isEmpty();
00620 const bool canCreateNewItems = (collection.rights() & Collection::CanCreateItem);
00621
00622
00623 const bool canCreateNewCollections = (collection.rights() & Collection::CanCreateCollection);
00624 const bool canContainCollections = collection.contentMimeTypes().contains( Collection::mimeType() );
00625 const bool resourceAllowsRequiredMimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet().contains( mimeTypes );
00626
00627 const bool isReadOnlyForItems = (isItemAction && (!canCreateNewItems || !canContainRequiredMimeTypes));
00628 const bool isReadOnlyForCollections = (isCollectionAction && (!canCreateNewCollections || !canContainCollections || !resourceAllowsRequiredMimeTypes));
00629
00630 const bool readOnly = CollectionUtils::isStructural( collection ) || isReadOnlyForItems || isReadOnlyForCollections;
00631
00632 if ( model->rowCount( index ) > 0 ) {
00633
00634 QMenu* popup = new QMenu( menu );
00635 const bool moveAction = ( type == MoveCollectionToMenu || type == MoveItemToMenu);
00636 popup->setObjectName( QString::fromUtf8( "subMenu" ) );
00637 popup->setTitle( label );
00638 popup->setIcon( icon );
00639
00640 fillFoldersMenu( type, popup, model, index );
00641
00642 if ( !readOnly ) {
00643 popup->addSeparator();
00644
00645 QAction *action = popup->addAction( moveAction ? i18n( "Move to This Folder" ) : i18n( "Copy to This Folder" ) );
00646 action->setData( QVariant::fromValue<QModelIndex>( index ) );
00647 }
00648
00649 menu->addMenu( popup );
00650
00651 } else {
00652
00653 QAction* action = menu->addAction( icon, label );
00654 action->setData( QVariant::fromValue<QModelIndex>( index ) );
00655 action->setEnabled( !readOnly );
00656 }
00657 }
00658 }
00659
00660 void checkModelsConsistency()
00661 {
00662 if ( favoritesModel == 0 || favoriteSelectionModel == 0 ) {
00663
00664 return;
00665 }
00666
00667
00668
00669 if ( collectionSelectionModel != 0 ) {
00670 const QAbstractItemModel *model = collectionSelectionModel->model();
00671 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) {
00672 model = proxy->sourceModel();
00673 }
00674 Q_ASSERT( model == favoritesModel->sourceModel() );
00675 }
00676
00677
00678 const QAbstractItemModel *model = favoriteSelectionModel->model();
00679 while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) {
00680 model = proxy->sourceModel();
00681 }
00682 Q_ASSERT( model == favoritesModel->sourceModel() );
00683 }
00684
00685 void markCutAction( QMimeData *mimeData, bool cut ) const
00686 {
00687 if ( !cut )
00688 return;
00689
00690 const QByteArray cutSelectionData = "1";
00691 mimeData->setData( QLatin1String( "application/x-kde.akonadi-cutselection" ), cutSelectionData);
00692 }
00693
00694 bool isCutAction( const QMimeData *mimeData ) const
00695 {
00696 const QByteArray data = mimeData->data( QLatin1String( "application/x-kde.akonadi-cutselection" ) );
00697 if ( data.isEmpty() )
00698 return false;
00699 else
00700 return (data.at( 0 ) == '1');
00701 }
00702
00703 StandardActionManager *q;
00704 KActionCollection *actionCollection;
00705 QWidget *parentWidget;
00706 QItemSelectionModel *collectionSelectionModel;
00707 QItemSelectionModel *itemSelectionModel;
00708 FavoriteCollectionsModel *favoritesModel;
00709 QItemSelectionModel *favoriteSelectionModel;
00710 QVector<KAction*> actions;
00711 QHash<StandardActionManager::Type, KLocalizedString> pluralLabels;
00712 };
00713
00714
00715
00716 StandardActionManager::StandardActionManager( KActionCollection * actionCollection,
00717 QWidget * parent) :
00718 QObject( parent ),
00719 d( new Private( this ) )
00720 {
00721 d->parentWidget = parent;
00722 d->actionCollection = actionCollection;
00723 connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ), SLOT( clipboardChanged( QClipboard::Mode ) ) );
00724 }
00725
00726 StandardActionManager::~ StandardActionManager()
00727 {
00728 delete d;
00729 }
00730
00731 void StandardActionManager::setCollectionSelectionModel( QItemSelectionModel * selectionModel )
00732 {
00733 d->collectionSelectionModel = selectionModel;
00734 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
00735 SLOT( collectionSelectionChanged() ) );
00736
00737 d->checkModelsConsistency();
00738 }
00739
00740 void StandardActionManager::setItemSelectionModel( QItemSelectionModel * selectionModel )
00741 {
00742 d->itemSelectionModel = selectionModel;
00743 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
00744 SLOT( updateActions() ) );
00745 }
00746
00747 void StandardActionManager::setFavoriteCollectionsModel( FavoriteCollectionsModel *favoritesModel )
00748 {
00749 d->favoritesModel = favoritesModel;
00750 d->checkModelsConsistency();
00751 }
00752
00753 void StandardActionManager::setFavoriteSelectionModel( QItemSelectionModel *selectionModel )
00754 {
00755 d->favoriteSelectionModel = selectionModel;
00756 connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
00757 SLOT( favoriteSelectionChanged() ) );
00758 d->checkModelsConsistency();
00759 }
00760
00761 KAction* StandardActionManager::createAction( Type type )
00762 {
00763 Q_ASSERT( type >= 0 && type < LastType );
00764 Q_ASSERT( actionData[type].name );
00765 if ( d->actions[type] )
00766 return d->actions[type];
00767 KAction *action;
00768 if ( !actionData[type].isActionMenu ) {
00769 action = new KAction( d->parentWidget );
00770 } else {
00771 action = new KActionMenu( d->parentWidget );
00772 }
00773
00774 if ( d->pluralLabels.contains( type ) && !d->pluralLabels.value( type ).isEmpty() )
00775 action->setText( d->pluralLabels.value( type ).subs( 1 ).toString() );
00776 else if ( actionData[type].label )
00777 action->setText( i18n( actionData[type].label ) );
00778
00779 if ( actionData[type].icon )
00780 action->setIcon( KIcon( QString::fromLatin1( actionData[type].icon ) ) );
00781
00782 action->setShortcut( actionData[type].shortcut );
00783
00784 if ( actionData[type].slot && !actionData[type].isActionMenu ) {
00785 connect( action, SIGNAL( triggered() ), actionData[type].slot );
00786 } else if ( actionData[type].slot ) {
00787 KActionMenu *actionMenu = qobject_cast<KActionMenu*>( action );
00788 connect( actionMenu->menu(), SIGNAL( triggered( QAction* ) ), actionData[type].slot );
00789 }
00790
00791 d->actionCollection->addAction( QString::fromLatin1(actionData[type].name), action );
00792 d->actions[type] = action;
00793 d->updateActions();
00794 return action;
00795 }
00796
00797 void StandardActionManager::createAllActions()
00798 {
00799 for ( int i = 0; i < LastType; ++i )
00800 createAction( (Type)i );
00801 }
00802
00803 KAction * StandardActionManager::action( Type type ) const
00804 {
00805 Q_ASSERT( type >= 0 && type < LastType );
00806 return d->actions[type];
00807 }
00808
00809 void StandardActionManager::setActionText( Type type, const KLocalizedString & text )
00810 {
00811 Q_ASSERT( type >= 0 && type < LastType );
00812 d->pluralLabels.insert( type, text );
00813 d->updateActions();
00814 }
00815
00816 #include "standardactionmanager.moc"