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