20 #include "dragdropmanager_p.h"
21 #include "specialcollectionattribute_p.h"
22 #include "collectionutils_p.h"
24 #include <QApplication>
30 #include <KDE/KLocalizedString>
33 #include "akonadi/collection.h"
34 #include "akonadi/entitytreemodel.h"
36 using namespace Akonadi;
38 DragDropManager::DragDropManager( QAbstractItemView *view )
39 : mShowDropActionMenu( true ), mIsManualSortingActive( false ), m_view( view )
45 const QModelIndex index = m_view->indexAt( event->pos() );
46 Collection collection = m_view->model()->data( index, EntityTreeModel::CollectionRole ).value<
Collection>();
48 const Item item = m_view->model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
49 if ( item.isValid() ) {
50 collection = m_view->model()->data( index.parent(), EntityTreeModel::CollectionRole ).value<Collection>();
57 bool DragDropManager::dropAllowed( QDragMoveEvent *event )
const
60 const Collection targetCollection = currentDropTarget( event );
61 if ( targetCollection.
isValid() ) {
62 const QStringList supportedContentTypes = targetCollection.
contentMimeTypes();
64 const QMimeData *data =
event->mimeData();
65 const KUrl::List urls = KUrl::List::fromMimeData( data );
66 foreach (
const KUrl &url, urls ) {
67 const Collection collection = Collection::fromUrl( url );
69 if ( !supportedContentTypes.contains( Collection::mimeType() ) &&
70 !supportedContentTypes.contains( Collection::virtualMimeType() ) ) {
75 if ( hasAncestor( m_view->indexAt( event->pos() ), collection.
id() ) ) {
79 const QString type = url.queryItems()[ QString::fromLatin1(
"type" ) ];
80 if ( !supportedContentTypes.contains( type ) ) {
92 bool DragDropManager::hasAncestor(
const QModelIndex &_index, Collection::Id parentId )
const
94 QModelIndex index( _index );
95 while ( index.isValid() ) {
96 if ( m_view->model()->data( index, EntityTreeModel::CollectionIdRole ).toLongLong() == parentId ) {
100 index = index.parent();
106 bool DragDropManager::processDropEvent( QDropEvent *event,
bool &menuCanceled,
bool dropOnItem )
108 const Collection targetCollection = currentDropTarget( event );
109 if ( !targetCollection.
isValid() ) {
113 if ( !mIsManualSortingActive && !dropOnItem ) {
117 const QStringList supportedContentTypes = targetCollection.
contentMimeTypes();
119 const QMimeData *data =
event->mimeData();
120 const KUrl::List urls = KUrl::List::fromMimeData( data );
121 foreach (
const KUrl &url, urls ) {
122 const Collection collection = Collection::fromUrl( url );
131 Qt::DropAction defaultAction;
134 bool moveAllowed, copyAllowed, linkAllowed;
135 moveAllowed = copyAllowed = linkAllowed =
false;
137 if ( ( targetCollection.
rights() & ( Collection::CanCreateCollection | Collection::CanCreateItem ) ) &&
138 (
event->possibleActions() & Qt::MoveAction ) ) {
141 if ( ( targetCollection.
rights() & ( Collection::CanCreateCollection | Collection::CanCreateItem ) ) &&
142 (
event->possibleActions() & Qt::CopyAction ) ) {
146 if ( ( targetCollection.
rights() & Collection::CanLinkItem ) && ( event->possibleActions() & Qt::LinkAction ) ) {
150 if ( mIsManualSortingActive && !dropOnItem ) {
156 if ( !moveAllowed && !copyAllowed && !linkAllowed ) {
157 kDebug() <<
"Cannot drop here:" <<
event->possibleActions() << m_view->model()->supportedDragActions() << m_view->model()->supportedDropActions();
162 if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) &&
163 ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
165 defaultAction = Qt::LinkAction;
170 }
else if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) ) {
172 defaultAction = Qt::CopyAction;
177 }
else if ( ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
179 defaultAction = Qt::MoveAction;
186 if ( actionCount == 1 ) {
187 kDebug() <<
"Selecting drop action" << defaultAction <<
", there are no other possibilities";
188 event->setDropAction( defaultAction );
192 if ( !mShowDropActionMenu ) {
194 defaultAction = Qt::MoveAction;
195 }
else if ( copyAllowed ) {
196 defaultAction = Qt::CopyAction;
197 }
else if ( linkAllowed ) {
198 defaultAction = Qt::LinkAction;
202 event->setDropAction( defaultAction );
207 QMenu popup( m_view );
208 QAction* moveDropAction = 0;
209 QAction* copyDropAction = 0;
210 QAction* linkAction = 0;
214 sequence = QKeySequence( Qt::ShiftModifier ).toString();
216 moveDropAction = popup.addAction( KIcon( QString::fromLatin1(
"go-jump" ) ), i18n(
"&Move Here" ) + QLatin1Char(
'\t' ) + sequence );
220 sequence = QKeySequence( Qt::ControlModifier ).toString();
222 copyDropAction = popup.addAction( KIcon( QString::fromLatin1(
"edit-copy" ) ), i18n(
"&Copy Here" ) + QLatin1Char(
'\t' ) + sequence );
226 sequence = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString();
228 linkAction = popup.addAction( KIcon( QLatin1String(
"edit-link" ) ), i18n(
"&Link Here" ) + QLatin1Char(
'\t' ) + sequence );
231 popup.addSeparator();
232 popup.addAction( KIcon( QString::fromLatin1(
"process-stop" ) ), i18n(
"C&ancel" ) + QLatin1Char(
'\t' ) + QKeySequence( Qt::Key_Escape ).toString() );
234 QAction *activatedAction = popup.exec( QCursor::pos() );
235 if ( !activatedAction ) {
238 }
else if ( activatedAction == moveDropAction ) {
239 event->setDropAction( Qt::MoveAction );
240 }
else if ( activatedAction == copyDropAction ) {
241 event->setDropAction( Qt::CopyAction );
242 }
else if ( activatedAction == linkAction ) {
243 event->setDropAction( Qt::LinkAction );
251 void DragDropManager::startDrag( Qt::DropActions supportedActions )
253 QModelIndexList indexes;
254 bool sourceDeletable =
true;
255 foreach (
const QModelIndex &index, m_view->selectionModel()->selectedRows() ) {
256 if ( !m_view->model()->flags( index ).testFlag( Qt::ItemIsDragEnabled ) ) {
260 if ( sourceDeletable ) {
264 source = index.data( EntityTreeModel::ParentCollectionRole ).value<
Collection>();
265 sourceDeletable = source.
rights() & Collection::CanDeleteItem;
271 indexes.append( index );
274 if ( indexes.isEmpty() ) {
278 QMimeData *mimeData = m_view->model()->mimeData( indexes );
283 QDrag *drag =
new QDrag( m_view );
284 drag->setMimeData( mimeData );
285 if ( indexes.size() > 1 ) {
286 drag->setPixmap( KIcon( QLatin1String(
"document-multiple" ) ).pixmap( QSize( 22, 22 ) ) );
288 QPixmap pixmap = indexes.first().data( Qt::DecorationRole ).value<QIcon>().pixmap( QSize( 22, 22 ) );
289 if ( pixmap.isNull() ) {
290 pixmap = KIcon( QLatin1String(
"text-plain" ) ).pixmap( QSize( 22, 22 ) );
292 drag->setPixmap( pixmap );
295 if ( !sourceDeletable ) {
296 supportedActions &= ~Qt::MoveAction;
299 Qt::DropAction defaultAction = Qt::IgnoreAction;
300 if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) &&
301 ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
302 defaultAction = Qt::LinkAction;
303 }
else if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) ) {
304 defaultAction = Qt::CopyAction;
305 }
else if ( ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
306 defaultAction = Qt::MoveAction;
309 drag->exec( supportedActions, defaultAction );
312 bool DragDropManager::showDropActionMenu()
const
314 return mShowDropActionMenu;
317 void DragDropManager::setShowDropActionMenu(
bool show )
319 mShowDropActionMenu = show;
322 bool DragDropManager::isManualSortingActive()
const
324 return mIsManualSortingActive;
327 void DragDropManager::setManualSortingActive(
bool active)
329 mIsManualSortingActive = active;
Represents a collection of PIM items.
An Attribute that stores the special collection type of a collection.
Id id() const
Returns the unique identifier of the entity.
Rights rights() const
Returns the rights the user has on the collection.
bool hasAttribute(const QByteArray &name) const
Returns true if the entity has an attribute of the given type name, false otherwise.
QStringList contentMimeTypes() const
Returns a list of possible content mimetypes, e.g.
bool isValid() const
Returns whether the entity is valid.
bool isVirtual() const
Returns whether the collection is virtual, for example a search collection.