• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

akonadi

standardactionmanager.cpp

00001 /*
00002     Copyright (c) 2008 Volker Krause <vkrause@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "standardactionmanager.h"
00021 
00022 #include "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 //@cond PRIVATE
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       // Update the action menu
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               // The root collection is selected. There are no valid actions to enable.
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       // TODO: Copy or move? We can't seem to cut yet
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       // TODO: fix this once ItemModifyJob can handle item lists
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           // The mimetypes that the selected collection can possibly contain
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           // new level
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           // insert an item
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         // No need to check when the favorite collections feature is not used
00667         return;
00668       }
00669 
00670       // Check that the collection selection model maps to the same
00671       // EntityTreeModel than favoritesModel
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       // Check that the favorite selection model maps to favoritesModel
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"; //krazy:exclude=doublequote_chars
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'); // true if 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 //@endcond
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"

akonadi

Skip menu "akonadi"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal