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

akonadi

  • akonadi
entitytreeview.cpp
1 /*
2  Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
3  Copyright (c) 2008 Stephen Kelly <steveire@gmail.com>
4  Copyright (c) 2012 Laurent Montel <montel@kde.org>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "entitytreeview.h"
23 
24 #include "dragdropmanager_p.h"
25 
26 #include <QtCore/QDebug>
27 #include <QtCore/QTimer>
28 #include <QApplication>
29 #include <QDragMoveEvent>
30 #include <QHeaderView>
31 #include <QMenu>
32 
33 #include <KAction>
34 #include <KLocale>
35 #include <KMessageBox>
36 #include <KUrl>
37 #include <KXMLGUIFactory>
38 
39 #include <akonadi/collection.h>
40 #include <akonadi/control.h>
41 #include <akonadi/item.h>
42 #include <akonadi/entitytreemodel.h>
43 
44 #include <kdebug.h>
45 #include <kxmlguiclient.h>
46 
47 #include "progressspinnerdelegate_p.h"
48 
49 using namespace Akonadi;
50 
54 class EntityTreeView::Private
55 {
56 public:
57  Private( EntityTreeView *parent )
58  : mParent( parent )
59 #ifndef QT_NO_DRAGANDDROP
60  , mDragDropManager( new DragDropManager( mParent ) )
61 #endif
62  , mXmlGuiClient( 0 )
63  , mDefaultPopupMenu( QLatin1String( "akonadi_collectionview_contextmenu" ) )
64  {
65  }
66 
67  void init();
68  void itemClicked( const QModelIndex& );
69  void itemDoubleClicked( const QModelIndex& );
70  void itemCurrentChanged( const QModelIndex& );
71 
72  void slotSelectionChanged( const QItemSelection & selected, const QItemSelection & deselected );
73 
74  EntityTreeView *mParent;
75  QBasicTimer mDragExpandTimer;
76  DragDropManager *mDragDropManager;
77  KXMLGUIClient *mXmlGuiClient;
78  QString mDefaultPopupMenu;
79 };
80 
81 void EntityTreeView::Private::init()
82 {
83  Akonadi::DelegateAnimator *animator = new Akonadi::DelegateAnimator( mParent );
84  Akonadi::ProgressSpinnerDelegate *customDelegate = new Akonadi::ProgressSpinnerDelegate( animator, mParent );
85  mParent->setItemDelegate( customDelegate );
86 
87  mParent->header()->setClickable( true );
88  mParent->header()->setStretchLastSection( false );
89 // mParent->setRootIsDecorated( false );
90 
91  // QTreeView::autoExpandDelay has very strange behaviour. It toggles the collapse/expand state
92  // of the item the cursor is currently over when a timer event fires.
93  // The behaviour we want is to expand a collapsed row on drag-over, but not collapse it.
94  // mDragExpandTimer is used to achieve this.
95 // mParent->setAutoExpandDelay ( QApplication::startDragTime() );
96 
97  mParent->setSortingEnabled( true );
98  mParent->sortByColumn( 0, Qt::AscendingOrder );
99  mParent->setEditTriggers( QAbstractItemView::EditKeyPressed );
100  mParent->setAcceptDrops( true );
101 #ifndef QT_NO_DRAGANDDROP
102  mParent->setDropIndicatorShown( true );
103  mParent->setDragDropMode( DragDrop );
104  mParent->setDragEnabled( true );
105 #endif
106 
107  mParent->connect( mParent, SIGNAL(clicked(QModelIndex)),
108  mParent, SLOT(itemClicked(QModelIndex)) );
109  mParent->connect( mParent, SIGNAL(doubleClicked(QModelIndex)),
110  mParent, SLOT(itemDoubleClicked(QModelIndex)) );
111 
112  Control::widgetNeedsAkonadi( mParent );
113 }
114 
115 void EntityTreeView::Private::slotSelectionChanged( const QItemSelection & selected, const QItemSelection& )
116 {
117  const int column = 0;
118  foreach ( const QItemSelectionRange &range, selected ) {
119  const QModelIndex index = range.topLeft();
120 
121  if ( index.column() > 0 )
122  continue;
123 
124  for ( int row = index.row(); row <= range.bottomRight().row(); ++row ) {
125  // Don't use canFetchMore here. We need to bypass the check in
126  // the EntityFilterModel when it shows only collections.
127  mParent->model()->fetchMore( index.sibling( row, column ) );
128  }
129  }
130 
131  if ( selected.size() == 1 ) {
132  const QItemSelectionRange &range = selected.first();
133  if ( range.topLeft().row() == range.bottomRight().row() )
134  mParent->scrollTo( range.topLeft(), QTreeView::EnsureVisible );
135  }
136 }
137 
138 void EntityTreeView::Private::itemClicked( const QModelIndex &index )
139 {
140  if ( !index.isValid() )
141  return;
142  QModelIndex idx = index.sibling( index.row(), 0 );
143 
144  const Collection collection = idx.model()->data( idx, EntityTreeModel::CollectionRole ).value<Collection>();
145  if ( collection.isValid() ) {
146  emit mParent->clicked( collection );
147  } else {
148  const Item item = idx.model()->data( idx, EntityTreeModel::ItemRole ).value<Item>();
149  if ( item.isValid() )
150  emit mParent->clicked( item );
151  }
152 }
153 
154 void EntityTreeView::Private::itemDoubleClicked( const QModelIndex &index )
155 {
156  if ( !index.isValid() )
157  return;
158  QModelIndex idx = index.sibling( index.row(), 0 );
159  const Collection collection = idx.model()->data( idx, EntityTreeModel::CollectionRole ).value<Collection>();
160  if ( collection.isValid() ) {
161  emit mParent->doubleClicked( collection );
162  } else {
163  const Item item = idx.model()->data( idx, EntityTreeModel::ItemRole ).value<Item>();
164  if ( item.isValid() )
165  emit mParent->doubleClicked( item );
166  }
167 }
168 
169 void EntityTreeView::Private::itemCurrentChanged( const QModelIndex &index )
170 {
171  if ( !index.isValid() )
172  return;
173  QModelIndex idx = index.sibling( index.row(), 0 );
174  const Collection collection = idx.model()->data( idx, EntityTreeModel::CollectionRole ).value<Collection>();
175  if ( collection.isValid() ) {
176  emit mParent->currentChanged( collection );
177  } else {
178  const Item item = idx.model()->data( idx, EntityTreeModel::ItemRole ).value<Item>();
179  if ( item.isValid() )
180  emit mParent->currentChanged( item );
181  }
182 }
183 
184 EntityTreeView::EntityTreeView( QWidget * parent )
185  : QTreeView( parent ),
186  d( new Private( this ) )
187 {
188  setSelectionMode( QAbstractItemView::SingleSelection );
189  d->init();
190 }
191 
192 EntityTreeView::EntityTreeView( KXMLGUIClient *xmlGuiClient, QWidget * parent )
193  : QTreeView( parent ),
194  d( new Private( this ) )
195 {
196  d->mXmlGuiClient = xmlGuiClient;
197  d->init();
198 }
199 
200 EntityTreeView::~EntityTreeView()
201 {
202  delete d->mDragDropManager;
203  delete d;
204 }
205 
206 void EntityTreeView::setModel( QAbstractItemModel * model )
207 {
208  if ( selectionModel() ) {
209  disconnect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
210  this, SLOT(itemCurrentChanged(QModelIndex)) );
211 
212  disconnect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
213  this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) );
214  }
215 
216  QTreeView::setModel( model );
217  header()->setStretchLastSection( true );
218 
219  connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
220  SLOT(itemCurrentChanged(QModelIndex)) );
221 
222  connect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
223  SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) );
224 }
225 
226 
227 void EntityTreeView::timerEvent( QTimerEvent *event )
228 {
229  if ( event->timerId() == d->mDragExpandTimer.timerId() ) {
230  const QPoint pos = viewport()->mapFromGlobal( QCursor::pos() );
231  if ( state() == QAbstractItemView::DraggingState && viewport()->rect().contains( pos ) )
232  setExpanded( indexAt( pos ), true );
233  }
234 
235  QTreeView::timerEvent( event );
236 }
237 
238 #ifndef QT_NO_DRAGANDDROP
239 void EntityTreeView::dragMoveEvent( QDragMoveEvent * event )
240 {
241  d->mDragExpandTimer.start( QApplication::startDragTime() , this );
242 
243  if ( d->mDragDropManager->dropAllowed( event ) ) {
244  // All urls are supported. process the event.
245  QTreeView::dragMoveEvent( event );
246  return;
247  }
248 
249  event->setDropAction( Qt::IgnoreAction );
250 }
251 
252 void EntityTreeView::dropEvent( QDropEvent * event )
253 {
254  d->mDragExpandTimer.stop();
255  bool menuCanceled = false;
256  if ( d->mDragDropManager->processDropEvent( event, menuCanceled, ( dropIndicatorPosition () == QAbstractItemView::OnItem ) ) )
257  QTreeView::dropEvent( event );
258 }
259 #endif
260 
261 #ifndef QT_NO_CONTEXTMENU
262 void EntityTreeView::contextMenuEvent( QContextMenuEvent * event )
263 {
264  if ( !d->mXmlGuiClient || !model() ) {
265  return;
266  }
267 
268  const QModelIndex index = indexAt( event->pos() );
269  QString popupName = d->mDefaultPopupMenu;
270 
271  if ( index.isValid() ) { // popup not over empty space
272  // check whether the index under the cursor is a collection or item
273  const Item item = model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
274  popupName = ( item.isValid() ? QLatin1String( "akonadi_itemview_contextmenu" ) :
275  QLatin1String( "akonadi_collectionview_contextmenu" ) );
276  }
277 
278  QMenu *popup = static_cast<QMenu*>( d->mXmlGuiClient->factory()->container( popupName,
279  d->mXmlGuiClient ) );
280  if ( popup )
281  popup->exec( event->globalPos() );
282 }
283 #endif
284 
285 void EntityTreeView::setXmlGuiClient( KXMLGUIClient * xmlGuiClient )
286 {
287  d->mXmlGuiClient = xmlGuiClient;
288 }
289 
290 #ifndef QT_NO_DRAGANDDROP
291 void EntityTreeView::startDrag( Qt::DropActions supportedActions )
292 {
293  d->mDragDropManager->startDrag( supportedActions );
294 }
295 #endif
296 
297 
298 void EntityTreeView::setDropActionMenuEnabled( bool enabled )
299 {
300 #ifndef QT_NO_DRAGANDDROP
301  d->mDragDropManager->setShowDropActionMenu( enabled );
302 #endif
303 }
304 
305 bool EntityTreeView::isDropActionMenuEnabled() const
306 {
307 #ifndef QT_NO_DRAGANDDROP
308  return d->mDragDropManager->showDropActionMenu();
309 #else
310  return false;
311 #endif
312 }
313 
314 void EntityTreeView::setManualSortingActive(bool active)
315 {
316 #ifndef QT_NO_DRAGANDDROP
317  d->mDragDropManager->setManualSortingActive( active );
318 #endif
319 }
320 
321 bool EntityTreeView::isManualSortingActive() const
322 {
323 #ifndef QT_NO_DRAGANDDROP
324  return d->mDragDropManager->isManualSortingActive();
325 #else
326  return false;
327 #endif
328 }
329 
330 void EntityTreeView::setDefaultPopupMenu( const QString &name )
331 {
332  d->mDefaultPopupMenu = name;
333 }
334 
335 
336 #include "moc_entitytreeview.cpp"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:36 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