• Skip to content
  • Skip to link menu
KDE 4.7 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         //Not necessary to delete and recreate menu when it was not created
00272         if ( menu->property( "actionType" ).isValid() && menu->isEmpty() )
00273           return;
00274         delete menu;
00275         menu = new KMenu();
00276 
00277         menu->setProperty( "actionType", static_cast<int>( type ) );
00278         q->connect( menu, SIGNAL( aboutToShow() ), SLOT( aboutToShowMenu() ) );
00279         q->connect( menu, SIGNAL( triggered( QAction* ) ), standardActionData[ type ].slot );
00280         actionMenu->setMenu( menu );
00281       }
00282     }
00283 
00284     void aboutToShowMenu()
00285     {
00286       QMenu *menu = qobject_cast<QMenu*>( q->sender() );
00287       if ( !menu )
00288         return;
00289 
00290       if ( !menu->isEmpty() )
00291         return;
00292       const StandardActionManager::Type type = static_cast<StandardActionManager::Type>( menu->property( "actionType" ).toInt() );
00293 
00294       fillFoldersMenu( type,
00295                        menu,
00296                        collectionSelectionModel->model(),
00297                        QModelIndex() );
00298     }
00299 
00300     void updatePluralLabel( int type, int count )
00301     {
00302       updatePluralLabel( static_cast<StandardActionManager::Type>( type ), count );
00303     }
00304 
00305     void updatePluralLabel( StandardActionManager::Type type, int count )
00306     {
00307       Q_ASSERT( type < StandardActionManager::LastType );
00308       if ( actions[type] && pluralLabels.contains( type ) && !pluralLabels.value( type ).isEmpty() ) {
00309         actions[type]->setText( pluralLabels.value( type ).subs( qMax( count, 1 ) ).toString() );
00310       }
00311     }
00312 
00313     bool isFavoriteCollection( const Akonadi::Collection &collection )
00314     {
00315       if ( !favoritesModel )
00316         return false;
00317 
00318       return favoritesModel->collections().contains( collection );
00319     }
00320 
00321     void encodeToClipboard( QItemSelectionModel* selectionModel, bool cut = false )
00322     {
00323       Q_ASSERT( selectionModel );
00324       if ( selectionModel->selectedRows().count() <= 0 )
00325         return;
00326 
00327 #ifndef QT_NO_CLIPBOARD
00328       QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00329       markCutAction( mimeData, cut );
00330       QApplication::clipboard()->setMimeData( mimeData );
00331 
00332       QAbstractItemModel *model = const_cast<QAbstractItemModel *>( selectionModel->model() );
00333 
00334       foreach ( const QModelIndex &index, selectionModel->selectedRows() )
00335         model->setData( index, true, EntityTreeModel::PendingCutRole );
00336 #endif
00337     }
00338 
00339     void updateActions()
00340     {
00341       // collect all selected collections
00342       Collection::List selectedCollections;
00343       if ( collectionSelectionModel ) {
00344         const QModelIndexList rows = collectionSelectionModel->selectedRows();
00345         foreach ( const QModelIndex &index, rows ) {
00346           Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00347           if ( !collection.isValid() )
00348             continue;
00349 
00350           const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00351           collection.setParentCollection( parentCollection );
00352 
00353           selectedCollections << collection;
00354         }
00355       }
00356 
00357       // collect all selected items
00358       Item::List selectedItems;
00359       if ( itemSelectionModel ) {
00360         const QModelIndexList rows = itemSelectionModel->selectedRows();
00361         foreach ( const QModelIndex &index, rows ) {
00362           Item item = index.data( EntityTreeModel::ItemRole ).value<Item>();
00363           if ( !item.isValid() )
00364             continue;
00365 
00366           const Collection parentCollection = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00367           item.setParentCollection( parentCollection );
00368 
00369           selectedItems << item;
00370         }
00371       }
00372 
00373       mActionStateManager.updateState( selectedCollections, selectedItems );
00374 
00375       emit q->actionStateUpdated();
00376     }
00377 
00378 #ifndef QT_NO_CLIPBOARD
00379     void clipboardChanged( QClipboard::Mode mode )
00380     {
00381       if ( mode == QClipboard::Clipboard )
00382         updateActions();
00383     }
00384 #endif
00385 
00386     QItemSelection mapToEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const
00387     {
00388       const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model );
00389       if ( proxy ) {
00390         return mapToEntityTreeModel( proxy->sourceModel(), proxy->mapSelectionToSource( selection ) );
00391       } else {
00392         return selection;
00393       }
00394     }
00395 
00396     QItemSelection mapFromEntityTreeModel( const QAbstractItemModel *model, const QItemSelection &selection ) const
00397     {
00398       const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model );
00399       if ( proxy ) {
00400         const QItemSelection select = mapFromEntityTreeModel( proxy->sourceModel(), selection );
00401         return proxy->mapSelectionFromSource( select );
00402       } else {
00403         return selection;
00404       }
00405     }
00406 
00407     void collectionSelectionChanged()
00408     {
00409       q->blockSignals( true );
00410 
00411       QItemSelection selection = collectionSelectionModel->selection();
00412       selection = mapToEntityTreeModel( collectionSelectionModel->model(), selection );
00413       selection = mapFromEntityTreeModel( favoritesModel, selection );
00414 
00415       if ( favoriteSelectionModel )
00416         favoriteSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect );
00417 
00418       q->blockSignals( false );
00419 
00420       updateActions();
00421     }
00422 
00423     void favoriteSelectionChanged()
00424     {
00425       q->blockSignals( true );
00426 
00427       QItemSelection selection = favoriteSelectionModel->selection();
00428       if ( selection.indexes().isEmpty() )
00429         return;
00430 
00431       selection = mapToEntityTreeModel( favoritesModel, selection );
00432       selection = mapFromEntityTreeModel( collectionSelectionModel->model(), selection );
00433 
00434       collectionSelectionModel->select( selection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
00435       q->blockSignals( false );
00436 
00437       updateActions();
00438     }
00439 
00440     void slotCreateCollection()
00441     {
00442       Q_ASSERT( collectionSelectionModel );
00443       if ( collectionSelectionModel->selection().indexes().isEmpty() )
00444         return;
00445 
00446       const QModelIndex index = collectionSelectionModel->selection().indexes().at( 0 );
00447       Q_ASSERT( index.isValid() );
00448       const Collection parentCollection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00449       Q_ASSERT( parentCollection.isValid() );
00450 
00451       if ( !canCreateCollection( parentCollection ) )
00452         return;
00453 
00454       const QString name = KInputDialog::getText( contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogTitle ),
00455                                                   contextText( StandardActionManager::CreateCollection, StandardActionManager::DialogText ),
00456                                                   QString(), 0, parentWidget );
00457       if ( name.isEmpty() )
00458         return;
00459 
00460       Collection collection;
00461       collection.setName( name );
00462       collection.setParentCollection( parentCollection );
00463       if ( actions[StandardActionManager::CreateCollection] ) {
00464         const QStringList mts = actions[StandardActionManager::CreateCollection]->property( "ContentMimeTypes" ).toStringList();
00465         if ( !mts.isEmpty() )
00466           collection.setContentMimeTypes( mts );
00467       }
00468       CollectionCreateJob *job = new CollectionCreateJob( collection );
00469       q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionCreationResult( KJob* ) ) );
00470     }
00471 
00472     void slotCopyCollections()
00473     {
00474       encodeToClipboard( collectionSelectionModel );
00475     }
00476 
00477     void slotCutCollections()
00478     {
00479       encodeToClipboard( collectionSelectionModel, true );
00480     }
00481 
00482     Collection::List selectedCollections() const
00483     {
00484       Collection::List collections;
00485 
00486       Q_ASSERT( collectionSelectionModel );
00487 
00488       foreach ( const QModelIndex &index, collectionSelectionModel->selectedRows() ) {
00489         Q_ASSERT( index.isValid() );
00490         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00491         Q_ASSERT( collection.isValid() );
00492 
00493         collections << collection;
00494       }
00495 
00496       return collections;
00497     }
00498 
00499     void slotDeleteCollection()
00500     {
00501       const Collection::List collections = selectedCollections();
00502       if ( collections.isEmpty() )
00503         return;
00504 
00505       const QString collectionName = collections.first().name();
00506       const QString text = contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxText,
00507                                         collections.count(), collectionName );
00508 
00509       if ( KMessageBox::questionYesNo( parentWidget, text,
00510            contextText( StandardActionManager::DeleteCollections, StandardActionManager::MessageBoxTitle, collections.count(), collectionName ),
00511            KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00512            QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00513         return;
00514 
00515       foreach ( const Collection &collection, collections ) {
00516         CollectionDeleteJob *job = new CollectionDeleteJob( collection, q );
00517         q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( collectionDeletionResult( KJob* ) ) );
00518       }
00519     }
00520 
00521     void slotSynchronizeCollection()
00522     {
00523       Q_ASSERT( collectionSelectionModel );
00524       const QModelIndexList list = collectionSelectionModel->selectedRows();
00525       if ( list.isEmpty() )
00526         return;
00527 
00528       const Collection::List collections = selectedCollections();
00529       if ( collections.isEmpty() )
00530         return;
00531 
00532       foreach( Collection collection, collections ) {
00533         AgentManager::self()->synchronizeCollection( collection, false );
00534       }
00535     }
00536 
00537     void slotSynchronizeCollectionRecursive()
00538     {
00539       Q_ASSERT( collectionSelectionModel );
00540       const QModelIndexList list = collectionSelectionModel->selectedRows();
00541       if ( list.isEmpty() )
00542         return;
00543 
00544       const Collection::List collections = selectedCollections();
00545       if ( collections.isEmpty() )
00546         return;
00547 
00548       foreach( Collection collection, collections ) {
00549         AgentManager::self()->synchronizeCollection( collection, true );
00550       }
00551     }
00552 
00553     void slotCollectionProperties()
00554     {
00555       const QModelIndexList list = collectionSelectionModel->selectedRows();
00556       if ( list.isEmpty() )
00557         return;
00558 
00559       const QModelIndex index = list.first();
00560       Q_ASSERT( index.isValid() );
00561 
00562       const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00563       Q_ASSERT( collection.isValid() );
00564 
00565       const QString displayName = collection.hasAttribute<EntityDisplayAttribute>() ? collection.attribute<EntityDisplayAttribute>()->displayName()
00566                                                                                     : collection.name();
00567 
00568       CollectionPropertiesDialog* dlg = new CollectionPropertiesDialog( collection, mCollectionPropertiesPageNames, parentWidget );
00569       dlg->setCaption( contextText( StandardActionManager::CollectionProperties, StandardActionManager::DialogTitle ).arg( displayName ) );
00570       dlg->show();
00571     }
00572 
00573     void slotCopyItems()
00574     {
00575       encodeToClipboard( itemSelectionModel );
00576     }
00577 
00578     void slotCutItems()
00579     {
00580       encodeToClipboard( itemSelectionModel, true );
00581     }
00582 
00583     void slotPaste()
00584     {
00585       Q_ASSERT( collectionSelectionModel );
00586 
00587       const QModelIndexList list = collectionSelectionModel->selectedRows();
00588       if ( list.isEmpty() )
00589         return;
00590 
00591       const QModelIndex index = list.first();
00592       Q_ASSERT( index.isValid() );
00593 
00594 #ifndef QT_NO_CLIPBOARD
00595       // TODO: Copy or move? We can't seem to cut yet
00596       QAbstractItemModel *model = const_cast<QAbstractItemModel *>( collectionSelectionModel->model() );
00597       const QMimeData *mimeData = QApplication::clipboard()->mimeData();
00598       model->dropMimeData( mimeData, isCutAction( mimeData ) ? Qt::MoveAction : Qt::CopyAction, -1, -1, index );
00599       model->setData( QModelIndex(), false, EntityTreeModel::PendingCutRole );
00600       QApplication::clipboard()->clear();
00601 #endif
00602     }
00603 
00604     void slotDeleteItems()
00605     {
00606       Q_ASSERT( itemSelectionModel );
00607 
00608       Item::List items;
00609       foreach ( const QModelIndex &index, itemSelectionModel->selectedRows() ) {
00610         bool ok;
00611         const qlonglong id = index.data( ItemModel::IdRole ).toLongLong( &ok );
00612         Q_ASSERT( ok );
00613         items << Item( id );
00614       }
00615 
00616       if ( items.isEmpty() )
00617         return;
00618 
00619       QMetaObject::invokeMethod(q, "slotDeleteItemsDeferred",
00620                                 Qt::QueuedConnection,
00621                                 Q_ARG(Akonadi::Item::List, items));
00622     }
00623 
00624     void slotDeleteItemsDeferred(const Akonadi::Item::List &items)
00625     {
00626       Q_ASSERT( itemSelectionModel );
00627 
00628       if ( KMessageBox::questionYesNo( parentWidget,
00629            contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxText, items.count(), QString() ),
00630            contextText( StandardActionManager::DeleteItems, StandardActionManager::MessageBoxTitle, items.count(), QString() ),
00631            KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00632            QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00633         return;
00634 
00635       ItemDeleteJob *job = new ItemDeleteJob( items, q );
00636       q->connect( job, SIGNAL( result( KJob* ) ), q, SLOT( itemDeletionResult( KJob* ) ) );
00637     }
00638 
00639     void slotLocalSubscription()
00640     {
00641       SubscriptionDialog* dlg = new SubscriptionDialog( mMimeTypeFilter, parentWidget );
00642       dlg->show();
00643     }
00644 
00645     void slotAddToFavorites()
00646     {
00647       Q_ASSERT( collectionSelectionModel );
00648       Q_ASSERT( favoritesModel );
00649       const QModelIndexList list = collectionSelectionModel->selectedRows();
00650       if ( list.isEmpty() )
00651         return;
00652 
00653       foreach ( const QModelIndex &index, list ) {
00654         Q_ASSERT( index.isValid() );
00655         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00656         Q_ASSERT( collection.isValid() );
00657 
00658         favoritesModel->addCollection( collection );
00659       }
00660 
00661       updateActions();
00662     }
00663 
00664     void slotRemoveFromFavorites()
00665     {
00666       Q_ASSERT( collectionSelectionModel );
00667       Q_ASSERT( favoritesModel );
00668       const QModelIndexList list = collectionSelectionModel->selectedRows();
00669       if ( list.isEmpty() )
00670         return;
00671 
00672       foreach ( const QModelIndex &index, list ) {
00673         Q_ASSERT( index.isValid() );
00674         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00675         Q_ASSERT( collection.isValid() );
00676 
00677         favoritesModel->removeCollection( collection );
00678       }
00679 
00680       updateActions();
00681     }
00682 
00683     void slotRenameFavorite()
00684     {
00685       Q_ASSERT( collectionSelectionModel );
00686       Q_ASSERT( favoritesModel );
00687       const QModelIndexList list = collectionSelectionModel->selectedRows();
00688       if ( list.isEmpty() )
00689         return;
00690 
00691       const QModelIndex index = list.first();
00692       Q_ASSERT( index.isValid() );
00693       const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00694       Q_ASSERT( collection.isValid() );
00695 
00696       bool ok;
00697       const QString label = KInputDialog::getText( contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogTitle ),
00698                                                    contextText( StandardActionManager::RenameFavoriteCollection, StandardActionManager::DialogText ),
00699                                                    favoritesModel->favoriteLabel( collection ), &ok, parentWidget );
00700       if ( !ok )
00701         return;
00702 
00703       favoritesModel->setFavoriteLabel( collection, label );
00704     }
00705 
00706     void slotCopyCollectionTo()
00707     {
00708       pasteTo( collectionSelectionModel, collectionSelectionModel->model(), CopyCollectionToMenu, Qt::CopyAction );
00709     }
00710 
00711     void slotCopyItemTo()
00712     {
00713       pasteTo( itemSelectionModel, collectionSelectionModel->model(), CopyItemToMenu, Qt::CopyAction );
00714     }
00715 
00716     void slotMoveCollectionTo()
00717     {
00718       pasteTo( collectionSelectionModel, collectionSelectionModel->model(), MoveCollectionToMenu, Qt::MoveAction );
00719     }
00720 
00721     void slotMoveItemTo()
00722     {
00723       pasteTo( itemSelectionModel, collectionSelectionModel->model(), MoveItemToMenu, Qt::MoveAction );
00724     }
00725 
00726     void slotCopyCollectionTo( QAction *action )
00727     {
00728       pasteTo( collectionSelectionModel, action, Qt::CopyAction );
00729     }
00730 
00731     void slotCopyItemTo( QAction *action )
00732     {
00733       pasteTo( itemSelectionModel, action, Qt::CopyAction );
00734     }
00735 
00736     void slotMoveCollectionTo( QAction *action )
00737     {
00738       pasteTo( collectionSelectionModel, action, Qt::MoveAction );
00739     }
00740 
00741     void slotMoveItemTo( QAction *action )
00742     {
00743       pasteTo( itemSelectionModel, action, Qt::MoveAction );
00744     }
00745 
00746     AgentInstance::List selectedAgentInstances() const
00747     {
00748       AgentInstance::List instances;
00749 
00750       Q_ASSERT( collectionSelectionModel );
00751       if ( collectionSelectionModel->selection().indexes().isEmpty() )
00752         return instances;
00753 
00754       foreach ( const QModelIndex &index, collectionSelectionModel->selection().indexes() ) {
00755         Q_ASSERT( index.isValid() );
00756         const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00757         Q_ASSERT( collection.isValid() );
00758 
00759         if ( collection.isValid() ) {
00760           const QString identifier = collection.resource();
00761           instances << AgentManager::self()->instance( identifier );
00762         }
00763       }
00764 
00765       return instances;
00766     }
00767 
00768     AgentInstance selectedAgentInstance() const
00769     {
00770       const AgentInstance::List instances = selectedAgentInstances();
00771 
00772       if ( instances.isEmpty() )
00773         return AgentInstance();
00774 
00775       return instances.first();
00776     }
00777 
00778     void slotCreateResource()
00779     {
00780       Akonadi::AgentTypeDialog dlg( parentWidget );
00781       dlg.setCaption( contextText( StandardActionManager::CreateResource, StandardActionManager::DialogTitle ) );
00782 
00783       foreach ( const QString &mimeType, mMimeTypeFilter )
00784         dlg.agentFilterProxyModel()->addMimeTypeFilter( mimeType );
00785 
00786       foreach ( const QString &capability, mCapabilityFilter )
00787         dlg.agentFilterProxyModel()->addCapabilityFilter( capability );
00788 
00789       if ( dlg.exec() ) {
00790         const AgentType agentType = dlg.agentType();
00791 
00792         if ( agentType.isValid() ) {
00793           AgentInstanceCreateJob *job = new AgentInstanceCreateJob( agentType, q );
00794           q->connect( job, SIGNAL( result( KJob* ) ), SLOT( resourceCreationResult( KJob* ) ) );
00795           job->configure( parentWidget );
00796           job->start();
00797         }
00798       }
00799     }
00800 
00801     void slotDeleteResource()
00802     {
00803       const AgentInstance::List instances = selectedAgentInstances();
00804       if ( instances.isEmpty() )
00805         return;
00806 
00807       if ( KMessageBox::questionYesNo( parentWidget,
00808            contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxText, instances.count(), instances.first().name() ),
00809            contextText( StandardActionManager::DeleteResources, StandardActionManager::MessageBoxTitle, instances.count(), instances.first().name() ),
00810            KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00811            QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00812         return;
00813 
00814       foreach ( const AgentInstance &instance, instances )
00815         AgentManager::self()->removeInstance( instance );
00816     }
00817 
00818     void slotSynchronizeResource()
00819     {
00820       const AgentInstance::List instances = selectedAgentInstances();
00821       if ( instances.isEmpty() )
00822         return;
00823 
00824       foreach ( AgentInstance instance, instances )
00825         instance.synchronize();
00826     }
00827 
00828     void slotResourceProperties()
00829     {
00830       AgentInstance instance = selectedAgentInstance();
00831       if ( !instance.isValid() )
00832         return;
00833 
00834       instance.configure( parentWidget );
00835     }
00836 
00837     void slotToggleWorkOffline( bool offline )
00838     {
00839       setWorkOffline( offline );
00840 
00841       AgentInstance::List instances = AgentManager::self()->instances();
00842       foreach ( AgentInstance instance, instances ) {
00843         instance.setIsOnline( !offline );
00844       }
00845     }
00846 
00847     void pasteTo( QItemSelectionModel *selectionModel, const QAbstractItemModel *model, StandardActionManager::Type type, Qt::DropAction dropAction )
00848     {
00849       const QSet<QString> mimeTypes = mimeTypesOfSelection( type );
00850 
00851       CollectionDialog dlg( const_cast<QAbstractItemModel*>( model ) );
00852       dlg.setMimeTypeFilter( mimeTypes.toList() );
00853 
00854       if ( type == CopyItemToMenu || type == MoveItemToMenu )
00855         dlg.setAccessRightsFilter( Collection::CanCreateItem );
00856       else if ( type == CopyCollectionToMenu || type == MoveCollectionToMenu )
00857         dlg.setAccessRightsFilter( Collection::CanCreateCollection );
00858 
00859       if ( dlg.exec() ) {
00860         const QModelIndex index = EntityTreeModel::modelIndexForCollection( collectionSelectionModel->model(), dlg.selectedCollection() );
00861         if ( !index.isValid() )
00862           return;
00863 
00864         const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00865 
00866         QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() );
00867         model->dropMimeData( mimeData, dropAction, -1, -1, index );
00868       }
00869     }
00870 
00871     void pasteTo( QItemSelectionModel *selectionModel, QAction *action, Qt::DropAction dropAction )
00872     {
00873       Q_ASSERT( selectionModel );
00874       Q_ASSERT( action );
00875 
00876       if ( selectionModel->selectedRows().count() <= 0 )
00877         return;
00878 
00879       const QMimeData *mimeData = selectionModel->model()->mimeData( selectionModel->selectedRows() );
00880 
00881       const QModelIndex index = action->data().value<QModelIndex>();
00882 
00883       Q_ASSERT( index.isValid() );
00884 
00885       QAbstractItemModel *model = const_cast<QAbstractItemModel *>( index.model() );
00886       model->dropMimeData( mimeData, dropAction, -1, -1, index );
00887     }
00888 
00889     void collectionCreationResult( KJob *job )
00890     {
00891       if ( job->error() ) {
00892         KMessageBox::error( parentWidget,
00893                             contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00894                             contextText( StandardActionManager::CreateCollection, StandardActionManager::ErrorMessageTitle ) );
00895       }
00896     }
00897 
00898     void collectionDeletionResult( KJob *job )
00899     {
00900       if ( job->error() ) {
00901         KMessageBox::error( parentWidget,
00902                             contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00903                             contextText( StandardActionManager::DeleteCollections, StandardActionManager::ErrorMessageTitle ) );
00904       }
00905     }
00906 
00907     void itemDeletionResult( KJob *job )
00908     {
00909       if ( job->error() ) {
00910         KMessageBox::error( parentWidget,
00911                             contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00912                             contextText( StandardActionManager::DeleteItems, StandardActionManager::ErrorMessageTitle ) );
00913       }
00914     }
00915 
00916     void resourceCreationResult( KJob *job )
00917     {
00918       if ( job->error() ) {
00919         KMessageBox::error( parentWidget,
00920                             contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00921                             contextText( StandardActionManager::CreateResource, StandardActionManager::ErrorMessageTitle ) );
00922       }
00923     }
00924 
00925     void pasteResult( KJob *job )
00926     {
00927       if ( job->error() ) {
00928         KMessageBox::error( parentWidget,
00929                             contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageText ).arg( job->errorString() ),
00930                             contextText( StandardActionManager::Paste, StandardActionManager::ErrorMessageTitle ) );
00931       }
00932     }
00933 
00937     QSet<QString> mimeTypesOfSelection( StandardActionManager::Type type ) const
00938     {
00939       QModelIndexList list;
00940       QSet<QString> mimeTypes;
00941 
00942       const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu );
00943       const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu );
00944 
00945       if ( isItemAction ) {
00946         list = itemSelectionModel->selectedRows();
00947         foreach ( const QModelIndex &index, list )
00948           mimeTypes << index.data( EntityTreeModel::MimeTypeRole ).toString();
00949       }
00950 
00951       if ( isCollectionAction ) {
00952         list = collectionSelectionModel->selectedRows();
00953         foreach ( const QModelIndex &index, list ) {
00954           const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00955 
00956           // The mimetypes that the selected collection can possibly contain
00957           mimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet();
00958         }
00959       }
00960 
00961       return mimeTypes;
00962     }
00963 
00967     bool isWritableTargetCollectionForMimeTypes( const Collection &collection, const QSet<QString> &mimeTypes, StandardActionManager::Type type ) const
00968     {
00969       if ( CollectionUtils::isVirtual( collection ) )
00970         return false;
00971 
00972       const bool isItemAction = ( type == CopyItemToMenu || type == MoveItemToMenu );
00973       const bool isCollectionAction = ( type == CopyCollectionToMenu || type == MoveCollectionToMenu );
00974 
00975       const bool canContainRequiredMimeTypes = !collection.contentMimeTypes().toSet().intersect( mimeTypes ).isEmpty();
00976       const bool canCreateNewItems = (collection.rights() & Collection::CanCreateItem);
00977 
00978       const bool canCreateNewCollections = (collection.rights() & Collection::CanCreateCollection);
00979       const bool canContainCollections = collection.contentMimeTypes().contains( Collection::mimeType() );
00980       const bool resourceAllowsRequiredMimeTypes = AgentManager::self()->instance( collection.resource() ).type().mimeTypes().toSet().contains( mimeTypes );
00981 
00982       const bool isReadOnlyForItems = (isItemAction && (!canCreateNewItems || !canContainRequiredMimeTypes));
00983       const bool isReadOnlyForCollections = (isCollectionAction && (!canCreateNewCollections || !canContainCollections || !resourceAllowsRequiredMimeTypes));
00984 
00985       return !(CollectionUtils::isStructural( collection ) || isReadOnlyForItems || isReadOnlyForCollections);
00986     }
00987 
00988     void fillFoldersMenu( StandardActionManager::Type type, QMenu *menu,
00989                           const QAbstractItemModel *model, QModelIndex parentIndex )
00990     {
00991       const int rowCount = model->rowCount( parentIndex );
00992 
00993       const QSet<QString> mimeTypes = mimeTypesOfSelection( type );
00994 
00995       for ( int row = 0; row < rowCount; ++row ) {
00996         const QModelIndex index = model->index( row, 0, parentIndex );
00997         const Collection collection = model->data( index, CollectionModel::CollectionRole ).value<Collection>();
00998 
00999         if ( CollectionUtils::isVirtual( collection ) )
01000           continue;
01001 
01002         const bool readOnly = !isWritableTargetCollectionForMimeTypes( collection, mimeTypes, type );
01003 
01004         QString label = model->data( index ).toString();
01005         label.replace( QLatin1String( "&" ), QLatin1String( "&&" ) );
01006 
01007         const QIcon icon = model->data( index, Qt::DecorationRole ).value<QIcon>();
01008 
01009         if ( model->rowCount( index ) > 0 ) {
01010           // new level
01011           QMenu* popup = new QMenu( menu );
01012           const bool moveAction = (type == MoveCollectionToMenu || type == MoveItemToMenu);
01013           popup->setObjectName( QString::fromUtf8( "subMenu" ) );
01014           popup->setTitle( label );
01015           popup->setIcon( icon );
01016 
01017           fillFoldersMenu( type, popup, model, index );
01018 
01019           if ( !readOnly ) {
01020             popup->addSeparator();
01021 
01022             QAction *action = popup->addAction( moveAction ? i18n( "Move to This Folder" ) : i18n( "Copy to This Folder" ) );
01023             action->setData( QVariant::fromValue<QModelIndex>( index ) );
01024           }
01025 
01026           menu->addMenu( popup );
01027 
01028         } else {
01029           // insert an item
01030           QAction* action = menu->addAction( icon, label );
01031           action->setData( QVariant::fromValue<QModelIndex>( index ) );
01032           action->setEnabled( !readOnly );
01033         }
01034       }
01035     }
01036 
01037     void checkModelsConsistency()
01038     {
01039       if ( favoritesModel == 0 || favoriteSelectionModel == 0 ) {
01040         // No need to check when the favorite collections feature is not used
01041         return;
01042       }
01043 
01044       // find the base ETM of the favourites view
01045       const QAbstractItemModel *favModel = favoritesModel;
01046       while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( favModel ) ) {
01047         favModel = proxy->sourceModel();
01048       }
01049 
01050       // Check that the collection selection model maps to the same
01051       // EntityTreeModel than favoritesModel
01052       if ( collectionSelectionModel != 0 ) {
01053         const QAbstractItemModel *model = collectionSelectionModel->model();
01054         while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) {
01055           model = proxy->sourceModel();
01056         }
01057 
01058         Q_ASSERT( model == favModel );
01059       }
01060 
01061       // Check that the favorite selection model maps to favoritesModel
01062       const QAbstractItemModel *model = favoriteSelectionModel->model();
01063       while ( const QAbstractProxyModel *proxy = qobject_cast<const QAbstractProxyModel*>( model ) ) {
01064         model = proxy->sourceModel();
01065       }
01066       Q_ASSERT( model == favModel );
01067     }
01068 
01069     void markCutAction( QMimeData *mimeData, bool cut ) const
01070     {
01071       if ( !cut )
01072         return;
01073 
01074       const QByteArray cutSelectionData = "1"; //krazy:exclude=doublequote_chars
01075       mimeData->setData( QLatin1String( "application/x-kde.akonadi-cutselection" ), cutSelectionData);
01076     }
01077 
01078     bool isCutAction( const QMimeData *mimeData ) const
01079     {
01080       const QByteArray data = mimeData->data( QLatin1String( "application/x-kde.akonadi-cutselection" ) );
01081       if ( data.isEmpty() )
01082         return false;
01083       else
01084         return (data.at( 0 ) == '1'); // true if 1
01085     }
01086 
01087     void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const QString &data )
01088     {
01089       ContextTextEntry entry;
01090       entry.text = data;
01091 
01092       contextTexts[ type ].insert( context, entry );
01093     }
01094 
01095     void setContextText( StandardActionManager::Type type, StandardActionManager::TextContext context, const KLocalizedString &data )
01096     {
01097       ContextTextEntry entry;
01098       entry.localizedText = data;
01099 
01100       contextTexts[ type ].insert( context, entry );
01101     }
01102 
01103     QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context ) const
01104     {
01105       return contextTexts[ type ].value( context ).text;
01106     }
01107 
01108     QString contextText( StandardActionManager::Type type, StandardActionManager::TextContext context, int count, const QString &value ) const
01109     {
01110       if ( contextTexts[ type ].value( context ).localizedText.isEmpty() )
01111         return contextTexts[ type ].value( context ).text;
01112 
01113       KLocalizedString text = contextTexts[ type ].value( context ).localizedText;
01114       const QString str = text.subs( count ).toString();
01115       const int argCount = str.count( QRegExp( QLatin1String( "%[0-9]" ) ) );
01116       if ( argCount > 0 ) {
01117         return text.subs( count ).subs( value ).toString();
01118       } else {
01119         return text.subs( count ).toString();
01120       }
01121     }
01122 
01123     StandardActionManager *q;
01124     KActionCollection *actionCollection;
01125     QWidget *parentWidget;
01126     QItemSelectionModel *collectionSelectionModel;
01127     QItemSelectionModel *itemSelectionModel;
01128     FavoriteCollectionsModel *favoritesModel;
01129     QItemSelectionModel *favoriteSelectionModel;
01130     QVector<KAction*> actions;
01131     QHash<StandardActionManager::Type, KLocalizedString> pluralLabels;
01132     QHash<StandardActionManager::Type, KLocalizedString> pluralIconLabels;
01133 
01134     struct ContextTextEntry
01135     {
01136       QString text;
01137       KLocalizedString localizedText;
01138       bool isLocalized;
01139     };
01140 
01141     typedef QHash<StandardActionManager::TextContext, ContextTextEntry> ContextTexts;
01142     QHash<StandardActionManager::Type, ContextTexts> contextTexts;
01143 
01144     ActionStateManager mActionStateManager;
01145 
01146     QStringList mMimeTypeFilter;
01147     QStringList mCapabilityFilter;
01148     QStringList mCollectionPropertiesPageNames;
01149 };
01150 
01151 //@endcond
01152 
01153 StandardActionManager::StandardActionManager( KActionCollection * actionCollection,
01154                                               QWidget * parent) :
01155     QObject( parent ),
01156     d( new Private( this ) )
01157 {
01158   d->parentWidget = parent;
01159   d->actionCollection = actionCollection;
01160   d->mActionStateManager.setReceiver( this );
01161 #ifndef QT_NO_CLIPBOARD
01162   connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ), SLOT( clipboardChanged( QClipboard::Mode ) ) );
01163 #endif
01164 }
01165 
01166 StandardActionManager::~ StandardActionManager()
01167 {
01168   delete d;
01169 }
01170 
01171 void StandardActionManager::setCollectionSelectionModel( QItemSelectionModel * selectionModel )
01172 {
01173   d->collectionSelectionModel = selectionModel;
01174   connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
01175            SLOT( collectionSelectionChanged() ) );
01176 
01177   d->checkModelsConsistency();
01178 }
01179 
01180 void StandardActionManager::setItemSelectionModel( QItemSelectionModel * selectionModel )
01181 {
01182   d->itemSelectionModel = selectionModel;
01183   connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
01184            SLOT( updateActions() ) );
01185 }
01186 
01187 void StandardActionManager::setFavoriteCollectionsModel( FavoriteCollectionsModel *favoritesModel )
01188 {
01189   d->favoritesModel = favoritesModel;
01190   d->checkModelsConsistency();
01191 }
01192 
01193 void StandardActionManager::setFavoriteSelectionModel( QItemSelectionModel *selectionModel )
01194 {
01195   d->favoriteSelectionModel = selectionModel;
01196   connect( selectionModel, SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
01197            SLOT( favoriteSelectionChanged() ) );
01198   d->checkModelsConsistency();
01199 }
01200 
01201 KAction* StandardActionManager::createAction( Type type )
01202 {
01203   Q_ASSERT( type < LastType );
01204   Q_ASSERT( standardActionData[type].name );
01205   if ( d->actions[type] )
01206     return d->actions[type];
01207   KAction *action = 0;
01208   switch ( standardActionData[type].actionType ) {
01209     case NormalAction:
01210       action = new KAction( d->parentWidget );
01211       break;
01212     case MenuAction:
01213       action = new KActionMenu( d->parentWidget );
01214       break;
01215     case ToggleAction:
01216       action = new KToggleAction( d->parentWidget );
01217       break;
01218   }
01219 
01220   if ( d->pluralLabels.contains( type ) && !d->pluralLabels.value( type ).isEmpty() )
01221     action->setText( d->pluralLabels.value( type ).subs( 1 ).toString() );
01222   else if ( standardActionData[type].label )
01223     action->setText( i18n( standardActionData[type].label ) );
01224 
01225   if ( d->pluralIconLabels.contains( type ) && !d->pluralIconLabels.value( type ).isEmpty() )
01226     action->setIconText( d->pluralIconLabels.value( type ).subs( 1 ).toString() );
01227   else if ( standardActionData[type].iconLabel )
01228     action->setIconText( i18n( standardActionData[type].iconLabel ) );
01229 
01230   if ( standardActionData[type].icon )
01231     action->setIcon( KIcon( QString::fromLatin1( standardActionData[type].icon ) ) );
01232 
01233   action->setShortcut( standardActionData[type].shortcut );
01234 
01235   if ( standardActionData[type].slot ) {
01236     switch ( standardActionData[type].actionType ) {
01237       case NormalAction:
01238         connect( action, SIGNAL( triggered() ), standardActionData[type].slot );
01239         break;
01240       case MenuAction:
01241         {
01242           KActionMenu *actionMenu = qobject_cast<KActionMenu*>( action );
01243           connect( actionMenu->menu(), SIGNAL( triggered( QAction* ) ), standardActionData[type].slot );
01244         }
01245         break;
01246       case ToggleAction:
01247         {
01248           connect( action, SIGNAL( triggered( bool ) ), standardActionData[type].slot );
01249         }
01250         break;
01251     }
01252   }
01253 
01254   if ( type == ToggleWorkOffline ) {
01255     // inititalize the action state with information from config file
01256     disconnect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot );
01257     action->setChecked( workOffline() );
01258     connect( action, SIGNAL( triggered( bool ) ), this, standardActionData[type].slot );
01259 
01260     //TODO: find a way to check for updates to the config file
01261   }
01262 
01263   d->actionCollection->addAction( QString::fromLatin1(standardActionData[type].name), action );
01264   d->actions[type] = action;
01265   d->updateActions();
01266   return action;
01267 }
01268 
01269 void StandardActionManager::createAllActions()
01270 {
01271   for ( uint i = 0; i < LastType; ++i )
01272     createAction( (Type)i );
01273 }
01274 
01275 KAction * StandardActionManager::action( Type type ) const
01276 {
01277   Q_ASSERT( type < LastType );
01278   return d->actions[type];
01279 }
01280 
01281 void StandardActionManager::setActionText( Type type, const KLocalizedString & text )
01282 {
01283   Q_ASSERT( type < LastType );
01284   d->pluralLabels.insert( type, text );
01285   d->updateActions();
01286 }
01287 
01288 void StandardActionManager::interceptAction( Type type, bool intercept )
01289 {
01290   Q_ASSERT( type < LastType );
01291 
01292   const KAction *action = d->actions[type];
01293 
01294   if ( !action )
01295     return;
01296 
01297   if ( intercept )
01298     disconnect( action, SIGNAL( triggered() ), this, standardActionData[type].slot );
01299   else
01300     connect( action, SIGNAL( triggered() ), standardActionData[type].slot );
01301 }
01302 
01303 Akonadi::Collection::List StandardActionManager::selectedCollections() const
01304 {
01305   Collection::List collections;
01306 
01307   if ( !d->collectionSelectionModel )
01308     return collections;
01309 
01310   foreach ( const QModelIndex &index, d->collectionSelectionModel->selectedRows() ) {
01311     const Collection collection = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
01312     if ( collection.isValid() )
01313       collections << collection;
01314   }
01315 
01316   return collections;
01317 }
01318 
01319 Item::List StandardActionManager::selectedItems() const
01320 {
01321   Item::List items;
01322 
01323   if ( !d->itemSelectionModel )
01324     return items;
01325 
01326   foreach ( const QModelIndex &index, d->itemSelectionModel->selectedRows() ) {
01327     const Item item = index.data( EntityTreeModel::ItemRole ).value<Item>();
01328     if ( item.isValid() )
01329       items << item;
01330   }
01331 
01332   return items;
01333 }
01334 
01335 void StandardActionManager::setContextText( Type type, TextContext context, const QString &text )
01336 {
01337   d->setContextText( type, context, text );
01338 }
01339 
01340 void StandardActionManager::setContextText( Type type, TextContext context, const KLocalizedString &text )
01341 {
01342   d->setContextText( type, context, text );
01343 }
01344 
01345 void StandardActionManager::setMimeTypeFilter( const QStringList &mimeTypes )
01346 {
01347   d->mMimeTypeFilter = mimeTypes;
01348 }
01349 
01350 void StandardActionManager::setCapabilityFilter( const QStringList &capabilities )
01351 {
01352   d->mCapabilityFilter = capabilities;
01353 }
01354 
01355 void StandardActionManager::setCollectionPropertiesPageNames( const QStringList &names )
01356 {
01357   d->mCollectionPropertiesPageNames = names;
01358 }
01359 
01360 #include "standardactionmanager.moc"

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • 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.5
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