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 #include "specialcollectionattribute_p.h"
00022
00023 #include <QtGui/QApplication>
00024 #include <QtGui/QDropEvent>
00025 #include <QtGui/QMenu>
00026
00027 #include <KDE/KIcon>
00028 #include <KDE/KLocale>
00029 #include <KDE/KUrl>
00030
00031 #include "akonadi/collection.h"
00032 #include "akonadi/entitytreemodel.h"
00033
00034 using namespace Akonadi;
00035
00036 DragDropManager::DragDropManager( QAbstractItemView *view )
00037 : mShowDropActionMenu( true ), m_view( view )
00038 {
00039 }
00040
00041 Collection DragDropManager::currentDropTarget( QDropEvent *event ) const
00042 {
00043 const QModelIndex index = m_view->indexAt( event->pos() );
00044
00045 Collection collection = m_view->model()->data( index, EntityTreeModel::CollectionRole ).value<Collection>();
00046 if ( !collection.isValid() ) {
00047 const Item item = m_view->model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
00048 if ( item.isValid() )
00049 collection = m_view->model()->data( index.parent(), EntityTreeModel::CollectionRole ).value<Collection>();
00050 }
00051
00052 return collection;
00053 }
00054
00055 bool DragDropManager::dropAllowed( QDragMoveEvent *event ) const
00056 {
00057
00058 const Collection targetCollection = currentDropTarget( event );
00059 if ( targetCollection.isValid() ) {
00060 const QStringList supportedContentTypes = targetCollection.contentMimeTypes();
00061
00062 const QMimeData *data = event->mimeData();
00063 const KUrl::List urls = KUrl::List::fromMimeData( data );
00064 foreach ( const KUrl &url, urls ) {
00065 const Collection collection = Collection::fromUrl( url );
00066 if ( collection.isValid() ) {
00067 if ( !supportedContentTypes.contains( Collection::mimeType() ) )
00068 break;
00069
00070
00071 if ( hasAncestor( m_view->indexAt( event->pos() ), collection.id() ) )
00072 break;
00073 } else {
00074 const QString type = url.queryItems()[ QString::fromLatin1( "type" ) ];
00075 if ( !supportedContentTypes.contains( type ) )
00076 break;
00077 }
00078
00079 return true;
00080 }
00081 }
00082
00083 return false;
00084 }
00085
00086 bool DragDropManager::hasAncestor( const QModelIndex &_index, Collection::Id parentId ) const
00087 {
00088 QModelIndex index( _index );
00089 while ( index.isValid() ) {
00090 if ( m_view->model()->data( index, EntityTreeModel::CollectionIdRole ).toLongLong() == parentId )
00091 return true;
00092
00093 index = index.parent();
00094 }
00095
00096 return false;
00097 }
00098
00099 bool DragDropManager::processDropEvent( QDropEvent *event )
00100 {
00101 const Collection targetCollection = currentDropTarget( event );
00102 if ( !targetCollection.isValid() )
00103 return false;
00104
00105 int actionCount = 0;
00106 Qt::DropAction defaultAction;
00107
00108
00109 bool moveAllowed, copyAllowed, linkAllowed;
00110 moveAllowed = copyAllowed = linkAllowed = false;
00111
00112 if ( (targetCollection.rights() & (Collection::CanCreateCollection | Collection::CanCreateItem))
00113 && (event->possibleActions() & Qt::MoveAction) ) {
00114 moveAllowed = true;
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 if ( !mShowDropActionMenu ) {
00159 if ( moveAllowed )
00160 defaultAction = Qt::MoveAction;
00161 else if ( copyAllowed )
00162 defaultAction = Qt::CopyAction;
00163 else if ( linkAllowed )
00164 defaultAction = Qt::LinkAction;
00165 else
00166 return false;
00167 event->setDropAction( defaultAction );
00168 return true;
00169 }
00170
00171
00172 QMenu popup( m_view );
00173 QAction* moveDropAction = 0;
00174 QAction* copyDropAction = 0;
00175 QAction* linkAction = 0;
00176 QString sequence;
00177
00178 if ( moveAllowed ) {
00179 sequence = QKeySequence( Qt::ShiftModifier ).toString();
00180 sequence.chop( 1 );
00181 moveDropAction = popup.addAction( KIcon( QString::fromLatin1( "go-jump" ) ), i18n( "&Move Here" ) + QLatin1Char( '\t' ) + sequence );
00182 }
00183
00184 if ( copyAllowed ) {
00185 sequence = QKeySequence( Qt::ControlModifier ).toString();
00186 sequence.chop( 1 );
00187 copyDropAction = popup.addAction( KIcon( QString::fromLatin1( "edit-copy" ) ), i18n( "&Copy Here" ) + QLatin1Char( '\t' ) + sequence );
00188 }
00189
00190 if ( linkAllowed ) {
00191 sequence = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString();
00192 sequence.chop( 1 );
00193 linkAction = popup.addAction( KIcon( QLatin1String( "edit-link" ) ), i18n( "&Link Here" ) + QLatin1Char( '\t' ) + sequence );
00194 }
00195
00196 popup.addSeparator();
00197 popup.addAction( KIcon( QString::fromLatin1( "process-stop" ) ), i18n( "C&ancel" ) + QLatin1Char( '\t' ) + QKeySequence( Qt::Key_Escape ).toString() );
00198
00199 QAction *activatedAction = popup.exec( QCursor::pos() );
00200
00201 if ( !activatedAction ) {
00202 return false;
00203 } else if ( activatedAction == moveDropAction ) {
00204 event->setDropAction( Qt::MoveAction );
00205 } else if ( activatedAction == copyDropAction ) {
00206 event->setDropAction( Qt::CopyAction );
00207 } else if ( activatedAction == linkAction ) {
00208 event->setDropAction( Qt::LinkAction );
00209 } else {
00210 return false;
00211 }
00212
00213 return true;
00214 }
00215
00216 void DragDropManager::startDrag( Qt::DropActions supportedActions )
00217 {
00218 QModelIndexList indexes;
00219 bool sourceDeletable = true;
00220 foreach ( const QModelIndex &index, m_view->selectionModel()->selectedRows() ) {
00221 if ( !m_view->model()->flags( index ) & Qt::ItemIsDragEnabled )
00222 continue;
00223
00224 if ( sourceDeletable ) {
00225 Collection source = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00226 if ( !source.isValid() ) {
00227
00228 source = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00229 sourceDeletable = source.rights() & Collection::CanDeleteItem;
00230 } else {
00231
00232 sourceDeletable = ( source.rights() & Collection::CanDeleteCollection ) && !source.hasAttribute<SpecialCollectionAttribute>() ;
00233 }
00234 }
00235 indexes.append( index );
00236 }
00237
00238 if ( indexes.isEmpty() )
00239 return;
00240
00241 QMimeData *mimeData = m_view->model()->mimeData( indexes );
00242 if ( !mimeData )
00243 return;
00244
00245 QDrag *drag = new QDrag( m_view );
00246 drag->setMimeData( mimeData );
00247 if ( indexes.size() > 1 ) {
00248 drag->setPixmap( KIcon( QLatin1String( "document-multiple" ) ).pixmap( QSize( 22, 22 ) ) );
00249 } else {
00250 QPixmap pixmap = indexes.first().data( Qt::DecorationRole ).value<QIcon>().pixmap( QSize( 22, 22 ) );
00251 if ( pixmap.isNull() )
00252 pixmap = KIcon( QLatin1String( "text-plain" ) ).pixmap( QSize( 22, 22 ) );
00253 drag->setPixmap( pixmap );
00254 }
00255
00256 if ( !sourceDeletable )
00257 supportedActions &= ~Qt::MoveAction;
00258
00259 Qt::DropAction defaultAction = Qt::IgnoreAction;
00260 if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) &&
00261 (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00262 defaultAction = Qt::LinkAction;
00263 } else if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) ) {
00264 defaultAction = Qt::CopyAction;
00265 } else if ( (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00266 defaultAction = Qt::MoveAction;
00267 }
00268
00269 drag->exec( supportedActions, defaultAction );
00270 }
00271
00272 bool DragDropManager::showDropActionMenu() const
00273 {
00274 return mShowDropActionMenu;
00275 }
00276
00277 void DragDropManager::setShowDropActionMenu( bool show )
00278 {
00279 mShowDropActionMenu = show;
00280 }