• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • KDE Home
  • 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 "actionstatemanager_p.h"
00023 #include "agentfilterproxymodel.h"
00024 #include "agentinstancecreatejob.h"
00025 #include "agentmanager.h"
00026 #include "agenttypedialog.h"
00027 #include "collectioncreatejob.h"
00028 #include "collectiondeletejob.h"
00029 #include "collectiondialog.h"
00030 #include "collectionmodel.h"
00031 #include "collectionutils_p.h"
00032 #include "entitytreemodel.h"
00033 #include "favoritecollectionsmodel.h"
00034 #include "itemdeletejob.h"
00035 #include "itemmodel.h"
00036 #include "metatypes.h"
00037 #include "pastehelper_p.h"
00038 #include "specialcollectionattribute_p.h"
00039 #include "collectionpropertiesdialog.h"
00040 #include "subscriptiondialog_p.h"
00041 
00042 #include <KAction>
00043 #include <KActionCollection>
00044 #include <KActionMenu>
00045 #include <KDebug>
00046 #include <KInputDialog>
00047 #include <KLocale>
00048 #include <KMenu>
00049 #include <KMessageBox>
00050 #include <KToggleAction>
00051 
00052 #include <QtCore/QMimeData>
00053 #include <QtGui/QApplication>
00054 #include <QtGui/QClipboard>
00055 #include <QtGui/QItemSelectionModel>
00056 
00057 #include <boost/static_assert.hpp>
00058 
00059 using namespace Akonadi;
00060 
00061 //@cond PRIVATE
00062 
00063 enum ActionType
00064 {
00065   NormalAction,
00066   MenuAction,
00067   ToggleAction
00068 };
00069 
00070 static const struct {
00071   const char *name;
00072   const char *label;
00073   const char *iconLabel;
00074   const char *icon;
00075   int shortcut;
00076   const char* slot;
00077   ActionType actionType;
00078 } standardActionData[] = {
00079   { "akonadi_collection_create", I18N_NOOP( "&New Folder..." ), I18N_NOOP( "New" ), "folder-new", 0, SLOT( slotCreateCollection() ), NormalAction },
00080   { "akonadi_collection_copy", 0, 0, "edit-copy", 0, SLOT( slotCopyCollections() ), NormalAction },
00081   { "akonadi_collection_delete", I18N_NOOP( "&Delete Folder" ), I18N_NOOP( "Delete" ), "edit-delete", 0, SLOT( slotDeleteCollection() ), NormalAction },
00082   { "akonadi_collection_sync", I18N_NOOP( "&Synchronize Folder" ), I18N_NOOP( "Synchronize" ), "view-refresh", Qt::Key_F5, SLOT( slotSynchronizeCollection() ), NormalAction },
00083   { "akonadi_collection_properties", I18N_NOOP( "Folder &Properties" ), I18N_NOOP( "Properties" ), "configure", 0, SLOT( slotCollectionProperties() ), NormalAction },
00084   { "akonadi_item_copy", 0, 0, "edit-copy", 0, SLOT( slotCopyItems() ), NormalAction },
00085   { "akonadi_paste", I18N_NOOP( "&Paste" ), I18N_NOOP( "Paste" ), "edit-paste", Qt::CTRL + Qt::Key_V, SLOT( slotPaste() ), NormalAction },
00086   { "akonadi_item_delete", 0, 0, "edit-delete", Qt::Key_Delete, SLOT( slotDeleteItems() ), NormalAction },
00087   { "akonadi_manage_local_subscriptions", I18N_NOOP( "Manage Local &Subscriptions..." ), I18N_NOOP( "Manage Local Subscriptions" ), 0, 0, SLOT( slotLocalSubscription() ), NormalAction },
00088   { "akonadi_collection_add_to_favorites", I18N_NOOP( "Add to Favorite Folders" ), I18N_NOOP( "Add to Favorite" ), "bookmark-new", 0, SLOT( slotAddToFavorites() ), NormalAction },
00089   { "akonadi_collection_remove_from_favorites", I18N_NOOP( "Remove from Favorite Folders" ), I18N_NOOP( "Remove from Favorite" ), "edit-delete", 0, SLOT( slotRemoveFromFavorites() ), NormalAction },
00090   { "akonadi_collection_rename_favorite", I18N_NOOP( "Rename Favorite..." ), I18N_NOOP( "Rename" ), "edit-rename", 0, SLOT( slotRenameFavorite() ), NormalAction },
00091   { "akonadi_collection_copy_to_menu", I18N_NOOP( "Copy Folder To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyCollectionTo( QAction* ) ), MenuAction },
00092   { "akonadi_item_copy_to_menu", I18N_NOOP( "Copy Item To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyItemTo( QAction* ) ), MenuAction },
00093   { "akonadi_item_move_to_menu", I18N_NOOP( "Move Item To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveItemTo( QAction* ) ), MenuAction },
00094   { "akonadi_collection_move_to_menu", I18N_NOOP( "Move Folder To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveCollectionTo( QAction* ) ), MenuAction },
00095   { "akonadi_item_cut", I18N_NOOP( "&Cut Item" ), I18N_NOOP( "Cut" ), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT( slotCutItems() ), NormalAction },
00096   { "akonadi_collection_cut", I18N_NOOP( "&Cut Folder" ), I18N_NOOP( "Cut" ), "edit-cut", Qt::CTRL + Qt::Key_X, SLOT( slotCutCollections() ), NormalAction },
00097   { "akonadi_resource_create", I18N_NOOP( "Create Resource" ), 0, "folder-new", 0, SLOT( slotCreateResource() ), NormalAction },
00098   { "akonadi_resource_delete", I18N_NOOP( "Delete Resource" ), 0, "edit-delete", 0, SLOT( slotDeleteResource() ), NormalAction },
00099   { "akonadi_resource_properties", I18N_NOOP( "&Resource Properties" ), I18N_NOOP( "Properties" ), "configure", 0, SLOT( slotResourceProperties() ), NormalAction },
00100   { "akonadi_resource_synchronize", I18N_NOOP( "Synchronize Resource" ), I18N_NOOP( "Synchronize" ), "view-refresh", 0, SLOT( slotSynchronizeResource() ), NormalAction },
00101   { "akonadi_work_offline", I18N_NOOP( "Work Offline" ), 0, "user-offline", 0, SLOT( slotToggleWorkOffline(bool) ), ToggleAction },
00102   { "akonadi_collection_copy_to_dialog", I18N_NOOP( "Copy Folder To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyCollectionTo() ), NormalAction },
00103   { "akonadi_collection_move_to_dialog", I18N_NOOP( "Move Folder To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveCollectionTo() ), NormalAction },
00104   { "akonadi_item_copy_to_dialog", I18N_NOOP( "Copy Item To..." ), I18N_NOOP( "Copy To" ), "edit-copy", 0, SLOT( slotCopyItemTo() ), NormalAction },
00105   { "akonadi_item_move_to_dialog", I18N_NOOP( "Move Item To..." ), I18N_NOOP( "Move To" ), "go-jump", 0, SLOT( slotMoveItemTo() ), NormalAction },
00106   { "akonadi_collection_sync_recursive", I18N_NOOP( "&Synchronize Folder Recursively" ), I18N_NOOP( "Synchronize Recursively" ), "view-refresh", Qt::CTRL + Qt::Key_F5, SLOT( slotSynchronizeCollectionRecursive() ), NormalAction }
00107 };
00108 static const int numStandardActionData = sizeof standardActionData / sizeof *standardActionData;
00109 
00110 BOOST_STATIC_ASSERT( numStandardActionData == StandardActionManager::LastType );
00111 
00112 static bool canCreateCollection( const Akonadi::Collection &collection )
00113 {
00114   if ( !( collection.rights() & Akonadi::Collection::CanCreateCollection ) )
00115     return false;
00116 
00117   if ( !collection.contentMimeTypes().contains( Akonadi::Collection::mimeType() ) )
00118     return false;
00119 
00120   return true;
00121 }
00122 
00123 static inline bool isRootCollection( const Akonadi::Collection &collection )
00124 {
00125   return (collection == Akonadi::Collection::root());
00126 }
00127 
00128 static void setWorkOffline( bool offline )
00129 {
00130   KConfig config( QLatin1String( "akonadikderc" ) );
00131   KConfigGroup group( &config, QLatin1String( "Actions" ) );
00132 
00133   group.writeEntry( "WorkOffline", offline );
00134 }
00135 
00136 static bool workOffline()
00137 {
00138   KConfig config( QLatin1String( "akonadikderc" ) );
00139   const KConfigGroup group( &config, QLatin1String( "Actions" ) );
00140 
00141   return group.readEntry( "WorkOffline", false );
00142 }
00143 
00147 class StandardActionManager::Private
00148 {
00149   public:
00150     Private( StandardActionManager *parent ) :
00151       q( parent ),
00152       collectionSelectionModel( 0 ),
00153       itemSelectionModel( 0 ),
00154       favoritesModel( 0 ),
00155       favoriteSelectionModel( 0 )
00156     {
00157       actions.fill( 0, StandardActionManager::LastType );
00158 
00159       pluralLabels.insert( StandardActionManager::CopyCollections,
00160                            ki18np( "&Copy Folder", "&Copy %1 Folders" ) );
00161       pluralLabels.insert( StandardActionManager::CopyItems,
00162                            ki18np( "&Copy Item", "&Copy %1 Items" ) );
00163       pluralLabels.insert( StandardActionManager::CutItems,
00164                            ki18np( "&Cut Item", "&Cut %1 Items" ) );
00165       pluralLabels.insert( StandardActionManager::CutCollections,
00166                            ki18np( "&Cut Folder", "&Cut %1 Folders" ) );
00167       pluralLabels.insert( StandardActionManager::DeleteItems,
00168                            ki18np( "&Delete Item", "&Delete %1 Items" ) );
00169       pluralLabels.insert( StandardActionManager::DeleteCollections,
00170                            ki18np( "&Delete Folder", "&Delete %1 Folders" ) );
00171       pluralLabels.insert( StandardActionManager::SynchronizeCollections,
00172                            ki18np( "&Synchronize Folder", "&Synchronize %1 Folders" ) );
00173       pluralLabels.insert( StandardActionManager::DeleteResources,
00174                            ki18np( "&Delete Resource", "&Delete %1 Resources" ) );
00175       pluralLabels.insert( StandardActionManager::SynchronizeResources,
00176                            ki18np( "&Synchronize Resource", "&Synchronize %1 Resources" ) );
00177 
00178       pluralIconLabels.insert( StandardActionManager::CopyCollections,
00179                            ki18np( "Copy Folder", "Copy %1 Folders" ) );
00180       pluralIconLabels.insert( StandardActionManager::CopyItems,
00181                            ki18np( "Copy Item", "Copy %1 Items" ) );
00182       pluralIconLabels.insert( StandardActionManager::CutItems,
00183                            ki18np( "Cut Item", "Cut %1 Items" ) );
00184       pluralIconLabels.insert( StandardActionManager::CutCollections,
00185                            ki18np( "Cut Folder", "Cut %1 Folders" ) );
00186       pluralIconLabels.insert( StandardActionManager::DeleteItems,
00187                            ki18np( "Delete Item", "Delete %1 Items" ) );
00188       pluralIconLabels.insert( StandardActionManager::DeleteCollections,
00189                            ki18np( "Delete Folder", "Delete %1 Folders" ) );
00190       pluralIconLabels.insert( StandardActionManager::SynchronizeCollections,
00191                            ki18np( "Synchronize Folder", "Synchronize %1 Folders" ) );
00192       pluralIconLabels.insert( StandardActionManager::DeleteResources,
00193                            ki18np( "Delete Resource", "Delete %1 Resources" ) );
00194       pluralIconLabels.insert( StandardActionManager::SynchronizeResources,
00195                            ki18np( "Synchronize Resource", "Synchronize %1 Resources" ) );
00196 
00197       setContextText( StandardActionManager::CreateCollection, StandardActionManager::DialogTitle,
00198                       i18nc( "@title:window", "New Folder" ) );
00199       setContextText( StandardActionManager::CreateCollection, StandardActionManager::DialogText,
00200                       i18nc( "@label:textbox name of a thing", "Name" ) );
00201       setContextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText,
00202                       i18n( "Could not create folder: %1" ) );
00203       setContextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle,
00204                       i18n( "Folder creation failed" ) );
00205 
00206       setContextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText,
00207                       ki18np( "Do you really want to delete this folder and all its sub-folders?",
00208                               "Do you really want to delete %1 folders and all their sub-folders?" ) );
00209       setContextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle,
00210                       ki18ncp( "@title:window", "Delete folder?", "Delete folders?" ) );
00211       setContextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText,
00212                       i18n( "Could not delete folder: %1" ) );
00213       setContextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle,
00214                       i18n( "Folder deletion failed" ) );
00215 
00216       setContextText( StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle,
00217                       i18nc( "@title:window", "Properties of Folder %1" ) );
00218 
00219       setContextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText,
00220                       ki18np( "Do you really want to delete the selected item?",
00221                               "Do you really want to delete %1 items?" ) );
00222       setContextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle,
00223                       ki18ncp( "@title:window", "Delete item?", "Delete items?" ) );
00224       setContextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText,
00225                       i18n( "Could not delete item: %1" ) );
00226       setContextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle,
00227                       i18n( "Item deletion failed" ) );
00228 
00229       setContextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle,
00230                       i18nc( "@title:window", "Rename Favorite" ) );
00231       setContextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText,
00232                       i18nc( "@label:textbox name of the folder", "Name:" ) );
00233 
00234       setContextText( StandardActionManager::CreateResource, StandardActionManager::DialogTitle,
00235                       i18nc( "@title:window", "New Resource" ) );
00236       setContextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText,
00237                       i18n( "Could not create resource: %1" ) );
00238       setContextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle,
00239                       i18n( "Resource creation failed" ) );
00240 
00241       setContextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText,
00242                       ki18np( "Do you really want to delete this resource?",
00243                               "Do you really want to delete %1 resources?" ) );
00244       setContextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle,
00245                       ki18ncp( "@title:window", "Delete Resource?", "Delete Resources?" ) );
00246 
00247       setContextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageText,
00248                       i18n( "Could not paste data: %1" ) );
00249       setContextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle,
00250                       i18n( "Paste failed" ) );
00251 
00252       qRegisterMetaType<Akonadi::Item::List>("Akonadi::Item::List");
00253     }
00254 
00255     void enableAction( int type, bool enable )
00256     {
00257       enableAction( static_cast<StandardActionManager::Type>( type ), enable );
00258     }
00259 
00260     void enableAction( StandardActionManager::Type type, bool enable )
00261     {
00262       Q_ASSERT( type < StandardActionManager::LastType );
00263       if ( actions[type] )
00264         actions[type]->setEnabled( enable );
00265 
00266       // Update the action menu
00267       KActionMenu *actionMenu = qobject_cast<KActionMenu*>( actions[type] );
00268       if ( actionMenu ) {
00269         //get rid of the submenus, they are re-created in enableAction. clear() is not enough, doesn't remove the submenu object instances.
00270         KMenu *menu = actionMenu->menu();
00271         delete menu;
00272         menu = new KMenu();
00273 
00274         menu->setProperty( "actionType", static_cast<int>( type ) );
00275         q->connect( menu, SIGNAL( aboutToShow() ), SLOT( aboutToShowMenu() ) );
00276         q->connect( menu, SIGNAL( triggered( QAction* ) ), standardActionData[ type ].slot );
00277         actionMenu->setMenu( menu );
00278       }
00279     }
00280 
00281     void aboutToShowMenu()
00282     {
00283       QMenu *menu = qobject_cast<QMenu*>( q->sender() );
00284       if ( !menu )
00285         return;
00286 
00287       if ( !menu->isEmpty() )
00288         return;
00289 
00290       const StandardActionManager::Type type = static_cast<StandardActionManager::Type>( menu->property( "actionType" ).toInt() );
00291 
00292       fillFoldersMenu( type,
00293                        menu,
00294                        collectionSelectionModel->model(),
00295                        QModelIndex() );
00296     }
00297 
00298     void updatePluralLabel( int type, int count )
00299     {
00300       updatePluralLabel( static_cast<StandardActionManager::Type>( type ), count );
00301     }
00302 
00303     void updatePluralLabel( StandardActionManager::Type type, int count )
00304     {
00305       Q_ASSERT( type < StandardActionManager::LastType );
00306       if ( actions[type] && pluralLabels.contains( type ) && !pluralLabels.value( type ).isEmpty() ) {
00307         actions[type]->setText( pluralLabels.value( type ).subs( qMax( count, 1 ) ).toString() );
00308       }
00309     }
00310 
00311     bool isFavoriteCollection( const Akonadi::Collection &collection )
00312     {
00313       if ( !favoritesModel )
00314         return false;
00315 
00316       return favoritesModel->collections().contains( collection );
00317     }
00318 
00319     void encodeToClipboard( QItemSelectionModel* selectionModel, bool cut = false )
00320     {
00321       Q_ASSERT( selectionModel );
00322       if ( selectionModel->selectedRows().count() <= 0 )
00323         return;
00324 
00325 #ifndef QT_NO_CLIPBOARD
00326       QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00327       markCutAction( mimeData, cut );
00328       QApplication::clipboard()->setMimeData( mimeData );
00329 
00330       QAbstractItemModel *model = const_cast<QAbstractItemModel *>( selectionModel->model() );
00331 
00332       foreach ( const QModelIndex &index, selectionModel->selectedRows() )
00333         model->setData( index, true, EntityTreeModel::PendingCutRole );
00334 #endif
00335     }
00336 
00337     void updateActions()
00338     {
00339       // collect all selected collections
00340       Collection::List selectedCollections;
00341       if ( collectionSelectionModel ) {
00342         const QModelIndexList rows = collectionSelectionModel->selectedRows();
00343         foreach ( const QModelIndex &index, rows ) {
00344           Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00345           if ( !collection.isValid() )
00346             continue;
00347 
00348           const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00349           collection.setParentCollection( parentCollection );
00350 
00351           selectedCollections << collection;
00352         }
00353       }
00354 
00355       // collect all selected items
00356       Item::List selectedItems;
00357       if ( itemSelectionModel ) {
00358         const QModelIndexList rows = itemSelectionModel->selectedRows();
00359         foreach ( const QModelIndex &index, rows ) {
00360           Item item = index.data( EntityTreeModel::ItemRole ).value<Item>();
00361           if ( !item.isValid() )
00362             continue;
00363 
00364           const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00365           item.setParentCollection( parentCollection );
00366 
00367           selectedItems << item;
00368         }
00369       }
00370 
00371       mActionStateManager.updateState( selectedCollections, selectedItems );
00372 
00373       emit q->actionStateUpdated();
00374     }
00375 
00376 #ifndef QT_NO_CLIPBOARD
00377     void clipboardChanged( QClipboard::Mode mode )
00378     {
00379       if ( mode == QClipboard::Clipboard )
00380         updateActions();
00381     }
00382 #endif
00383 
00384     QItemSelection mapToEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const
00385     {
00386       const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model );
00387       if ( proxy ) {
00388         return mapToEntityTreeModel( proxy->sourceModel(), proxy->mapSelectionToSource( selection ) );
00389       } else {
00390         return selection;
00391       }
00392     }
00393 
00394     QItemSelection mapFromEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const
00395     {
00396       const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model );
00397       if ( proxy ) {
00398         const QItemSelection select = mapFromEntityTreeModel( proxy->sourceModel(), selection );
00399         return proxy->mapSelectionFromSource( select );
00400       } else {
00401         return selection;
00402       }
00403     }
00404 
00405     void collectionSelectionChanged()
00406     {
00407       q->blockSignals( true );
00408 
00409       QItemSelection selection = collectionSelectionModel->selection();
00410       selection = mapToEntityTreeModel( collectionSelectionModel->model(), selection );
00411       selection = mapFromEntityTreeModel( favoritesModel, selection );
00412 
00413       if ( favoriteSelectionModel )
00414         favoriteSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect );
00415 
00416       q->blockSignals( false );
00417 
00418       updateActions();
00419     }
00420 
00421     void favoriteSelectionChanged()
00422     {
00423       q->blockSignals( true );
00424 
00425       QItemSelection selection = favoriteSelectionModel->selection();
00426       if ( selection.indexes().isEmpty() )
00427         return;
00428 
00429       selection = mapToEntityTreeModel( favoritesModel, selection );
00430       selection = mapFromEntityTreeModel( collectionSelectionModel->model(), selection );
00431 
00432       collectionSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
00433       q->blockSignals( false );
00434 
00435       updateActions();
00436     }
00437 
00438     void slotCreateCollection()
00439     {
00440       Q_ASSERT( collectionSelectionModel );
00441       if ( collectionSelectionModel->selection().indexes().isEmpty() )
00442         return;
00443 
00444       const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00445       Q_ASSERT( index.isValid() );
00446       const Collection parentCollection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00447       Q_ASSERT( parentCollection.isValid() );
00448 
00449       if ( !canCreateCollection( parentCollection ) )
00450         return;
00451 
00452       const QString name = KInputDialog::getText( contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogTitle ),
00453                                                   contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogText ),
00454                                                   QString(), 0, parentWidget );
00455       if ( name.isEmpty() )
00456         return;
00457 
00458       Collection collection;
00459       collection.setName( name );
00460       collection.setParentCollection( parentCollection );
00461       if ( actions[StandardActionManager::CreateCollection] ) {
00462         const QStringList mts = actions[StandardActionManager::CreateCollection]->property( "ContentMimeTypes" ).toStringList();
00463         if ( !mts.isEmpty() )
00464           collection.setContentMimeTypes( mts );
00465       }
00466       CollectionCreateJob *job = new CollectionCreateJob( collection );
00467       q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionCreationResult( KJob* ) ) );
00468     }
00469 
00470     void slotCopyCollections()
00471     {
00472       encodeToClipboard( collectionSelectionModel );
00473     }
00474 
00475     void slotCutCollections()
00476     {
00477       encodeToClipboard( collectionSelectionModel, true );
00478     }
00479 
00480     Collection::List selectedCollections() const
00481     {
00482       Collection::List collections;
00483 
00484       Q_ASSERT( collectionSelectionModel );
00485 
00486       foreach ( const QModelIndex &index, collectionSelectionModel->selectedRows() ) {
00487         Q_ASSERT( index.isValid() );
00488         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00489         Q_ASSERT( collection.isValid() );
00490 
00491         collections << collection;
00492       }
00493 
00494       return collections;
00495     }
00496 
00497     void slotDeleteCollection()
00498     {
00499       const Collection::List collections = selectedCollections();
00500       if ( collections.isEmpty() )
00501         return;
00502 
00503       const QString collectionName = collections.first().name();
00504       const QString text = contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText,
00505                                         collections.count(), collectionName );
00506 
00507       if ( KMessageBox::questionYesNo( parentWidget, text,
00508            contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, collections.count(), collectionName ),
00509            KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00510            QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00511         return;
00512 
00513       foreach ( const Collection &collection, collections ) {
00514         CollectionDeleteJob *job = new CollectionDeleteJob( collection, q );
00515         q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionDeletionResult( KJob* ) ) );
00516       }
00517     }
00518 
00519     void slotSynchronizeCollection()
00520     {
00521       Q_ASSERT( collectionSelectionModel );
00522       const QModelIndexList list = collectionSelectionModel->selectedRows();
00523       if ( list.isEmpty() )
00524         return;
00525 
00526       const Collection::List collections = selectedCollections();
00527       if ( collections.isEmpty() )
00528         return;
00529 
00530       foreach( Collection collection, collections ) {
00531         AgentManager::self()->synchronizeCollection( collection, false );
00532       }
00533     }
00534 
00535     void slotSynchronizeCollectionRecursive()
00536     {
00537       Q_ASSERT( collectionSelectionModel );
00538       const QModelIndexList list = collectionSelectionModel->selectedRows();
00539       if ( list.isEmpty() )
00540         return;
00541 
00542       const Collection::List collections = selectedCollections();
00543       if ( collections.isEmpty() )
00544         return;
00545 
00546       foreach( Collection collection, collections ) {
00547         AgentManager::self()->synchronizeCollection( collection, true );
00548       }
00549     }
00550 
00551     void slotCollectionProperties()
00552     {
00553       const QModelIndexList list = collectionSelectionModel->selectedRows();
00554       if ( list.isEmpty() )
00555         return;
00556 
00557       const QModelIndex index = list.first();
00558       Q_ASSERT( index.isValid() );
00559 
00560       const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00561       Q_ASSERT( collection.isValid() );
00562 
00563       const QString displayName = collection.hasAttribute<EntityDisplayAttribute>() ? collection.attribute<EntityDisplayAttribute>()->displayName()
00564                                                                                     : collection.name();
00565 
00566       CollectionPropertiesDialog* dlg = new CollectionPropertiesDialog( collection, mCollectionPropertiesPageNames, parentWidget );
00567       dlg->setCaption( contextText( StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle ).arg( displayName ) );
00568       dlg->show();
00569     }
00570 
00571     void slotCopyItems()
00572     {
00573       encodeToClipboard( itemSelectionModel );
00574     }
00575 
00576     void slotCutItems()
00577     {
00578       encodeToClipboard( itemSelectionModel, true );
00579     }
00580 
00581     void slotPaste()
00582     {
00583       Q_ASSERT( collectionSelectionModel );
00584 
00585       const QModelIndexList list = collectionSelectionModel->selectedRows();
00586       if ( list.isEmpty() )
00587         return;
00588 
00589       const QModelIndex index = list.first();
00590       Q_ASSERT( index.isValid() );
00591 
00592 #ifndef QT_NO_CLIPBOARD
00593       // TODO: Copy or move? We can't seem to cut yet
00594       QAbstractItemModel *model = const_cast<QAbstractItemModel *>( collectionSelectionModel->model() );
00595       const QMimeData *mimeData = QApplication::clipboard()->mimeData();
00596       model->dropMimeData( mimeData, isCutAction( mimeData ) ? Qt::MoveAction : Qt::CopyAction, -1, -1, index );
00597       model->setData( QModelIndex(), false, EntityTreeModel::PendingCutRole );
00598       QApplication::clipboard()->clear();
00599 #endif
00600     }
00601 
00602     void slotDeleteItems()
00603     {
00604       Q_ASSERT( itemSelectionModel );
00605 
00606       Item::List items;
00607       foreach ( const QModelIndex &index, itemSelectionModel->selectedRows() ) {
00608         bool ok;
00609         const qlonglong id = index.data( ItemModel::IdRole ).toLongLong( &ok );
00610         Q_ASSERT( ok );
00611         items << Item( id );
00612       }
00613 
00614       if ( items.isEmpty() )
00615         return;
00616 
00617       QMetaObject::invokeMethod(q, "slotDeleteItemsDeferred",
00618                                 Qt::QueuedConnection,
00619                                 Q_ARG(Akonadi::Item::List, items));
00620     }
00621 
00622     void slotDeleteItemsDeferred(const Akonadi::Item::List &items)
00623     {
00624       Q_ASSERT( itemSelectionModel );
00625 
00626       if ( KMessageBox::questionYesNo( parentWidget,
00627            contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, items.count(), QString() ),
00628            contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, items.count(), QString() ),
00629            KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00630            QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00631         return;
00632 
00633       ItemDeleteJob *job = new ItemDeleteJob( items, q );
00634       q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( itemDeletionResult( KJob* ) ) );
00635     }
00636 
00637     void slotLocalSubscription()
00638     {
00639       SubscriptionDialog* dlg = new SubscriptionDialog( parentWidget );
00640       dlg->show();
00641     }
00642 
00643     void slotAddToFavorites()
00644     {
00645       Q_ASSERT( collectionSelectionModel );
00646       Q_ASSERT( favoritesModel );
00647       const QModelIndexList list = collectionSelectionModel->selectedRows();
00648       if ( list.isEmpty() )
00649         return;
00650 
00651       foreach ( const QModelIndex &index, list ) {
00652         Q_ASSERT( index.isValid() );
00653         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00654         Q_ASSERT( collection.isValid() );
00655 
00656         favoritesModel->addCollection( collection );
00657       }
00658 
00659       updateActions();
00660     }
00661 
00662     void slotRemoveFromFavorites()
00663     {
00664       Q_ASSERT( collectionSelectionModel );
00665       Q_ASSERT( favoritesModel );
00666       const QModelIndexList list = collectionSelectionModel->selectedRows();
00667       if ( list.isEmpty() )
00668         return;
00669 
00670       foreach ( const QModelIndex &index, list ) {
00671         Q_ASSERT( index.isValid() );
00672         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00673         Q_ASSERT( collection.isValid() );
00674 
00675         favoritesModel->removeCollection( collection );
00676       }
00677 
00678       updateActions();
00679     }
00680 
00681     void slotRenameFavorite()
00682     {
00683       Q_ASSERT( collectionSelectionModel );
00684       Q_ASSERT( favoritesModel );
00685       const QModelIndexList list = collectionSelectionModel->selectedRows();
00686       if ( list.isEmpty() )
00687         return;
00688 
00689       const QModelIndex index = list.first();
00690       Q_ASSERT( index.isValid() );
00691       const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00692       Q_ASSERT( collection.isValid() );
00693 
00694       bool ok;
00695       const QString label = KInputDialog::getText( contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle ),
00696                                                    contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText ),
00697                                                    favoritesModel->favoriteLabel( collection ), &ok, parentWidget );
00698       if ( !ok )
00699         return;
00700 
00701       favoritesModel->setFavoriteLabel( collection, label );
00702     }
00703 
00704     void slotCopyCollectionTo()
00705     {
00706       pasteTo( collectionSelectionModel, collectionSelectionModel->model(), CopyCollectionToMenu, Qt::CopyAction );
00707     }
00708 
00709     void slotCopyItemTo()
00710     {
00711       pasteTo( itemSelectionModel, collectionSelectionModel->model(), CopyItemToMenu, Qt::CopyAction );
00712     }
00713 
00714     void slotMoveCollectionTo()
00715     {
00716       pasteTo( collectionSelectionModel, collectionSelectionModel->model(), MoveCollectionToMenu, Qt::MoveAction );
00717     }
00718 
00719     void slotMoveItemTo()
00720     {
00721       pasteTo( itemSelectionModel, collectionSelectionModel->model(), MoveItemToMenu, Qt::MoveAction );
00722     }
00723 
00724     void slotCopyCollectionTo( QAction *action )
00725     {
00726       pasteTo( collectionSelectionModel, action, Qt::CopyAction );
00727     }
00728 
00729     void slotCopyItemTo( QAction *action )
00730     {
00731       pasteTo( itemSelectionModel, action, Qt::CopyAction );
00732     }
00733 
00734     void slotMoveCollectionTo( QAction *action )
00735     {
00736       pasteTo( collectionSelectionModel, action, Qt::MoveAction );
00737     }
00738 
00739     void slotMoveItemTo( QAction *action )
00740     {
00741       pasteTo( itemSelectionModel, action, Qt::MoveAction );
00742     }
00743 
00744     AgentInstance::List selectedAgentInstances() const
00745     {
00746       AgentInstance::List instances;
00747 
00748       Q_ASSERT( collectionSelectionModel );
00749       if ( collectionSelectionModel->selection().indexes().isEmpty() )
00750         return instances;
00751 
00752       foreach ( const QModelIndex &index, collectionSelectionModel->selection().indexes() ) {
00753         Q_ASSERT( index.isValid() );
00754         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00755         Q_ASSERT( collection.isValid() );
00756 
00757         if ( collection.isValid() ) {
00758           const QString identifier = collection.resource();
00759           instances << AgentManager::self()->instance( identifier );
00760         }
00761       }
00762 
00763       return instances;
00764     }
00765 
00766     AgentInstance selectedAgentInstance() const
00767     {
00768       const AgentInstance::List instances = selectedAgentInstances();
00769 
00770       if ( instances.isEmpty() )
00771         return AgentInstance();
00772 
00773       return instances.first();
00774     }
00775 
00776     void slotCreateResource()
00777     {
00778       Akonadi::AgentTypeDialog dlg( parentWidget );
00779       dlg.setCaption( contextText( StandardActionManager::CreateResource, StandardActionManager::DialogTitle ) );
00780 
00781       foreach ( const QString &mimeType, mMimeTypeFilter )
00782         dlg.agentFilterProxyModel()->addMimeTypeFilter( mimeType );
00783 
00784       foreach ( const QString &capability, mCapabilityFilter )
00785         dlg.agentFilterProxyModel()->addCapabilityFilter( capability );
00786 
00787       if ( dlg.exec() ) {
00788         const AgentType agentType = dlg.agentType();
00789 
00790         if ( agentType.isValid() ) {
00791           AgentInstanceCreateJob *job = new AgentInstanceCreateJob( agentType, q );
00792           q->connect( job, SIGNAL( result( KJob* ) ), SLOT( resourceCreationResult( KJob* ) ) );
00793           job->configure( parentWidget );
00794           job->start();
00795         }
00796       }
00797     }
00798 
00799     void slotDeleteResource()
00800     {
00801       const AgentInstance::List instances = selectedAgentInstances();
00802       if ( instances.isEmpty() )
00803         return;
00804 
00805       if ( KMessageBox::questionYesNo( parentWidget,
00806            contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, instances.count(), instances.first().name() ),
00807            contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, instances.count(), instances.first().name() ),
00808            KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00809            QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00810         return;
00811 
00812       foreach ( const AgentInstance &instance, instances )
00813         AgentManager::self()->removeInstance( instance );
00814     }
00815 
00816     void slotSynchronizeResource()
00817     {
00818       const AgentInstance::List instances = selectedAgentInstances();
00819       if ( instances.isEmpty() )
00820         return;
00821 
00822       foreach ( AgentInstance instance, instances )
00823         instance.synchronize();
00824     }
00825 
00826     void slotResourceProperties()
00827     {
00828       AgentInstance instance = selectedAgentInstance();
00829       if ( !instance.isValid() )
00830         return;
00831 
00832       instance.configure( parentWidget );
00833     }
00834 
00835     void slotToggleWorkOffline( bool offline )
00836     {
00837       setWorkOffline( offline );
00838 
00839       AgentInstance::List instances = AgentManager::self()->instances();
00840       foreach ( AgentInstance instance, instances ) {
00841         instance.setIsOnline( !offline );
00842       }
00843     }
00844 
00845     void pasteTo( QItemSelectionModel *selectionModel, const QAbstractItemModel *model, StandardActionManager::Type type, Qt::DropAction dropAction )
00846     {
00847       const QSet<QString> mimeTypes = mimeTypesOfSelection( type );
00848 
00849       CollectionDialog dlg( const_cast<QAbstractItemModel*>( model ) );
00850       dlg.setMimeTypeFilter( mimeTypes.toList() );
00851 
00852       if ( type == CopyItemToMenu || type == MoveItemToMenu )
00853         dlg.setAccessRightsFilter( Collection::CanCreateItem );
00854       else if ( type == CopyCollectionToMenu || type == MoveCollectionToMenu )
00855         dlg.setAccessRightsFilter( Collection::CanCreateCollection );
00856 
00857       if ( dlg.exec() ) {
00858         const QModelIndex index = EntityTreeModel::modelIndexForCollection( collectionSelectionModel->model(), dlg.selectedCollection() );
00859         if ( !index.isValid() )
00860           return;
00861 
00862         const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00863 
00864         QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() );
00865         model->dropMimeData( mimeData, dropAction, -1, -1, index );
00866       }
00867     }
00868 
00869     void pasteTo( QItemSelectionModel *selectionModel, QAction *action, Qt::DropAction dropAction )
00870     {
00871       Q_ASSERT( selectionModel );
00872       Q_ASSERT( action );
00873 
00874       if ( selectionModel->selectedRows().count() <= 0 )
00875         return;
00876 
00877       const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00878 
00879       const QModelIndex index = action->data().value<QModelIndex>();
00880 
00881       Q_ASSERT( index.isValid() );
00882 
00883       QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() );
00884       model->dropMimeData( mimeData, dropAction, -1, -1, index );
00885     }
00886 
00887     void collectionCreationResult( KJob *job )
00888     {
00889       if ( job->error() ) {
00890         KMessageBox::error( parentWidget,
00891                             contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00892                             contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle ) );
00893       }
00894     }
00895 
00896     void collectionDeletionResult( KJob *job )
00897     {
00898       if ( job->error() ) {
00899         KMessageBox::error( parentWidget,
00900                             contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00901                             contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle ) );
00902       }
00903     }
00904 
00905     void itemDeletionResult( KJob *job )
00906     {
00907       if ( job->error() ) {
00908         KMessageBox::error( parentWidget,
00909                             contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00910                             contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle ) );
00911       }
00912     }
00913 
00914     void resourceCreationResult( KJob *job )
00915     {
00916       if ( job->error() ) {
00917         KMessageBox::error( parentWidget,
00918                             contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00919                             contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle ) );
00920       }
00921     }
00922 
00923     void pasteResult( KJob *job )
00924     {
00925       if ( job->error() ) {
00926         KMessageBox::error( parentWidget,
00927                             contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00928                             contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle ) );
00929       }
00930     }
00931 
00935     QSet<QString> mimeTypesOfSelection( StandardActionManager::Type type ) const
00936     {
00937       QModelIndexList list;
00938       QSet<QString> mimeTypes;
00939 
00940       const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu );
00941       const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu );
00942 
00943       if ( isItemAction ) {
00944         list = itemSelectionModel->selectedRows();
00945         foreach ( const QModelIndex &index, list )
00946           mimeTypes << index.data( EntityTreeModel::MimeTypeRole ).toString();
00947       }
00948 
00949       if ( isCollectionAction ) {
00950         list = collectionSelectionModel->selectedRows();
00951         foreach ( const QModelIndex &index, list ) {
00952           const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00953 
00954           // The mimetypes that the selected collection can possibly contain
00955           mimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet();
00956         }
00957       }
00958 
00959       return mimeTypes;
00960     }
00961 
00965     bool isWritableTargetCollectionForMimeTypes( const Collection &collection, const QSet<QString> &mimeTypes, StandardActionManager::Type type ) const
00966     {
00967       if ( CollectionUtils::isVirtual( collection ) )
00968         return false;
00969 
00970       const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu );
00971       const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu );
00972 
00973       const bool canContainRequiredMimeTypes = !collection.contentMimeTypes().toSet().intersect( mimeTypes ).isEmpty();
00974       const bool canCreateNewItems = (collection.rights() & Collection::CanCreateItem);
00975 
00976       const bool canCreateNewCollections = (collection.rights() & Collection::CanCreateCollection);
00977       const bool canContainCollections = collection.contentMimeTypes().contains( Collection::mimeType() );
00978       const bool resourceAllowsRequiredMimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet().contains( mimeTypes );
00979 
00980       const bool isReadOnlyForItems = (isItemAction && (!canCreateNewItems || !canContainRequiredMimeTypes));
00981       const bool isReadOnlyForCollections = (isCollectionAction && (!canCreateNewCollections || !canContainCollections || !resourceAllowsRequiredMimeTypes));
00982 
00983       return !(CollectionUtils::isStructural( collection ) || isReadOnlyForItems || isReadOnlyForCollections);
00984     }
00985 
00986     void fillFoldersMenu( StandardActionManager::Type type, QMenu *menu,
00987                           const QAbstractItemModel *model, QModelIndex parentIndex )
00988     {
00989       const int rowCount = model->rowCount( parentIndex );
00990 
00991       const QSet<QString> mimeTypes = mimeTypesOfSelection( type );
00992 
00993       for ( int row = 0; row < rowCount; ++row ) {
00994         const QModelIndex index = model->index( row, 0, parentIndex );
00995         const Collection collection = model->data( index, CollectionModel::CollectionRole ).value<Collection>();
00996 
00997         if ( CollectionUtils::isVirtual( collection ) )
00998           continue;
00999 
01000         const bool readOnly = !isWritableTargetCollectionForMimeTypes( collection, mimeTypes, type );
01001 
01002         QString label = model->data( index ).toString();
01003         label.replace( QLatin1String( "&" ), QLatin1String( "&&" ) );
01004 
01005         const QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>();
01006 
01007         if ( model->rowCount( index ) > 0 ) {
01008           // new level
01009           QMenu* popup = new QMenu( menu );
01010           const bool moveAction = (type == MoveCollectionToMenu || type == MoveItemToMenu);
01011           popup->setObjectName( QString::fromUtf8( "subMenu" ) );
01012           popup->setTitle( label );
01013           popup->setIcon( icon );
01014 
01015           fillFoldersMenu( type, popup, model, index );
01016 
01017           if ( !readOnly ) {
01018             popup->addSeparator();
01019 
01020             QAction *action = popup->addAction( moveAction ? i18n( "Move to This Folder" ) : i18n( "Copy to This Folder" ) );
01021             action->setData( QVariant::fromValue<QModelIndex>( index ) );
01022           }
01023 
01024           menu->addMenu( popup );
01025 
01026         } else {
01027           // insert an item
01028           QAction* action = menu->addAction( icon, label );
01029           action->setData( QVariant::fromValue<QModelIndex>( index ) );
01030           action->setEnabled( !readOnly );
01031         }
01032       }
01033     }
01034 
01035     void checkModelsConsistency()
01036     {
01037       if ( favoritesModel == 0 || favoriteSelectionModel == 0 ) {
01038         // No need to check when the favorite collections feature is not used
01039         return;
01040       }
01041 
01042       // find the base ETM of the favourites view
01043       const QAbstractItemModel *favModel = favoritesModel;
01044       while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( favModel ) ) {
01045         favModel = proxy->sourceModel();
01046       }
01047 
01048       // Check that the collection selection model maps to the same
01049       // EntityTreeModel than favoritesModel
01050       if ( collectionSelectionModel != 0 ) {
01051         const QAbstractItemModel *model = collectionSelectionModel->model();
01052         while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) {
01053           model = proxy->sourceModel();
01054         }
01055 
01056         Q_ASSERT( model == favModel );
01057       }
01058 
01059       // Check that the favorite selection model maps to favoritesModel
01060       const QAbstractItemModel *model = favoriteSelectionModel->model();
01061       while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) {
01062         model = proxy->sourceModel();
01063       }
01064       Q_ASSERT( model == favModel );
01065     }
01066 
01067     void markCutAction( QMimeData *mimeData, bool cut ) const
01068     {
01069       if ( !cut )
01070         return;
01071 
01072       const QByteArray cutSelectionData = "1"; //krazy:exclude=doublequote_chars
01073       mimeData->setData( QLatin1String( "application/x-kde.akonadi-cutselection" ), cutSelectionData);
01074     }
01075 
01076     bool isCutAction( const QMimeData *mimeData ) const
01077     {
01078       const QByteArray data = mimeData->data( QLatin1String( "application/x-kde.akonadi-cutselection" ) );
01079       if ( data.isEmpty() )
01080         return false;
01081       else
01082         return (data.at( 0 ) == '1'); // true if 1
01083     }
01084 
01085     void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &data )
01086     {
01087       ContextTextEntry entry;
01088       entry.text = data;
01089 
01090       contextTexts[ type ].insert( context, entry );
01091     }
01092 
01093     void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const KLocalizedString &data )
01094     {
01095       ContextTextEntry entry;
01096       entry.localizedText = data;
01097 
01098       contextTexts[ type ].insert( context, entry );
01099     }
01100 
01101     QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context ) const
01102     {
01103       return contextTexts[ type ].value( context ).text;
01104     }
01105 
01106     QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context, int count, const QString &value ) const
01107     {
01108       if ( contextTexts[ type ].value( context ).localizedText.isEmpty() )
01109         return contextTexts[ type ].value( context ).text;
01110 
01111       KLocalizedString text = contextTexts[ type ].value( context ).localizedText;
01112       const QString str = text.subs( count ).toString();
01113       const int argCount = str.count( QRegExp( QLatin1String( "%[0-9]" ) ) );
01114       if ( argCount > 0 ) {
01115         return text.subs( count ).subs( value ).toString();
01116       } else {
01117         return text.subs( count ).toString();
01118       }
01119     }
01120 
01121     StandardActionManager *q;
01122     KActionCollection *actionCollection;
01123     QWidget *parentWidget;
01124     QItemSelectionModel *collectionSelectionModel;
01125     QItemSelectionModel *itemSelectionModel;
01126     FavoriteCollectionsModel *favoritesModel;
01127     QItemSelectionModel *favoriteSelectionModel;
01128     QVector<KAction*> actions;
01129     QHash<StandardActionManager::Type, KLocalizedString> pluralLabels;
01130     QHash<StandardActionManager::Type, KLocalizedString> pluralIconLabels;
01131 
01132     struct ContextTextEntry
01133     {
01134       QString text;
01135       KLocalizedString localizedText;
01136       bool isLocalized;
01137     };
01138 
01139     typedef QHash<StandardActionManager::TextContext, ContextTextEntry> ContextTexts;
01140     QHash<StandardActionManager::Type, ContextTexts> contextTexts;
01141 
01142     ActionStateManager mActionStateManager;
01143 
01144     QStringList mMimeTypeFilter;
01145     QStringList mCapabilityFilter;
01146     QStringList mCollectionPropertiesPageNames;
01147 };
01148 
01149 //@endcond
01150 
01151 StandardActionManager::StandardActionManager( KActionCollection * actionCollection,
01152                                               QWidget * parent) :
01153     QObject( parent ),
01154     d( new Private( this ) )
01155 {
01156   d->parentWidget = parent;
01157   d->actionCollection = actionCollection;
01158   d->mActionStateManager.setReceiver( this );
01159 #ifndef QT_NO_CLIPBOARD
01160   connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ), SLOT( clipboardChanged( QClipboard::Mode ) ) );
01161 #endif
01162 }
01163 
01164 StandardActionManager::~ StandardActionManager()
01165 {
01166   delete d;
01167 }
01168 
01169 void StandardActionManager::setCollectionSelectionModel( QItemSelectionModel * selectionModel )
01170 {
01171   d->collectionSelectionModel = selectionModel;
01172   connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
01173            SLOT( collectionSelectionChanged() ) );
01174 
01175   d->checkModelsConsistency();
01176 }
01177 
01178 void StandardActionManager::setItemSelectionModel( QItemSelectionModel * selectionModel )
01179 {
01180   d->itemSelectionModel = selectionModel;
01181   connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
01182            SLOT( updateActions() ) );
01183 }
01184 
01185 void StandardActionManager::setFavoriteCollectionsModel( FavoriteCollectionsModel *favoritesModel )
01186 {
01187   d->favoritesModel = favoritesModel;
01188   d->checkModelsConsistency();
01189 }
01190 
01191 void StandardActionManager::setFavoriteSelectionModel( QItemSelectionModel *selectionModel )
01192 {
01193   d->favoriteSelectionModel = selectionModel;
01194   connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
01195            SLOT( favoriteSelectionChanged() ) );
01196   d->checkModelsConsistency();
01197 }
01198 
01199 KAction* StandardActionManager::createAction( Type type )
01200 {
01201   Q_ASSERT( type < LastType );
01202   Q_ASSERT( standardActionData[type].name );
01203   if ( d->actions[type] )
01204     return d->actions[type];
01205   KAction *action = 0;
01206   switch ( standardActionData[type].actionType ) {
01207     case NormalAction:
01208       action = new KAction( d->parentWidget );
01209       break;
01210     case MenuAction:
01211       action = new KActionMenu( d->parentWidget );
01212       break;
01213     case ToggleAction:
01214       action = new KToggleAction( d->parentWidget );
01215       break;
01216   }
01217 
01218   if ( d->pluralLabels.contains( type ) && !d->pluralLabels.value( type ).isEmpty() )
01219     action->setText( d->pluralLabels.value( type ).subs( 1 ).toString() );
01220   else if ( standardActionData[type].label )
01221     action->setText( i18n( standardActionData[type].label ) );
01222 
01223   if ( d->pluralIconLabels.contains( type ) && !d->pluralIconLabels.value( type ).isEmpty() )
01224     action->setIconText( d->pluralIconLabels.value( type ).subs( 1 ).toString() );
01225   else if ( standardActionData[type].iconLabel )
01226     action->setIconText( i18n( standardActionData[type].iconLabel ) );
01227 
01228   if ( standardActionData[type].icon )
01229     action->setIcon( KIcon( QString::fromLatin1( standardActionData[type].icon ) ) );
01230 
01231   action->setShortcut( standardActionData[type].shortcut );
01232 
01233   if ( standardActionData[type].slot ) {
01234     switch ( standardActionData[type].actionType ) {
01235       case NormalAction:
01236         connect( action, SIGNAL( triggered() ), standardActionData[type].slot );
01237         break;
01238       case MenuAction:
01239         {
01240           KActionMenu *actionMenu = qobject_cast<KActionMenu*>( action );
01241           connect( actionMenu->menu(), SIGNAL( triggered( QAction* ) ), standardActionData[type].slot );
01242         }
01243         break;
01244       case ToggleAction:
01245         {
01246           connect( action, SIGNAL( triggered( bool ) ), standardActionData[type].slot );
01247         }
01248         break;
01249     }
01250   }
01251 
01252   if ( type == ToggleWorkOffline ) {
01253     // inititalize the action state with information from config file
01254     disconnect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot );
01255     action->setChecked( workOffline() );
01256     connect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot );
01257 
01258     //TODO: find a way to check for updates to the config file
01259   }
01260 
01261   d->actionCollection->addAction( QString::fromLatin1(standardActionData[type].name), action );
01262   d->actions[type] = action;
01263   d->updateActions();
01264   return action;
01265 }
01266 
01267 void StandardActionManager::createAllActions()
01268 {
01269   for ( uint i = 0; i < LastType; ++i )
01270     createAction( (Type)i );
01271 }
01272 
01273 KAction * StandardActionManager::action( Type type ) const
01274 {
01275   Q_ASSERT( type < LastType );
01276   return d->actions[type];
01277 }
01278 
01279 void StandardActionManager::setActionText( Type type, const KLocalizedString & text )
01280 {
01281   Q_ASSERT( type < LastType );
01282   d->pluralLabels.insert( type, text );
01283   d->updateActions();
01284 }
01285 
01286 void StandardActionManager::interceptAction( Type type, bool intercept )
01287 {
01288   Q_ASSERT( type < LastType );
01289 
01290   const KAction *action = d->actions[type];
01291 
01292   if ( !action )
01293     return;
01294 
01295   if ( intercept )
01296     disconnect( action, SIGNAL( triggered() ), this, standardActionData[type].slot );
01297   else
01298     connect( action, SIGNAL( triggered() ), standardActionData[type].slot );
01299 }
01300 
01301 Akonadi::Collection::List StandardActionManager::selectedCollections() const
01302 {
01303   Collection::List collections;
01304 
01305   if ( !d->collectionSelectionModel )
01306     return collections;
01307 
01308   foreach ( const QModelIndex &index, d->collectionSelectionModel->selectedRows() ) {
01309     const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
01310     if ( collection.isValid() )
01311       collections << collection;
01312   }
01313 
01314   return collections;
01315 }
01316 
01317 Item::List StandardActionManager::selectedItems() const
01318 {
01319   Item::List items;
01320 
01321   if ( !d->itemSelectionModel )
01322     return items;
01323 
01324   foreach ( const QModelIndex &index, d->itemSelectionModel->selectedRows() ) {
01325     const Item item = index.data( EntityTreeModel::ItemRole ).value<Item>();
01326     if ( item.isValid() )
01327       items << item;
01328   }
01329 
01330   return items;
01331 }
01332 
01333 void StandardActionManager::setContextText( Type type, TextContext context, const QString &text )
01334 {
01335   d->setContextText( type, context, text );
01336 }
01337 
01338 void StandardActionManager::setContextText( Type type, TextContext context, const KLocalizedString &text )
01339 {
01340   d->setContextText( type, context, text );
01341 }
01342 
01343 void StandardActionManager::setMimeTypeFilter( const QStringList &mimeTypes )
01344 {
01345   d->mMimeTypeFilter = mimeTypes;
01346 }
01347 
01348 void StandardActionManager::setCapabilityFilter( const QStringList &capabilities )
01349 {
01350   d->mCapabilityFilter = capabilities;
01351 }
01352 
01353 void StandardActionManager::setCollectionPropertiesPageNames( const QStringList &names )
01354 {
01355   d->mCollectionPropertiesPageNames = names;
01356 }
01357 
01358 #include "standardactionmanager.moc"

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
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • 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.4
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