00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "standardactionmanager.h"
00021
00022 #include "agentmanager.h"
00023 #include "collectioncreatejob.h"
00024 #include "collectiondeletejob.h"
00025 #include "collectionmodel.h"
00026 #include "collectionutils_p.h"
00027 #include "collectionpropertiesdialog.h"
00028 #include "itemdeletejob.h"
00029 #include "itemmodel.h"
00030 #include "pastehelper.h"
00031 #include "subscriptiondialog.h"
00032
00033 #include <KAction>
00034 #include <KActionCollection>
00035 #include <KDebug>
00036 #include <KInputDialog>
00037 #include <KLocale>
00038 #include <KMessageBox>
00039
00040 #include <QApplication>
00041 #include <QClipboard>
00042 #include <QItemSelectionModel>
00043 #include <QMimeData>
00044
00045 #include <boost/static_assert.hpp>
00046
00047 using namespace Akonadi;
00048
00049 static const struct {
00050 const char *name;
00051 const char *label;
00052 const char *icon;
00053 int shortcut;
00054 const char* slot;
00055 } actionData[] = {
00056 { "akonadi_collection_create", I18N_NOOP("&New Folder..."), "folder-new", 0, SLOT(slotCreateCollection()) },
00057 { "akonadi_collection_copy", 0, "edit-copy", 0, SLOT(slotCopyCollections()) },
00058 { "akonadi_collection_delete", I18N_NOOP("&Delete Folder"), "edit-delete", 0, SLOT(slotDeleteCollection()) },
00059 { "akonadi_collection_sync", I18N_NOOP("&Synchronize Folder"), "view-refresh", Qt::Key_F5, SLOT(slotSynchronizeCollection()) },
00060 { "akonadi_collection_properties", I18N_NOOP("Folder &Properties..."), "configure", 0, SLOT(slotCollectionProperties()) },
00061 { "akonadi_item_copy", 0, "edit-copy", 0, SLOT(slotCopyItems()) },
00062 { "akonadi_paste", I18N_NOOP("&Paste"), "edit-paste", Qt::CTRL + Qt::Key_V, SLOT(slotPaste()) },
00063 { "akonadi_item_delete", 0, "edit-delete", Qt::Key_Delete, SLOT(slotDeleteItems()) },
00064 { "akonadi_manage_local_subscriptions", I18N_NOOP("Manage Local &Subscriptions..."), 0, 0, SLOT(slotLocalSubscription()) }
00065 };
00066 static const int numActionData = sizeof actionData / sizeof *actionData;
00067
00068 BOOST_STATIC_ASSERT( numActionData == StandardActionManager::LastType );
00069
00070 static bool canCreateCollection( const Collection &collection )
00071 {
00072 if ( !( collection.rights() & Collection::CanCreateCollection ) )
00073 return false;
00074
00075 if ( !collection.contentMimeTypes().contains( Collection::mimeType() ) )
00076 return false;
00077
00078 return true;
00079 }
00080
00084 class StandardActionManager::Private
00085 {
00086 public:
00087 Private( StandardActionManager *parent ) :
00088 q( parent ),
00089 collectionSelectionModel( 0 ),
00090 itemSelectionModel( 0 )
00091 {
00092 actions.fill( 0, StandardActionManager::LastType );
00093
00094 pluralLabels.insert( StandardActionManager::CopyCollections, ki18np( "&Copy Folder", "&Copy %1 Folders" ) );
00095 pluralLabels.insert( StandardActionManager::CopyItems, ki18np( "&Copy Item", "&Copy %1 Items" ) );
00096 pluralLabels.insert( StandardActionManager::DeleteItems, ki18np( "&Delete Item", "&Delete %1 Items" ) );
00097 }
00098
00099 void enableAction( StandardActionManager::Type type, bool enable )
00100 {
00101 Q_ASSERT( type >= 0 && type < StandardActionManager::LastType );
00102 if ( actions[type] )
00103 actions[type]->setEnabled( enable );
00104 }
00105
00106 void updatePluralLabel( StandardActionManager::Type type, int count )
00107 {
00108 Q_ASSERT( type >= 0 && type < StandardActionManager::LastType );
00109 if ( actions[type] && pluralLabels.contains( type ) && !pluralLabels.value( type ).isEmpty() ) {
00110 actions[type]->setText( pluralLabels.value( type ).subs( qMax( count, 1 ) ).toString() );
00111 }
00112 }
00113
00114 void copy( QItemSelectionModel* selModel )
00115 {
00116 Q_ASSERT( selModel );
00117 if ( selModel->selectedRows().count() <= 0 )
00118 return;
00119 QMimeData *mimeData = selModel->model()->mimeData( selModel->selectedRows() );
00120 QApplication::clipboard()->setMimeData( mimeData );
00121 }
00122
00123 void updateActions()
00124 {
00125 bool singleColSelected = false;
00126 bool multiColSelected = false;
00127 int colCount = 0;
00128 QModelIndex selectedIndex;
00129 if ( collectionSelectionModel ) {
00130 colCount = collectionSelectionModel->selectedRows().count();
00131 singleColSelected = colCount == 1;
00132 multiColSelected = colCount > 0;
00133 if ( singleColSelected )
00134 selectedIndex = collectionSelectionModel->selectedRows().first();
00135 }
00136
00137 enableAction( CopyCollections, multiColSelected );
00138 enableAction( CollectionProperties, singleColSelected );
00139
00140 if ( singleColSelected && selectedIndex.isValid() ) {
00141 const Collection col = selectedIndex.data( CollectionModel::CollectionRole ).value<Collection>();
00142 enableAction( CreateCollection, canCreateCollection( col ) );
00143 enableAction( DeleteCollections, col.rights() & Collection::CanDeleteCollection );
00144 enableAction( SynchronizeCollections, CollectionUtils::isResource( col ) || CollectionUtils::isFolder( col ) );
00145 enableAction( Paste, PasteHelper::canPaste( QApplication::clipboard()->mimeData(), col ) );
00146 } else {
00147 enableAction( CreateCollection, false );
00148 enableAction( DeleteCollections, false );
00149 enableAction( SynchronizeCollections, false );
00150 enableAction( Paste, false );
00151 }
00152
00153 bool multiItemSelected = false;
00154 int itemCount = 0;
00155 if ( itemSelectionModel ) {
00156 itemCount = itemSelectionModel->selectedRows().count();
00157 multiItemSelected = itemCount > 0;
00158 }
00159
00160 enableAction( CopyItems, multiItemSelected );
00161 enableAction( DeleteItems, multiItemSelected );
00162
00163 updatePluralLabel( CopyCollections, colCount );
00164 updatePluralLabel( CopyItems, itemCount );
00165 updatePluralLabel( DeleteItems, itemCount );
00166
00167 emit q->actionStateUpdated();
00168 }
00169
00170 void clipboardChanged( QClipboard::Mode mode )
00171 {
00172 if ( mode == QClipboard::Clipboard )
00173 updateActions();
00174 }
00175
00176 void slotCreateCollection()
00177 {
00178 const QModelIndex index = collectionSelectionModel->currentIndex();
00179 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00180
00181 if ( !canCreateCollection( collection ) )
00182 return;
00183
00184 const QString name = KInputDialog::getText( i18nc( "@title:window", "New Folder"),
00185 i18nc( "@label:textbox, name of a thing", "Name"),
00186 QString(), 0, parentWidget );
00187 if ( name.isEmpty() )
00188 return;
00189 Collection::Id parentId = index.data( CollectionModel::CollectionIdRole ).toLongLong();
00190 if ( parentId <= 0 )
00191 return;
00192
00193 Collection col;
00194 col.setName( name );
00195 col.setParent( parentId );
00196 CollectionCreateJob *job = new CollectionCreateJob( col );
00197 q->connect( job, SIGNAL(result(KJob*)), q, SLOT(collectionCreationResult(KJob*)) );
00198 }
00199
00200 void slotCopyCollections()
00201 {
00202 copy( collectionSelectionModel );
00203 }
00204
00205 void slotDeleteCollection()
00206 {
00207 Q_ASSERT( collectionSelectionModel );
00208 const QModelIndex index = collectionSelectionModel->currentIndex();
00209 if ( !index.isValid() )
00210 return;
00211
00212 const Collection collection = index.data( CollectionModel::CollectionRole ).value<Collection>();
00213 QString text = i18n( "Do you really want to delete folder '%1' and all its sub-folders?", index.data().toString() );
00214 if ( CollectionUtils::isVirtual( collection ) )
00215 text = i18n( "Do you really want to delete the search view '%1'?", index.data().toString() );
00216
00217 if ( KMessageBox::questionYesNo( parentWidget, text,
00218 i18n("Delete folder?"), KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00219 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00220 return;
00221 const Collection::Id colId = index.data( CollectionModel::CollectionIdRole ).toLongLong();
00222 if ( colId <= 0 )
00223 return;
00224
00225 CollectionDeleteJob *job = new CollectionDeleteJob( Collection( colId ), q );
00226 q->connect( job, SIGNAL(result(KJob*)), q, SLOT(collectionDeletionResult(KJob*)) );
00227 }
00228
00229 void slotSynchronizeCollection()
00230 {
00231 QModelIndex index = collectionSelectionModel->currentIndex();
00232 if ( !index.isValid() )
00233 return;
00234 const Collection col = index.data( CollectionModel::CollectionRole ).value<Collection>();
00235 AgentManager::self()->synchronizeCollection( col );
00236 }
00237
00238 void slotCollectionProperties()
00239 {
00240 const QModelIndex index = collectionSelectionModel->currentIndex();
00241 if ( !index.isValid() )
00242 return;
00243 const Collection col = index.data( CollectionModel::CollectionRole ).value<Collection>();
00244 CollectionPropertiesDialog* dlg = new CollectionPropertiesDialog( col, parentWidget );
00245 dlg->show();
00246 }
00247
00248 void slotCopyItems()
00249 {
00250 copy( itemSelectionModel );
00251 }
00252
00253 void slotPaste()
00254 {
00255 const QModelIndex index = collectionSelectionModel->currentIndex();
00256 if ( !index.isValid() )
00257 return;
00258 const Collection col = index.data( CollectionModel::CollectionRole ).value<Collection>();
00259 KJob *job = PasteHelper::paste( QApplication::clipboard()->mimeData(), col );
00260 q->connect( job, SIGNAL(result(KJob*)), q, SLOT(pasteResult(KJob*)) );
00261 }
00262
00263 void slotDeleteItems()
00264 {
00265 if ( KMessageBox::questionYesNo( parentWidget,
00266 i18n( "Do you really want to delete all selected items?" ),
00267 i18n("Delete?"), KStandardGuiItem::del(), KStandardGuiItem::cancel(),
00268 QString(), KMessageBox::Dangerous ) != KMessageBox::Yes )
00269 return;
00270
00271 Q_ASSERT( itemSelectionModel );
00272
00273
00274 foreach ( const QModelIndex &index, itemSelectionModel->selectedRows() ) {
00275 new ItemDeleteJob( Item( index.data( ItemModel::IdRole ).toLongLong() ), q );
00276 }
00277 }
00278
00279 void slotLocalSubscription()
00280 {
00281 SubscriptionDialog* dlg = new SubscriptionDialog( parentWidget );
00282 dlg->show();
00283 }
00284
00285 void collectionCreationResult( KJob *job )
00286 {
00287 if ( job->error() ) {
00288 KMessageBox::error( parentWidget, i18n("Could not create folder: %1", job->errorString()),
00289 i18n("Folder creation failed") );
00290 }
00291 }
00292
00293 void collectionDeletionResult( KJob *job )
00294 {
00295 if ( job->error() ) {
00296 KMessageBox::error( parentWidget, i18n("Could not delete folder: %1", job->errorString()),
00297 i18n("Folder deletion failed") );
00298 }
00299 }
00300
00301 void pasteResult( KJob *job )
00302 {
00303 if ( job->error() ) {
00304 KMessageBox::error( parentWidget, i18n("Could not paste data: %1", job->errorString()),
00305 i18n("Paste failed") );
00306 }
00307 }
00308
00309 StandardActionManager *q;
00310 KActionCollection *actionCollection;
00311 QWidget *parentWidget;
00312 QItemSelectionModel *collectionSelectionModel;
00313 QItemSelectionModel *itemSelectionModel;
00314 QVector<KAction*> actions;
00315 AgentManager *agentManager;
00316 QHash<StandardActionManager::Type, KLocalizedString> pluralLabels;
00317 };
00318
00319 StandardActionManager::StandardActionManager( KActionCollection * actionCollection,
00320 QWidget * parent) :
00321 QObject( parent ),
00322 d( new Private( this ) )
00323 {
00324 d->parentWidget = parent;
00325 d->actionCollection = actionCollection;
00326 connect( QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)), SLOT(clipboardChanged(QClipboard::Mode)) );
00327 }
00328
00329 StandardActionManager::~ StandardActionManager()
00330 {
00331 delete d;
00332 }
00333
00334 void StandardActionManager::setCollectionSelectionModel(QItemSelectionModel * selectionModel)
00335 {
00336 d->collectionSelectionModel = selectionModel;
00337 connect( selectionModel, SIGNAL(selectionChanged( const QItemSelection&, const QItemSelection& )),
00338 SLOT(updateActions()) );
00339 }
00340
00341 void StandardActionManager::setItemSelectionModel(QItemSelectionModel * selectionModel)
00342 {
00343 d->itemSelectionModel = selectionModel;
00344 connect( selectionModel, SIGNAL(selectionChanged( const QItemSelection&, const QItemSelection& )),
00345 SLOT(updateActions()) );
00346 }
00347
00348 KAction* StandardActionManager::createAction( Type type )
00349 {
00350 Q_ASSERT( type >= 0 && type < LastType );
00351 Q_ASSERT( actionData[type].name );
00352 if ( d->actions[type] )
00353 return d->actions[type];
00354 KAction *action = new KAction( d->parentWidget );
00355 if ( d->pluralLabels.contains( type ) && !d->pluralLabels.value( type ).isEmpty() )
00356 action->setText( d->pluralLabels.value( type ).subs( 1 ).toString() );
00357 else if ( actionData[type].label )
00358 action->setText( i18n( actionData[type].label ) );
00359 if ( actionData[type].icon )
00360 action->setIcon( KIcon( QString::fromLatin1( actionData[type].icon ) ) );
00361 action->setShortcut( actionData[type].shortcut );
00362 if ( actionData[type].slot )
00363 connect( action, SIGNAL(triggered()), actionData[type].slot );
00364 d->actionCollection->addAction( QString::fromLatin1(actionData[type].name), action );
00365 d->actions[type] = action;
00366 d->updateActions();
00367 return action;
00368 }
00369
00370 void StandardActionManager::createAllActions()
00371 {
00372 for ( int i = 0; i < LastType; ++i )
00373 createAction( (Type)i );
00374 }
00375
00376 KAction * StandardActionManager::action( Type type ) const
00377 {
00378 Q_ASSERT( type >= 0 && type < LastType );
00379 return d->actions[type];
00380 }
00381
00382 void StandardActionManager::setActionText(Type type, const KLocalizedString & text)
00383 {
00384 Q_ASSERT( type >= 0 && type < LastType );
00385 d->pluralLabels.insert( type, text );
00386 }
00387
00388 #include "standardactionmanager.moc"