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

akonadi

dragdropmanager.cpp
00001 /*
00002     Copyright (c) 2009 Stephen Kelly <steveire@gmail.com>
00003 
00004     This library is free software; you can redistribute it and/or modify it
00005     under the terms of the GNU Library General Public License as published by
00006     the Free Software Foundation; either version 2 of the License, or (at your
00007     option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful, but WITHOUT
00010     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00012     License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to the
00016     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
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 ), mIsManualSortingActive( false ), 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   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   // Check if the collection under the cursor accepts this data type
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         // Check if we don't try to drop on one of the children
00071         if ( hasAncestor( m_view->indexAt( event->pos() ), collection.id() ) )
00072           break;
00073       } else { // This is an item.
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, bool &menuCanceled, bool dropOnItem )
00100 {
00101   const Collection targetCollection = currentDropTarget( event );
00102   if ( !targetCollection.isValid() )
00103     return false;
00104 
00105   if ( !mIsManualSortingActive && !dropOnItem )
00106   {
00107     return false;
00108   }
00109 
00110   const QStringList supportedContentTypes = targetCollection.contentMimeTypes();
00111   
00112   const QMimeData *data = event->mimeData();
00113   const KUrl::List urls = KUrl::List::fromMimeData( data );
00114   foreach ( const KUrl &url, urls ) {
00115     const Collection collection = Collection::fromUrl( url );
00116     if( !collection.isValid() ) {
00117       if ( !dropOnItem ) {
00118         return false;
00119       }
00120     }
00121   } 
00122     
00123   int actionCount = 0;
00124   Qt::DropAction defaultAction;
00125   // TODO check if the source supports moving
00126 
00127   bool moveAllowed, copyAllowed, linkAllowed;
00128   moveAllowed = copyAllowed = linkAllowed = false;
00129 
00130   if ( (targetCollection.rights() & (Collection::CanCreateCollection | Collection::CanCreateItem))
00131        && (event->possibleActions() & Qt::MoveAction) ) {
00132     moveAllowed = true;
00133   }
00134   if ( (targetCollection.rights() & (Collection::CanCreateCollection | Collection::CanCreateItem))
00135         && (event->possibleActions() & Qt::CopyAction) ) {
00136     copyAllowed = true;
00137   }
00138 
00139   if ( (targetCollection.rights() & Collection::CanLinkItem) && (event->possibleActions() & Qt::LinkAction) ) {
00140     linkAllowed = true;
00141   }
00142 
00143   if ( mIsManualSortingActive && !dropOnItem ) {
00144     moveAllowed = true;
00145     copyAllowed = false;
00146     linkAllowed = false;
00147   }
00148     
00149   if ( !moveAllowed && !copyAllowed && !linkAllowed ) {
00150     kDebug() << "Cannot drop here:" << event->possibleActions() << m_view->model()->supportedDragActions() << m_view->model()->supportedDropActions();
00151     return false;
00152   }
00153 
00154   // first check whether the user pressed a modifier key to select a specific action
00155   if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) &&
00156        (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00157     if ( linkAllowed ) {
00158       defaultAction = Qt::LinkAction;
00159       actionCount = 1;
00160     } else
00161       return false;
00162   } else if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) ) {
00163     if ( copyAllowed ) {
00164       defaultAction = Qt::CopyAction;
00165       actionCount = 1;
00166     } else
00167       return false;
00168   } else if ( (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00169     if ( moveAllowed ) {
00170       defaultAction = Qt::MoveAction;
00171       actionCount = 1;
00172     } else
00173       return false;
00174   }
00175 
00176   if ( actionCount == 1 ) {
00177     kDebug() << "Selecting drop action" << defaultAction << ", there are no other possibilities";
00178     event->setDropAction( defaultAction );
00179     return true;
00180   }
00181 
00182   if ( !mShowDropActionMenu ) {
00183     if ( moveAllowed )
00184       defaultAction = Qt::MoveAction;
00185     else if ( copyAllowed )
00186       defaultAction = Qt::CopyAction;
00187     else if ( linkAllowed )
00188       defaultAction = Qt::LinkAction;
00189     else
00190       return false;
00191     event->setDropAction( defaultAction );
00192     return true;
00193   }
00194 
00195   // otherwise show up a menu to allow the user to select an action
00196   QMenu popup( m_view );
00197   QAction* moveDropAction = 0;
00198   QAction* copyDropAction = 0;
00199   QAction* linkAction = 0;
00200   QString sequence;
00201 
00202   if ( moveAllowed ) {
00203     sequence = QKeySequence( Qt::ShiftModifier ).toString();
00204     sequence.chop( 1 ); // chop superfluous '+'
00205     moveDropAction = popup.addAction( KIcon( QString::fromLatin1( "go-jump" ) ), i18n( "&Move Here" ) + QLatin1Char( '\t' ) + sequence );
00206   }
00207 
00208   if ( copyAllowed ) {
00209     sequence = QKeySequence( Qt::ControlModifier ).toString();
00210     sequence.chop( 1 ); // chop superfluous '+'
00211     copyDropAction = popup.addAction( KIcon( QString::fromLatin1( "edit-copy" ) ), i18n( "&Copy Here" ) + QLatin1Char( '\t' ) + sequence );
00212   }
00213 
00214   if ( linkAllowed ) {
00215     sequence = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString();
00216     sequence.chop( 1 ); // chop superfluous '+'
00217     linkAction = popup.addAction( KIcon( QLatin1String( "edit-link" ) ), i18n( "&Link Here" ) + QLatin1Char( '\t' ) + sequence );
00218   }
00219 
00220   popup.addSeparator();
00221   popup.addAction( KIcon( QString::fromLatin1( "process-stop" ) ), i18n( "C&ancel" ) + QLatin1Char( '\t' ) + QKeySequence( Qt::Key_Escape ).toString() );
00222 
00223   QAction *activatedAction = popup.exec( QCursor::pos() );
00224   if ( !activatedAction ) {
00225     menuCanceled = true;
00226     return false;
00227   } else if ( activatedAction == moveDropAction ) {
00228     event->setDropAction( Qt::MoveAction );
00229   } else if ( activatedAction == copyDropAction ) {
00230     event->setDropAction( Qt::CopyAction );
00231   } else if ( activatedAction == linkAction ) {
00232     event->setDropAction( Qt::LinkAction );
00233   } else {
00234     menuCanceled = true;
00235     return false;
00236   }
00237   return true;
00238 }
00239 
00240 void DragDropManager::startDrag( Qt::DropActions supportedActions )
00241 {
00242   QModelIndexList indexes;
00243   bool sourceDeletable = true;
00244   foreach ( const QModelIndex &index, m_view->selectionModel()->selectedRows() ) {
00245     if ( !m_view->model()->flags( index ).testFlag( Qt::ItemIsDragEnabled ) )
00246       continue;
00247 
00248     if ( sourceDeletable ) {
00249       Collection source = index.data( EntityTreeModel::CollectionRole ).value<Collection>();
00250       if ( !source.isValid() ) {
00251         // index points to an item
00252         source = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00253         sourceDeletable = source.rights() & Collection::CanDeleteItem;
00254       } else {
00255         // index points to a collection
00256         sourceDeletable = ( source.rights() & Collection::CanDeleteCollection ) && !source.hasAttribute<SpecialCollectionAttribute>() && !CollectionUtils::isVirtual( source );
00257       }
00258     }
00259     indexes.append( index );
00260   }
00261 
00262   if ( indexes.isEmpty() )
00263     return;
00264 
00265   QMimeData *mimeData = m_view->model()->mimeData( indexes );
00266   if ( !mimeData )
00267     return;
00268 
00269   QDrag *drag = new QDrag( m_view );
00270   drag->setMimeData( mimeData );
00271   if ( indexes.size() > 1 ) {
00272     drag->setPixmap( KIcon( QLatin1String( "document-multiple" ) ).pixmap( QSize( 22, 22 ) ) );
00273   } else {
00274     QPixmap pixmap = indexes.first().data( Qt::DecorationRole ).value<QIcon>().pixmap( QSize( 22, 22 ) );
00275     if ( pixmap.isNull() )
00276       pixmap = KIcon( QLatin1String( "text-plain" ) ).pixmap( QSize( 22, 22 ) );
00277     drag->setPixmap( pixmap );
00278   }
00279 
00280   if ( !sourceDeletable )
00281     supportedActions &= ~Qt::MoveAction;
00282 
00283   Qt::DropAction defaultAction = Qt::IgnoreAction;
00284   if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) &&
00285        (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00286     defaultAction = Qt::LinkAction;
00287   } else if ( (QApplication::keyboardModifiers() & Qt::ControlModifier) ) {
00288     defaultAction = Qt::CopyAction;
00289   } else if ( (QApplication::keyboardModifiers() & Qt::ShiftModifier) ) {
00290     defaultAction = Qt::MoveAction;
00291   }
00292 
00293   drag->exec( supportedActions, defaultAction );
00294 }
00295 
00296 bool DragDropManager::showDropActionMenu() const
00297 {
00298   return mShowDropActionMenu;
00299 }
00300 
00301 void DragDropManager::setShowDropActionMenu( bool show )
00302 {
00303   mShowDropActionMenu = show;
00304 }
00305 
00306 bool DragDropManager::isManualSortingActive() const
00307 {
00308   return mIsManualSortingActive;
00309 }
00310 
00311 void DragDropManager::setManualSortingActive(bool active)
00312 {
00313   mIsManualSortingActive = active;
00314 }
00315 
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:09:22 by doxygen 1.7.5 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.8.5 API Reference

Skip menu "kdepimlibs-4.8.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