• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.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 <QtGui/QApplication>
25 #include <QtGui/QDropEvent>
26 #include <QtGui/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  return collection;
53 }
54 
55 bool DragDropManager::dropAllowed( QDragMoveEvent *event ) const
56 {
57  // Check if the collection under the cursor accepts this data type
58  const Collection targetCollection = currentDropTarget( event );
59  if ( targetCollection.isValid() ) {
60  const QStringList supportedContentTypes = targetCollection.contentMimeTypes();
61 
62  const QMimeData *data = event->mimeData();
63  const KUrl::List urls = KUrl::List::fromMimeData( data );
64  foreach ( const KUrl &url, urls ) {
65  const Collection collection = Collection::fromUrl( url );
66  if ( collection.isValid() ) {
67  if ( !supportedContentTypes.contains( Collection::mimeType() ) )
68  break;
69 
70  // Check if we don't try to drop on one of the children
71  if ( hasAncestor( m_view->indexAt( event->pos() ), collection.id() ) )
72  break;
73  } else { // This is an item.
74  const QString type = url.queryItems()[ QString::fromLatin1( "type" ) ];
75  if ( !supportedContentTypes.contains( type ) )
76  break;
77  }
78 
79  return true;
80  }
81  }
82 
83  return false;
84 }
85 
86 bool DragDropManager::hasAncestor( const QModelIndex &_index, Collection::Id parentId ) const
87 {
88  QModelIndex index( _index );
89  while ( index.isValid() ) {
90  if ( m_view->model()->data( index, EntityTreeModel::CollectionIdRole ).toLongLong() == parentId )
91  return true;
92 
93  index = index.parent();
94  }
95 
96  return false;
97 }
98 
99 bool DragDropManager::processDropEvent( QDropEvent *event, bool &menuCanceled, bool dropOnItem )
100 {
101  const Collection targetCollection = currentDropTarget( event );
102  if ( !targetCollection.isValid() )
103  return false;
104 
105  if ( !mIsManualSortingActive && !dropOnItem )
106  {
107  return false;
108  }
109 
110  const QStringList supportedContentTypes = targetCollection.contentMimeTypes();
111 
112  const QMimeData *data = event->mimeData();
113  const KUrl::List urls = KUrl::List::fromMimeData( data );
114  foreach ( const KUrl &url, urls ) {
115  const Collection collection = Collection::fromUrl( url );
116  if( !collection.isValid() ) {
117  if ( !dropOnItem ) {
118  return false;
119  }
120  }
121  }
122 
123  int actionCount = 0;
124  Qt::DropAction defaultAction;
125  // TODO check if the source supports moving
126 
127  bool moveAllowed, copyAllowed, linkAllowed;
128  moveAllowed = copyAllowed = linkAllowed = false;
129 
130  if ( (targetCollection.rights() & (Collection::CanCreateCollection | Collection::CanCreateItem))
131  && (event->possibleActions() & Qt::MoveAction) ) {
132  moveAllowed = true;
133  }
134  if ( (targetCollection.rights() & (Collection::CanCreateCollection | Collection::CanCreateItem))
135  && (event->possibleActions() & Qt::CopyAction) ) {
136  copyAllowed = true;
137  }
138 
139  if ( (targetCollection.rights() & Collection::CanLinkItem) && (event->possibleActions() & Qt::LinkAction) ) {
140  linkAllowed = true;
141  }
142 
143  if ( mIsManualSortingActive && !dropOnItem ) {
144  moveAllowed = true;
145  copyAllowed = false;
146  linkAllowed = false;
147  }
148 
149  if ( !moveAllowed && !copyAllowed && !linkAllowed ) {
150  kDebug() << "Cannot drop here:" << event->possibleActions() << m_view->model()->supportedDragActions() << m_view->model()->supportedDropActions();
151  return false;
152  }
153 
154  // first check whether the user pressed a modifier key to select a specific action
155  if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) &&
156  (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
157  if ( linkAllowed ) {
158  defaultAction = Qt::LinkAction;
159  actionCount = 1;
160  } else
161  return false;
162  } else if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) ) {
163  if ( copyAllowed ) {
164  defaultAction = Qt::CopyAction;
165  actionCount = 1;
166  } else
167  return false;
168  } else if ( (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
169  if ( moveAllowed ) {
170  defaultAction = Qt::MoveAction;
171  actionCount = 1;
172  } else
173  return false;
174  }
175 
176  if ( actionCount == 1 ) {
177  kDebug() << "Selecting drop action" << defaultAction << ", there are no other possibilities";
178  event->setDropAction( defaultAction );
179  return true;
180  }
181 
182  if ( !mShowDropActionMenu ) {
183  if ( moveAllowed )
184  defaultAction = Qt::MoveAction;
185  else if ( copyAllowed )
186  defaultAction = Qt::CopyAction;
187  else if ( linkAllowed )
188  defaultAction = Qt::LinkAction;
189  else
190  return false;
191  event->setDropAction( defaultAction );
192  return true;
193  }
194 
195  // otherwise show up a menu to allow the user to select an action
196  QMenu popup( m_view );
197  QAction* moveDropAction = 0;
198  QAction* copyDropAction = 0;
199  QAction* linkAction = 0;
200  QString sequence;
201 
202  if ( moveAllowed ) {
203  sequence = QKeySequence( Qt::ShiftModifier ).toString();
204  sequence.chop( 1 ); // chop superfluous '+'
205  moveDropAction = popup.addAction( KIcon( QString::fromLatin1( "go-jump" ) ), i18n( "&Move Here" ) + QLatin1Char( '\t' ) + sequence );
206  }
207 
208  if ( copyAllowed ) {
209  sequence = QKeySequence( Qt::ControlModifier ).toString();
210  sequence.chop( 1 ); // chop superfluous '+'
211  copyDropAction = popup.addAction( KIcon( QString::fromLatin1( "edit-copy" ) ), i18n( "&Copy Here" ) + QLatin1Char( '\t' ) + sequence );
212  }
213 
214  if ( linkAllowed ) {
215  sequence = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString();
216  sequence.chop( 1 ); // chop superfluous '+'
217  linkAction = popup.addAction( KIcon( QLatin1String( "edit-link" ) ), i18n( "&Link Here" ) + QLatin1Char( '\t' ) + sequence );
218  }
219 
220  popup.addSeparator();
221  popup.addAction( KIcon( QString::fromLatin1( "process-stop" ) ), i18n( "C&ancel" ) + QLatin1Char( '\t' ) + QKeySequence( Qt::Key_Escape ).toString() );
222 
223  QAction *activatedAction = popup.exec( QCursor::pos() );
224  if ( !activatedAction ) {
225  menuCanceled = true;
226  return false;
227  } else if ( activatedAction == moveDropAction ) {
228  event->setDropAction( Qt::MoveAction );
229  } else if ( activatedAction == copyDropAction ) {
230  event->setDropAction( Qt::CopyAction );
231  } else if ( activatedAction == linkAction ) {
232  event->setDropAction( Qt::LinkAction );
233  } else {
234  menuCanceled = true;
235  return false;
236  }
237  return true;
238 }
239 
240 void DragDropManager::startDrag( Qt::DropActions supportedActions )
241 {
242  QModelIndexList indexes;
243  bool sourceDeletable = true;
244  foreach ( const QModelIndex &index, m_view->selectionModel()->selectedRows() ) {
245  if ( !m_view->model()->flags( index ).testFlag( Qt::ItemIsDragEnabled ) )
246  continue;
247 
248  if ( sourceDeletable ) {
249  Collection source = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
250  if ( !source.isValid() ) {
251  // index points to an item
252  source = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
253  sourceDeletable = source.rights() & Collection::CanDeleteItem;
254  } else {
255  // index points to a collection
256  sourceDeletable = ( source.rights() & Collection::CanDeleteCollection ) && !source.hasAttribute<SpecialCollectionAttribute>() && !CollectionUtils::isVirtual( source );
257  }
258  }
259  indexes.append( index );
260  }
261 
262  if ( indexes.isEmpty() )
263  return;
264 
265  QMimeData *mimeData = m_view->model()->mimeData( indexes );
266  if ( !mimeData )
267  return;
268 
269  QDrag *drag = new QDrag( m_view );
270  drag->setMimeData( mimeData );
271  if ( indexes.size() > 1 ) {
272  drag->setPixmap( KIcon( QLatin1String( "document-multiple" ) ).pixmap( QSize( 22, 22 ) ) );
273  } else {
274  QPixmap pixmap = indexes.first().data( Qt::DecorationRole ).value<QIcon>().pixmap( QSize( 22, 22 ) );
275  if ( pixmap.isNull() )
276  pixmap = KIcon( QLatin1String( "text-plain" ) ).pixmap( QSize( 22, 22 ) );
277  drag->setPixmap( pixmap );
278  }
279 
280  if ( !sourceDeletable )
281  supportedActions &= ~Qt::MoveAction;
282 
283  Qt::DropAction defaultAction = Qt::IgnoreAction;
284  if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) &&
285  (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
286  defaultAction = Qt::LinkAction;
287  } else if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) ) {
288  defaultAction = Qt::CopyAction;
289  } else if ( (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
290  defaultAction = Qt::MoveAction;
291  }
292 
293  drag->exec( supportedActions, defaultAction );
294 }
295 
296 bool DragDropManager::showDropActionMenu() const
297 {
298  return mShowDropActionMenu;
299 }
300 
301 void DragDropManager::setShowDropActionMenu( bool show )
302 {
303  mShowDropActionMenu = show;
304 }
305 
306 bool DragDropManager::isManualSortingActive() const
307 {
308  return mIsManualSortingActive;
309 }
310 
311 void DragDropManager::setManualSortingActive(bool active)
312 {
313  mIsManualSortingActive = active;
314 }
315 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jan 5 2013 19:46:03 by doxygen 1.8.1.2 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.9.5 API Reference

Skip menu "kdepimlibs-4.9.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • 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