• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • 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 ), 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   // Check if the collection under the cursor accepts this data type
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         // Check if we don't try to drop on one of the children
00072         if ( hasAncestor( m_view->indexAt( event->pos() ), collection.id() ) )
00073           break;
00074       } else { // This is an item.
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   // TODO check if the source supports moving
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   // first check whether the user pressed a modifier key to select a specific action
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   // otherwise show up a menu to allow the user to select an action
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 ); // chop superfluous '+'
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 ); // chop superfluous '+'
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 ); // chop superfluous '+'
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         // index points to an item
00229         source = index.data( EntityTreeModel::ParentCollectionRole ).value<Collection>();
00230         sourceDeletable = source.rights() & Collection::CanDeleteItem;
00231       } else {
00232         // index points to a collection
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 }

akonadi

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • 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
Generated for KDE-PIM Libraries by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal