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