akonadi
entitytreeview.cpp
00001 /* 00002 Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org> 00003 Copyright (c) 2008 Stephen Kelly <steveire@gmail.com> 00004 Copyright (c) 2012 Laurent Montel <montel@kde.org> 00005 00006 This library is free software; you can redistribute it and/or modify it 00007 under the terms of the GNU Library General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or (at your 00009 option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, but WITHOUT 00012 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00014 License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to the 00018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00019 02110-1301, USA. 00020 */ 00021 00022 #include "entitytreeview.h" 00023 00024 #include "dragdropmanager_p.h" 00025 00026 #include <QtCore/QDebug> 00027 #include <QtCore/QTimer> 00028 #include <QtGui/QApplication> 00029 #include <QtGui/QDragMoveEvent> 00030 #include <QtGui/QHeaderView> 00031 #include <QtGui/QMenu> 00032 00033 #include <KAction> 00034 #include <KLocale> 00035 #include <KMessageBox> 00036 #include <KUrl> 00037 #include <KXMLGUIFactory> 00038 00039 #include <akonadi/collection.h> 00040 #include <akonadi/control.h> 00041 #include <akonadi/item.h> 00042 #include <akonadi/entitytreemodel.h> 00043 00044 #include <kdebug.h> 00045 #include <kxmlguiclient.h> 00046 00047 #include "progressspinnerdelegate_p.h" 00048 00049 using namespace Akonadi; 00050 00054 class EntityTreeView::Private 00055 { 00056 public: 00057 Private( EntityTreeView *parent ) 00058 : mParent( parent ) 00059 #ifndef QT_NO_DRAGANDDROP 00060 , mDragDropManager( new DragDropManager( mParent ) ) 00061 #endif 00062 , mXmlGuiClient( 0 ) 00063 { 00064 } 00065 00066 void init(); 00067 void itemClicked( const QModelIndex& ); 00068 void itemDoubleClicked( const QModelIndex& ); 00069 void itemCurrentChanged( const QModelIndex& ); 00070 00071 void slotSelectionChanged( const QItemSelection & selected, const QItemSelection & deselected ); 00072 00073 EntityTreeView *mParent; 00074 QBasicTimer mDragExpandTimer; 00075 DragDropManager *mDragDropManager; 00076 KXMLGUIClient *mXmlGuiClient; 00077 }; 00078 00079 void EntityTreeView::Private::init() 00080 { 00081 Akonadi::DelegateAnimator *animator = new Akonadi::DelegateAnimator(mParent); 00082 Akonadi::ProgressSpinnerDelegate *customDelegate = new Akonadi::ProgressSpinnerDelegate(animator, mParent); 00083 mParent->setItemDelegate(customDelegate); 00084 00085 mParent->header()->setClickable( true ); 00086 mParent->header()->setStretchLastSection( false ); 00087 // mParent->setRootIsDecorated( false ); 00088 00089 // QTreeView::autoExpandDelay has very strange behaviour. It toggles the collapse/expand state 00090 // of the item the cursor is currently over when a timer event fires. 00091 // The behaviour we want is to expand a collapsed row on drag-over, but not collapse it. 00092 // mDragExpandTimer is used to achieve this. 00093 // mParent->setAutoExpandDelay ( QApplication::startDragTime() ); 00094 00095 mParent->setSortingEnabled( true ); 00096 mParent->sortByColumn( 0, Qt::AscendingOrder ); 00097 mParent->setEditTriggers( QAbstractItemView::EditKeyPressed ); 00098 mParent->setAcceptDrops( true ); 00099 #ifndef QT_NO_DRAGANDDROP 00100 mParent->setDropIndicatorShown( true ); 00101 mParent->setDragDropMode( DragDrop ); 00102 mParent->setDragEnabled( true ); 00103 #endif 00104 00105 mParent->connect( mParent, SIGNAL(clicked(QModelIndex)), 00106 mParent, SLOT(itemClicked(QModelIndex)) ); 00107 mParent->connect( mParent, SIGNAL(doubleClicked(QModelIndex)), 00108 mParent, SLOT(itemDoubleClicked(QModelIndex)) ); 00109 00110 Control::widgetNeedsAkonadi( mParent ); 00111 } 00112 00113 void EntityTreeView::Private::slotSelectionChanged( const QItemSelection & selected, const QItemSelection& ) 00114 { 00115 const int column = 0; 00116 foreach ( const QItemSelectionRange &range, selected ) { 00117 const QModelIndex index = range.topLeft(); 00118 00119 if ( index.column() > 0 ) 00120 continue; 00121 00122 for ( int row = index.row(); row <= range.bottomRight().row(); ++row ) { 00123 // Don't use canFetchMore here. We need to bypass the check in 00124 // the EntityFilterModel when it shows only collections. 00125 mParent->model()->fetchMore( index.sibling( row, column ) ); 00126 } 00127 } 00128 00129 if ( selected.size() == 1 ) { 00130 const QItemSelectionRange &range = selected.first(); 00131 if ( range.topLeft().row() == range.bottomRight().row() ) 00132 mParent->scrollTo( range.topLeft(), QTreeView::EnsureVisible ); 00133 } 00134 } 00135 00136 void EntityTreeView::Private::itemClicked( const QModelIndex &index ) 00137 { 00138 if ( !index.isValid() ) 00139 return; 00140 QModelIndex idx = index.sibling( index.row(), 0); 00141 00142 const Collection collection = idx.model()->data( idx, EntityTreeModel::CollectionRole ).value<Collection>(); 00143 if ( collection.isValid() ) { 00144 emit mParent->clicked( collection ); 00145 } else { 00146 const Item item = idx.model()->data( idx, EntityTreeModel::ItemRole ).value<Item>(); 00147 if ( item.isValid() ) 00148 emit mParent->clicked( item ); 00149 } 00150 } 00151 00152 void EntityTreeView::Private::itemDoubleClicked( const QModelIndex &index ) 00153 { 00154 if ( !index.isValid() ) 00155 return; 00156 QModelIndex idx = index.sibling( index.row(), 0); 00157 const Collection collection = idx.model()->data( idx, EntityTreeModel::CollectionRole ).value<Collection>(); 00158 if ( collection.isValid() ) { 00159 emit mParent->doubleClicked( collection ); 00160 } else { 00161 const Item item = idx.model()->data( idx, EntityTreeModel::ItemRole ).value<Item>(); 00162 if ( item.isValid() ) 00163 emit mParent->doubleClicked( item ); 00164 } 00165 } 00166 00167 void EntityTreeView::Private::itemCurrentChanged( const QModelIndex &index ) 00168 { 00169 if ( !index.isValid() ) 00170 return; 00171 QModelIndex idx = index.sibling( index.row(), 0); 00172 const Collection collection = idx.model()->data( idx, EntityTreeModel::CollectionRole ).value<Collection>(); 00173 if ( collection.isValid() ) { 00174 emit mParent->currentChanged( collection ); 00175 } else { 00176 const Item item = idx.model()->data( idx, EntityTreeModel::ItemRole ).value<Item>(); 00177 if ( item.isValid() ) 00178 emit mParent->currentChanged( item ); 00179 } 00180 } 00181 00182 EntityTreeView::EntityTreeView( QWidget * parent ) 00183 : QTreeView( parent ), 00184 d( new Private( this ) ) 00185 { 00186 setSelectionMode( QAbstractItemView::SingleSelection ); 00187 d->init(); 00188 } 00189 00190 EntityTreeView::EntityTreeView( KXMLGUIClient *xmlGuiClient, QWidget * parent ) 00191 : QTreeView( parent ), 00192 d( new Private( this ) ) 00193 { 00194 d->mXmlGuiClient = xmlGuiClient; 00195 d->init(); 00196 } 00197 00198 EntityTreeView::~EntityTreeView() 00199 { 00200 delete d->mDragDropManager; 00201 delete d; 00202 } 00203 00204 void EntityTreeView::setModel( QAbstractItemModel * model ) 00205 { 00206 if ( selectionModel() ) { 00207 disconnect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), 00208 this, SLOT(itemCurrentChanged(QModelIndex)) ); 00209 00210 disconnect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), 00211 this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) ); 00212 } 00213 00214 QTreeView::setModel( model ); 00215 header()->setStretchLastSection( true ); 00216 00217 connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), 00218 SLOT(itemCurrentChanged(QModelIndex)) ); 00219 00220 connect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), 00221 SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) ); 00222 } 00223 00224 00225 void EntityTreeView::timerEvent( QTimerEvent *event ) 00226 { 00227 if ( event->timerId() == d->mDragExpandTimer.timerId() ) { 00228 const QPoint pos = viewport()->mapFromGlobal( QCursor::pos() ); 00229 if ( state() == QAbstractItemView::DraggingState && viewport()->rect().contains( pos ) ) 00230 setExpanded( indexAt( pos ), true ); 00231 } 00232 00233 QTreeView::timerEvent( event ); 00234 } 00235 00236 #ifndef QT_NO_DRAGANDDROP 00237 void EntityTreeView::dragMoveEvent( QDragMoveEvent * event ) 00238 { 00239 d->mDragExpandTimer.start( QApplication::startDragTime() , this ); 00240 00241 if ( d->mDragDropManager->dropAllowed( event ) ) { 00242 // All urls are supported. process the event. 00243 QTreeView::dragMoveEvent( event ); 00244 return; 00245 } 00246 00247 event->setDropAction( Qt::IgnoreAction ); 00248 } 00249 00250 void EntityTreeView::dropEvent( QDropEvent * event ) 00251 { 00252 d->mDragExpandTimer.stop(); 00253 bool menuCanceled = false; 00254 if ( d->mDragDropManager->processDropEvent( event, menuCanceled, ( dropIndicatorPosition () == QAbstractItemView::OnItem ) ) ) 00255 QTreeView::dropEvent( event ); 00256 } 00257 #endif 00258 00259 #ifndef QT_NO_CONTEXTMENU 00260 void EntityTreeView::contextMenuEvent( QContextMenuEvent * event ) 00261 { 00262 if ( !d->mXmlGuiClient || !model()) 00263 return; 00264 00265 const QModelIndex index = indexAt( event->pos() ); 00266 00267 QMenu *popup = 0; 00268 00269 // check if the index under the cursor is a collection or item 00270 const Item item = model()->data( index, EntityTreeModel::ItemRole ).value<Item>(); 00271 if ( item.isValid() ) 00272 popup = static_cast<QMenu*>( d->mXmlGuiClient->factory()->container( 00273 QLatin1String( "akonadi_itemview_contextmenu" ), d->mXmlGuiClient ) ); 00274 else 00275 popup = static_cast<QMenu*>( d->mXmlGuiClient->factory()->container( 00276 QLatin1String( "akonadi_collectionview_contextmenu" ), d->mXmlGuiClient ) ); 00277 if ( popup ) 00278 popup->exec( event->globalPos() ); 00279 } 00280 #endif 00281 00282 void EntityTreeView::setXmlGuiClient( KXMLGUIClient * xmlGuiClient ) 00283 { 00284 d->mXmlGuiClient = xmlGuiClient; 00285 } 00286 00287 #ifndef QT_NO_DRAGANDDROP 00288 void EntityTreeView::startDrag( Qt::DropActions supportedActions ) 00289 { 00290 d->mDragDropManager->startDrag( supportedActions ); 00291 } 00292 #endif 00293 00294 00295 void EntityTreeView::setDropActionMenuEnabled( bool enabled ) 00296 { 00297 #ifndef QT_NO_DRAGANDDROP 00298 d->mDragDropManager->setShowDropActionMenu( enabled ); 00299 #endif 00300 } 00301 00302 bool EntityTreeView::isDropActionMenuEnabled() const 00303 { 00304 #ifndef QT_NO_DRAGANDDROP 00305 return d->mDragDropManager->showDropActionMenu(); 00306 #else 00307 return false; 00308 #endif 00309 } 00310 00311 void EntityTreeView::setManualSortingActive(bool active) 00312 { 00313 #ifndef QT_NO_DRAGANDDROP 00314 d->mDragDropManager->setManualSortingActive( active ); 00315 #endif 00316 } 00317 00318 bool EntityTreeView::isManualSortingActive() const 00319 { 00320 #ifndef QT_NO_DRAGANDDROP 00321 return d->mDragDropManager->isManualSortingActive(); 00322 #else 00323 return false; 00324 #endif 00325 } 00326 00327 00328 #include "entitytreeview.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:00:43 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue May 8 2012 00:00:43 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.