• Skip to content
  • Skip to link menu
KDE 4.5 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 #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 //@cond PRIVATE
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       // Update the action menu
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               // The root collection is selected. There are no valid actions to enable.
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       // TODO: Copy or move? We can't seem to cut yet
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       // TODO: fix this once ItemModifyJob can handle item lists
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           // The mimetypes that the selected collection can possibly contain
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           // new level
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           // insert an item
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         // No need to check when the favorite collections feature is not used
00664         return;
00665       }
00666 
00667       // Check that the collection selection model maps to the same
00668       // EntityTreeModel than favoritesModel
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       // Check that the favorite selection model maps to favoritesModel
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"; //krazy:exclude=doublequote_chars
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'); // true if 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 //@endcond
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"

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.7.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