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