• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
dragdropmanager.cpp
1 /*
2  Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "dragdropmanager_p.h"
21 #include "specialcollectionattribute_p.h"
22 #include "collectionutils_p.h"
23 
24 #include <QApplication>
25 #include <QDropEvent>
26 #include <QMenu>
27 
28 #include <KDE/KIcon>
29 #include <KDE/KLocale>
30 #include <KDE/KUrl>
31 
32 #include "akonadi/collection.h"
33 #include "akonadi/entitytreemodel.h"
34 
35 using namespace Akonadi;
36 
37 DragDropManager::DragDropManager( QAbstractItemView *view )
38  : mShowDropActionMenu( true ), mIsManualSortingActive( false ), m_view( view )
39 {
40 }
41 
42 Akonadi::Collection DragDropManager::currentDropTarget( QDropEvent *event ) const
43 {
44  const QModelIndex index = m_view->indexAt( event->pos() );
45  Collection collection = m_view->model()->data( index, EntityTreeModel::CollectionRole ).value<Collection>();
46  if ( !collection.isValid() ) {
47  const Item item = m_view->model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
48  if ( item.isValid() ) {
49  collection = m_view->model()->data( index.parent(), EntityTreeModel::CollectionRole ).value<Collection>();
50  }
51  }
52 
53  return collection;
54 }
55 
56 bool DragDropManager::dropAllowed( QDragMoveEvent *event ) const
57 {
58  // Check if the collection under the cursor accepts this data type
59  const Collection targetCollection = currentDropTarget( event );
60  if ( targetCollection.isValid() ) {
61  const QStringList supportedContentTypes = targetCollection.contentMimeTypes();
62 
63  const QMimeData *data = event->mimeData();
64  const KUrl::List urls = KUrl::List::fromMimeData( data );
65  foreach ( const KUrl &url, urls ) {
66  const Collection collection = Collection::fromUrl( url );
67  if ( collection.isValid() ) {
68  if ( !supportedContentTypes.contains( Collection::mimeType() ) ) {
69  break;
70  }
71 
72  // Check if we don't try to drop on one of the children
73  if ( hasAncestor( m_view->indexAt( event->pos() ), collection.id() ) ) {
74  break;
75  }
76  } else { // This is an item.
77  const QString type = url.queryItems()[ QString::fromLatin1( "type" ) ];
78  if ( !supportedContentTypes.contains( type ) ) {
79  break;
80  }
81  }
82 
83  return true;
84  }
85  }
86 
87  return false;
88 }
89 
90 bool DragDropManager::hasAncestor( const QModelIndex &_index, Collection::Id parentId ) const
91 {
92  QModelIndex index( _index );
93  while ( index.isValid() ) {
94  if ( m_view->model()->data( index, EntityTreeModel::CollectionIdRole ).toLongLong() == parentId ) {
95  return true;
96  }
97 
98  index = index.parent();
99  }
100 
101  return false;
102 }
103 
104 bool DragDropManager::processDropEvent( QDropEvent *event, bool &menuCanceled, bool dropOnItem )
105 {
106  const Collection targetCollection = currentDropTarget( event );
107  if ( !targetCollection.isValid() ) {
108  return false;
109  }
110 
111  if ( !mIsManualSortingActive && !dropOnItem ) {
112  return false;
113  }
114 
115  const QStringList supportedContentTypes = targetCollection.contentMimeTypes();
116 
117  const QMimeData *data = event->mimeData();
118  const KUrl::List urls = KUrl::List::fromMimeData( data );
119  foreach ( const KUrl &url, urls ) {
120  const Collection collection = Collection::fromUrl( url );
121  if ( !collection.isValid() ) {
122  if ( !dropOnItem ) {
123  return false;
124  }
125  }
126  }
127 
128  int actionCount = 0;
129  Qt::DropAction defaultAction;
130  // TODO check if the source supports moving
131 
132  bool moveAllowed, copyAllowed, linkAllowed;
133  moveAllowed = copyAllowed = linkAllowed = false;
134 
135  if ( ( targetCollection.rights() & ( Collection::CanCreateCollection | Collection::CanCreateItem ) ) &&
136  ( event->possibleActions() & Qt::MoveAction ) ) {
137  moveAllowed = true;
138  }
139  if ( ( targetCollection.rights() & ( Collection::CanCreateCollection | Collection::CanCreateItem ) ) &&
140  ( event->possibleActions() & Qt::CopyAction ) ) {
141  copyAllowed = true;
142  }
143 
144  if ( ( targetCollection.rights() & Collection::CanLinkItem ) && ( event->possibleActions() & Qt::LinkAction ) ) {
145  linkAllowed = true;
146  }
147 
148  if ( mIsManualSortingActive && !dropOnItem ) {
149  moveAllowed = true;
150  copyAllowed = false;
151  linkAllowed = false;
152  }
153 
154  if ( !moveAllowed && !copyAllowed && !linkAllowed ) {
155  kDebug() << "Cannot drop here:" << event->possibleActions() << m_view->model()->supportedDragActions() << m_view->model()->supportedDropActions();
156  return false;
157  }
158 
159  // first check whether the user pressed a modifier key to select a specific action
160  if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) &&
161  ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
162  if ( linkAllowed ) {
163  defaultAction = Qt::LinkAction;
164  actionCount = 1;
165  } else {
166  return false;
167  }
168  } else if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) ) {
169  if ( copyAllowed ) {
170  defaultAction = Qt::CopyAction;
171  actionCount = 1;
172  } else {
173  return false;
174  }
175  } else if ( ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
176  if ( moveAllowed ) {
177  defaultAction = Qt::MoveAction;
178  actionCount = 1;
179  } else {
180  return false;
181  }
182  }
183 
184  if ( actionCount == 1 ) {
185  kDebug() << "Selecting drop action" << defaultAction << ", there are no other possibilities";
186  event->setDropAction( defaultAction );
187  return true;
188  }
189 
190  if ( !mShowDropActionMenu ) {
191  if ( moveAllowed ) {
192  defaultAction = Qt::MoveAction;
193  } else if ( copyAllowed ) {
194  defaultAction = Qt::CopyAction;
195  } else if ( linkAllowed ) {
196  defaultAction = Qt::LinkAction;
197  } else {
198  return false;
199  }
200  event->setDropAction( defaultAction );
201  return true;
202  }
203 
204  // otherwise show up a menu to allow the user to select an action
205  QMenu popup( m_view );
206  QAction* moveDropAction = 0;
207  QAction* copyDropAction = 0;
208  QAction* linkAction = 0;
209  QString sequence;
210 
211  if ( moveAllowed ) {
212  sequence = QKeySequence( Qt::ShiftModifier ).toString();
213  sequence.chop( 1 ); // chop superfluous '+'
214  moveDropAction = popup.addAction( KIcon( QString::fromLatin1( "go-jump" ) ), i18n( "&Move Here" ) + QLatin1Char( '\t' ) + sequence );
215  }
216 
217  if ( copyAllowed ) {
218  sequence = QKeySequence( Qt::ControlModifier ).toString();
219  sequence.chop( 1 ); // chop superfluous '+'
220  copyDropAction = popup.addAction( KIcon( QString::fromLatin1( "edit-copy" ) ), i18n( "&Copy Here" ) + QLatin1Char( '\t' ) + sequence );
221  }
222 
223  if ( linkAllowed ) {
224  sequence = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString();
225  sequence.chop( 1 ); // chop superfluous '+'
226  linkAction = popup.addAction( KIcon( QLatin1String( "edit-link" ) ), i18n( "&Link Here" ) + QLatin1Char( '\t' ) + sequence );
227  }
228 
229  popup.addSeparator();
230  popup.addAction( KIcon( QString::fromLatin1( "process-stop" ) ), i18n( "C&ancel" ) + QLatin1Char( '\t' ) + QKeySequence( Qt::Key_Escape ).toString() );
231 
232  QAction *activatedAction = popup.exec( QCursor::pos() );
233  if ( !activatedAction ) {
234  menuCanceled = true;
235  return false;
236  } else if ( activatedAction == moveDropAction ) {
237  event->setDropAction( Qt::MoveAction );
238  } else if ( activatedAction == copyDropAction ) {
239  event->setDropAction( Qt::CopyAction );
240  } else if ( activatedAction == linkAction ) {
241  event->setDropAction( Qt::LinkAction );
242  } else {
243  menuCanceled = true;
244  return false;
245  }
246  return true;
247 }
248 
249 void DragDropManager::startDrag( Qt::DropActions supportedActions )
250 {
251  QModelIndexList indexes;
252  bool sourceDeletable = true;
253  foreach ( const QModelIndex &index, m_view->selectionModel()->selectedRows() ) {
254  if ( !m_view->model()->flags( index ).testFlag( Qt::ItemIsDragEnabled ) ) {
255  continue;
256  }
257 
258  if ( sourceDeletable ) {
259  Collection source = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
260  if ( !source.isValid() ) {
261  // index points to an item
262  source = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
263  sourceDeletable = source.rights() & Collection::CanDeleteItem;
264  } else {
265  // index points to a collection
266  sourceDeletable = ( source.rights() & Collection::CanDeleteCollection ) && !source.hasAttribute<SpecialCollectionAttribute>() && !source.isVirtual();
267  }
268  }
269  indexes.append( index );
270  }
271 
272  if ( indexes.isEmpty() ) {
273  return;
274  }
275 
276  QMimeData *mimeData = m_view->model()->mimeData( indexes );
277  if ( !mimeData ) {
278  return;
279  }
280 
281  QDrag *drag = new QDrag( m_view );
282  drag->setMimeData( mimeData );
283  if ( indexes.size() > 1 ) {
284  drag->setPixmap( KIcon( QLatin1String( "document-multiple" ) ).pixmap( QSize( 22, 22 ) ) );
285  } else {
286  QPixmap pixmap = indexes.first().data( Qt::DecorationRole ).value<QIcon>().pixmap( QSize( 22, 22 ) );
287  if ( pixmap.isNull() ) {
288  pixmap = KIcon( QLatin1String( "text-plain" ) ).pixmap( QSize( 22, 22 ) );
289  }
290  drag->setPixmap( pixmap );
291  }
292 
293  if ( !sourceDeletable ) {
294  supportedActions &= ~Qt::MoveAction;
295  }
296 
297  Qt::DropAction defaultAction = Qt::IgnoreAction;
298  if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) &&
299  ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
300  defaultAction = Qt::LinkAction;
301  } else if ( ( QApplication::keyboardModifiers() & Qt::ControlModifier ) ) {
302  defaultAction = Qt::CopyAction;
303  } else if ( ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) ) {
304  defaultAction = Qt::MoveAction;
305  }
306 
307  drag->exec( supportedActions, defaultAction );
308 }
309 
310 bool DragDropManager::showDropActionMenu() const
311 {
312  return mShowDropActionMenu;
313 }
314 
315 void DragDropManager::setShowDropActionMenu( bool show )
316 {
317  mShowDropActionMenu = show;
318 }
319 
320 bool DragDropManager::isManualSortingActive() const
321 {
322  return mIsManualSortingActive;
323 }
324 
325 void DragDropManager::setManualSortingActive(bool active)
326 {
327  mIsManualSortingActive = active;
328 }
329 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:35 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal