2
Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
3
Copyright (c) 2008 Stephen Kelly <steveire@gmail.com>
5
This library is free software; you can redistribute it and/or modify it
6
under the terms of the GNU Library General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or (at your
8
option) any later version.
10
This library is distributed in the hope that it will be useful, but WITHOUT
11
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13
License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to the
17
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
#include "entitytreeview.h"
23
#include <QtCore/QDebug>
24
#include <QtCore/QTimer>
25
#include <QtGui/QApplication>
26
#include <QtGui/QDragMoveEvent>
27
#include <QtGui/QHeaderView>
28
#include <QtGui/QMenu>
32
#include <KMessageBox>
34
#include <KXMLGUIFactory>
36
#include <kxmlguiclient.h>
38
#include <akonadi/collection.h>
39
#include <akonadi/control.h>
40
#include <akonadi/item.h>
41
#include "entitytreemodel.h"
45
using namespace Akonadi;
50
class EntityTreeView::Private
53
Private( EntityTreeView *parent )
55
xmlGuiClient( 0 ), showChildCollectionTree(false) {
60
void itemClicked( const QModelIndex& );
61
void itemDoubleClicked( const QModelIndex& );
62
void itemCurrentChanged( const QModelIndex& );
63
bool hasParent( const QModelIndex& idx, Collection::Id parentId );
65
EntityTreeView *mParent;
66
QModelIndex dragOverIndex;
67
QTimer dragExpandTimer;
69
KXMLGUIClient *xmlGuiClient;
70
bool showChildCollectionTree;
73
void EntityTreeView::showChildCollectionTree( bool include )
75
d->showChildCollectionTree = include;
78
bool EntityTreeView::childCollectionTreeShown() const
80
return d->showChildCollectionTree;
83
void EntityTreeView::Private::init()
85
mParent->header()->setClickable( true );
86
mParent->header()->setStretchLastSection( false );
87
// mParent->setRootIsDecorated( false );
89
// mParent->setAutoExpandDelay ( QApplication::startDragTime() );
91
mParent->setSortingEnabled( true );
92
mParent->sortByColumn( 0, Qt::AscendingOrder );
93
mParent->setEditTriggers( QAbstractItemView::EditKeyPressed );
94
mParent->setAcceptDrops( true );
95
mParent->setDropIndicatorShown( true );
96
mParent->setDragDropMode( DragDrop );
97
mParent->setDragEnabled( true );
99
dragExpandTimer.setSingleShot( true );
100
mParent->connect( &dragExpandTimer, SIGNAL( timeout() ), SLOT( dragExpand() ) );
102
mParent->connect( mParent, SIGNAL( clicked( const QModelIndex& ) ),
103
mParent, SLOT( itemClicked( const QModelIndex& ) ) );
104
mParent->connect( mParent, SIGNAL( doubleClicked( const QModelIndex& ) ),
105
mParent, SLOT( itemDoubleClicked( const QModelIndex& ) ) );
107
Control::widgetNeedsAkonadi( mParent );
110
bool EntityTreeView::Private::hasParent( const QModelIndex& idx, Collection::Id parentId )
112
QModelIndex idx2 = idx;
113
while ( idx2.isValid() ) {
114
if ( mParent->model()->data( idx2, EntityTreeModel::CollectionIdRole ).toLongLong() == parentId )
117
idx2 = idx2.parent();
122
void EntityTreeView::Private::dragExpand()
124
mParent->setExpanded( dragOverIndex, true );
125
dragOverIndex = QModelIndex();
128
void EntityTreeView::Private::itemClicked( const QModelIndex &index )
130
if ( !index.isValid() )
133
const Collection collection = index.model()->data( index, EntityTreeModel::CollectionRole ).value<Collection>();
134
if ( collection.isValid() ) {
135
emit mParent->clicked( collection );
137
const Item item = index.model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
138
if ( item.isValid() )
139
emit mParent->clicked( item );
143
void EntityTreeView::Private::itemDoubleClicked( const QModelIndex &index )
145
if ( !index.isValid() )
148
const Collection collection = index.model()->data( index, EntityTreeModel::CollectionRole ).value<Collection>();
149
if ( collection.isValid() ) {
150
emit mParent->doubleClicked( collection );
152
const Item item = index.model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
153
if ( item.isValid() )
154
emit mParent->doubleClicked( item );
158
void EntityTreeView::Private::itemCurrentChanged( const QModelIndex &index )
160
if ( !index.isValid() )
163
const Collection collection = index.model()->data( index, EntityTreeModel::CollectionRole ).value<Collection>();
164
if ( collection.isValid() ) {
165
emit mParent->currentChanged( collection );
167
const Item item = index.model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
168
if ( item.isValid() )
169
emit mParent->currentChanged( item );
173
EntityTreeView::EntityTreeView( QWidget * parent ) :
175
d( new Private( this ) )
178
setSelectionMode( QAbstractItemView::SingleSelection );
182
EntityTreeView::EntityTreeView( KXMLGUIClient *xmlGuiClient, QWidget * parent ) :
184
d( new Private( this ) )
186
d->xmlGuiClient = xmlGuiClient;
190
EntityTreeView::~EntityTreeView()
195
void EntityTreeView::setRootIndex(const QModelIndex &idx)
197
QAbstractItemView::setRootIndex(idx);
198
if (!d->showChildCollectionTree)
200
QModelIndex rowIndex = idx.child( 0, 0);
201
while (rowIndex.isValid())
203
if ( model()->data( rowIndex, EntityTreeModel::MimeTypeRole ) == Collection::mimeType() )
205
setRowHidden( rowIndex.row(), idx, true );
207
rowIndex = rowIndex.sibling( rowIndex.row() + 1, rowIndex.column() );
212
void EntityTreeView::setModel( QAbstractItemModel * model )
214
QTreeView::setModel( model );
215
header()->setStretchLastSection( true );
217
connect( selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
218
this, SLOT( itemCurrentChanged( const QModelIndex& ) ) );
221
void EntityTreeView::dragMoveEvent( QDragMoveEvent * event )
223
QModelIndex index = indexAt( event->pos() );
224
if ( d->dragOverIndex != index ) {
225
d->dragExpandTimer.stop();
226
if ( index.isValid() && !isExpanded( index ) && itemsExpandable() ) {
227
d->dragExpandTimer.start( QApplication::startDragTime() );
228
d->dragOverIndex = index;
232
// Check if the collection under the cursor accepts this data type
233
Collection col = model()->data( index, EntityTreeModel::CollectionRole ).value<Collection>();
236
Item item = model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
239
col = model()->data( index.parent(), EntityTreeModel::CollectionRole ).value<Collection>();
244
QStringList supportedContentTypes = col.contentMimeTypes();
245
const QMimeData *data = event->mimeData();
246
KUrl::List urls = KUrl::List::fromMimeData( data );
247
foreach( const KUrl &url, urls ) {
248
const Collection collection = Collection::fromUrl( url );
249
if ( collection.isValid() ) {
250
if ( !supportedContentTypes.contains( Collection::mimeType() ) )
253
// Check if we don't try to drop on one of the children
254
if ( d->hasParent( index, collection.id() ) )
256
} else { // This is an item.
257
QString type = url.queryItems()[ QString::fromLatin1( "type" )];
258
if ( !supportedContentTypes.contains( type ) )
261
// All urls are supported. process the event.
262
QTreeView::dragMoveEvent( event );
267
event->setDropAction( Qt::IgnoreAction );
271
void EntityTreeView::dragLeaveEvent( QDragLeaveEvent * event )
273
d->dragExpandTimer.stop();
274
d->dragOverIndex = QModelIndex();
275
QTreeView::dragLeaveEvent( event );
279
void EntityTreeView::dropEvent( QDropEvent * event )
281
d->dragExpandTimer.stop();
282
d->dragOverIndex = QModelIndex();
284
QModelIndexList idxs = selectedIndexes();
288
QAction* moveDropAction;
289
// TODO If possible, hide unavailable actions ...
290
// Use the model to determine if a move is ok.
293
moveDropAction = popup.addAction( KIcon( QString::fromLatin1( "edit-rename" ) ), i18n( "&Move here" ) );
296
//TODO: If dropping on one of the selectedIndexes, just return.
297
// open a context menu offering different drop actions (move, copy and cancel)
298
QAction* copyDropAction = popup.addAction( KIcon( QString::fromLatin1( "edit-copy" ) ), i18n( "&Copy here" ) );
299
popup.addSeparator();
300
popup.addAction( KIcon( QString::fromLatin1( "process-stop" ) ), i18n( "Cancel" ) );
302
QAction *activatedAction = popup.exec( QCursor::pos() );
304
if ( activatedAction == moveDropAction ) {
305
event->setDropAction( Qt::MoveAction );
306
} else if ( activatedAction == copyDropAction ) {
307
event->setDropAction( Qt::CopyAction );
309
// TODO: Handle link action.
312
QTreeView::dropEvent( event );
315
void EntityTreeView::contextMenuEvent( QContextMenuEvent * event )
317
if ( !d->xmlGuiClient )
320
const QModelIndex index = indexAt( event->pos() );
324
// check if the index under the cursor is a collection or item
325
const Item item = model()->data( index, EntityTreeModel::ItemRole ).value<Item>();
326
if ( item.isValid() )
327
popup = static_cast<QMenu*>( d->xmlGuiClient->factory()->container(
328
QLatin1String( "akonadi_itemview_contextmenu" ), d->xmlGuiClient ) );
330
popup = static_cast<QMenu*>( d->xmlGuiClient->factory()->container(
331
QLatin1String( "akonadi_collectionview_contextmenu" ), d->xmlGuiClient ) );
333
popup->exec( event->globalPos() );
336
void EntityTreeView::setXmlGuiClient( KXMLGUIClient * xmlGuiClient )
338
d->xmlGuiClient = xmlGuiClient;
341
#include "entitytreeview.moc"