akonadi
dragdropmanager.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "dragdropmanager_p.h"
00021
00022 #include <QtGui/QApplication>
00023 #include <QtGui/QDropEvent>
00024 #include <QtGui/QMenu>
00025
00026 #include <KDE/KIcon>
00027 #include <KDE/KLocale>
00028 #include <KDE/KUrl>
00029
00030 #include "akonadi/collection.h"
00031 #include "akonadi/entitytreemodel.h"
00032
00033 using namespace Akonadi;
00034
00035 DragDropManager::DragDropManager( QAbstractItemView *view )
00036 : m_view( view )
00037 {
00038 }
00039
00040 Collection DragDropManager::currentDropTarget( QDropEvent *event ) const
00041 {
00042 const QModelIndex index = m_view->indexAt( event->pos() );
00043
00044 Collection collection = m_view->model()->data( index, EntityTreeModel::CollectionRole ).value<Collection>();
00045 if ( !collection.isValid() ) {
00046 const Item item = m_view->model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
00047 if ( item.isValid() )
00048 collection = m_view->model()->data( index.parent(), EntityTreeModel::CollectionRole ).value<Collection>();
00049 }
00050
00051 return collection;
00052 }
00053
00054 bool DragDropManager::dropAllowed( QDragMoveEvent *event ) const
00055 {
00056
00057 const Collection targetCollection = currentDropTarget( event );
00058 if ( targetCollection.isValid() ) {
00059 const QStringList supportedContentTypes = targetCollection.contentMimeTypes();
00060
00061 const QMimeData *data = event->mimeData();
00062 const KUrl::List urls = KUrl::List::fromMimeData( data );
00063 foreach ( const KUrl &url, urls ) {
00064 const Collection collection = Collection::fromUrl( url );
00065 if ( collection.isValid() ) {
00066 if ( !supportedContentTypes.contains( Collection::mimeType() ) )
00067 break;
00068
00069
00070 if ( hasAncestor( m_view->indexAt( event->pos() ), collection.id() ) )
00071 break;
00072 } else {
00073 const QString type = url.queryItems()[ QString::fromLatin1( "type" ) ];
00074 if ( !supportedContentTypes.contains( type ) )
00075 break;
00076 }
00077
00078 return true;
00079 }
00080 }
00081
00082 return false;
00083 }
00084
00085 bool DragDropManager::hasAncestor( const QModelIndex &_index, Collection::Id parentId ) const
00086 {
00087 QModelIndex index( _index );
00088 while ( index.isValid() ) {
00089 if ( m_view->model()->data( index, EntityTreeModel::CollectionIdRole ).toLongLong() == parentId )
00090 return true;
00091
00092 index = index.parent();
00093 }
00094
00095 return false;
00096 }
00097
00098 bool DragDropManager::processDropEvent( QDropEvent *event )
00099 {
00100 const Collection targetCollection = currentDropTarget( event );
00101 if ( !targetCollection.isValid() )
00102 return false;
00103
00104 int actionCount = 0;
00105 Qt::DropAction defaultAction;
00106
00107
00108 bool moveAllowed, copyAllowed, linkAllowed;
00109 moveAllowed = copyAllowed = linkAllowed = false;
00110
00111 if ( (targetCollection.rights() & (Collection::CanCreateCollection | Collection::CanCreateItem))
00112 && (event->possibleActions() & Qt::MoveAction) ) {
00113 moveAllowed = true;
00114 }
00115
00116 if ( (targetCollection.rights() & (Collection::CanCreateCollection | Collection::CanCreateItem))
00117 && (event->possibleActions() & Qt::CopyAction) ) {
00118 copyAllowed = true;
00119 }
00120
00121 if ( (targetCollection.rights() & Collection::CanLinkItem) && (event->possibleActions() & Qt::LinkAction) ) {
00122 linkAllowed = true;
00123 }
00124
00125 if ( !moveAllowed && !copyAllowed && !linkAllowed ) {
00126 kDebug() << "Cannot drop here:" << event->possibleActions() << m_view->model()->supportedDragActions() << m_view->model()->supportedDropActions();
00127 return false;
00128 }
00129
00130
00131 if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) &&
00132 (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00133 if ( linkAllowed ) {
00134 defaultAction = Qt::LinkAction;
00135 actionCount = 1;
00136 } else
00137 return false;
00138 } else if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) ) {
00139 if ( copyAllowed ) {
00140 defaultAction = Qt::CopyAction;
00141 actionCount = 1;
00142 } else
00143 return false;
00144 } else if ( (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00145 if ( moveAllowed ) {
00146 defaultAction = Qt::MoveAction;
00147 actionCount = 1;
00148 } else
00149 return false;
00150 }
00151
00152 if ( actionCount == 1 ) {
00153 kDebug() << "Selecting drop action" << defaultAction << ", there are no other possibilities";
00154 event->setDropAction( defaultAction );
00155 return true;
00156 }
00157
00158
00159 QMenu popup( m_view );
00160 QAction* moveDropAction = 0;
00161 QAction* copyDropAction = 0;
00162 QAction* linkAction = 0;
00163 QString sequence;
00164
00165 if ( moveAllowed ) {
00166 sequence = QKeySequence( Qt::ShiftModifier ).toString();
00167 sequence.chop( 1 );
00168 moveDropAction = popup.addAction( KIcon( QString::fromLatin1( "go-jump" ) ), i18n( "&Move Here" ) + QLatin1Char( '\t' ) + sequence );
00169 }
00170
00171 if ( copyAllowed ) {
00172 sequence = QKeySequence( Qt::ControlModifier ).toString();
00173 sequence.chop( 1 );
00174 copyDropAction = popup.addAction( KIcon( QString::fromLatin1( "edit-copy" ) ), i18n( "&Copy Here" ) + QLatin1Char( '\t' ) + sequence );
00175 }
00176
00177 if ( linkAllowed ) {
00178 sequence = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString();
00179 sequence.chop( 1 );
00180 linkAction = popup.addAction( KIcon( QLatin1String( "edit-link" ) ), i18n( "&Link Here" ) + QLatin1Char( '\t' ) + sequence );
00181 }
00182
00183 popup.addSeparator();
00184 popup.addAction( KIcon( QString::fromLatin1( "process-stop" ) ), i18n( "C&ancel" ) + QLatin1Char( '\t' ) + QKeySequence( Qt::Key_Escape ).toString() );
00185
00186 QAction *activatedAction = popup.exec( QCursor::pos() );
00187
00188 if ( !activatedAction ) {
00189 return false;
00190 } else if ( activatedAction == moveDropAction ) {
00191 event->setDropAction( Qt::MoveAction );
00192 } else if ( activatedAction == copyDropAction ) {
00193 event->setDropAction( Qt::CopyAction );
00194 } else if ( activatedAction == linkAction ) {
00195 event->setDropAction( Qt::LinkAction );
00196 } else {
00197 return false;
00198 }
00199
00200 return true;
00201 }
00202
00203 void DragDropManager::startDrag( Qt::DropActions supportedActions )
00204 {
00205 QModelIndexList indexes;
00206 bool sourceDeletable = true;
00207 foreach ( const QModelIndex &index, m_view->selectionModel()->selectedRows() ) {
00208 if ( !m_view->model()->flags( index ) & Qt::ItemIsDragEnabled )
00209 continue;
00210
00211 if ( sourceDeletable ) {
00212 Collection source = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00213 if ( !source.isValid() ) {
00214
00215 source = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00216 sourceDeletable = source.rights() & Collection::CanDeleteItem;
00217 } else {
00218
00219 sourceDeletable = source.rights() & Collection::CanDeleteCollection;
00220 }
00221 }
00222
00223 indexes.append( index );
00224 }
00225
00226 if ( indexes.isEmpty() )
00227 return;
00228
00229 QMimeData *mimeData = m_view->model()->mimeData( indexes );
00230 if ( !mimeData )
00231 return;
00232
00233 QDrag *drag = new QDrag( m_view );
00234 drag->setMimeData( mimeData );
00235 if ( indexes.size() > 1 ) {
00236 drag->setPixmap( KIcon( QLatin1String( "document-multiple" ) ).pixmap( QSize( 22, 22 ) ) );
00237 } else {
00238 QPixmap pixmap = indexes.first().data( Qt::DecorationRole ).value<QIcon>().pixmap( QSize( 22, 22 ) );
00239 if ( pixmap.isNull() )
00240 pixmap = KIcon( QLatin1String( "text-plain" ) ).pixmap( QSize( 22, 22 ) );
00241 drag->setPixmap( pixmap );
00242 }
00243
00244 if ( !sourceDeletable )
00245 supportedActions &= ~Qt::MoveAction;
00246
00247 Qt::DropAction defaultAction = Qt::IgnoreAction;
00248 if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) &&
00249 (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00250 defaultAction = Qt::LinkAction;
00251 } else if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) ) {
00252 defaultAction = Qt::CopyAction;
00253 } else if ( (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00254 defaultAction = Qt::MoveAction;
00255 }
00256
00257 drag->exec( supportedActions, defaultAction );
00258 }