1/*
2 Copyright (c) 2006 - 2007 Volker Krause <vkrause@kde.org>
3 Copyright (c) 2008 Stephen Kelly <steveire@gmail.com>
4 Copyright (c) 2009 Kevin Ottens <ervin@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 "entitylistview.h"
23
24#include "dragdropmanager_p.h"
25#include "favoritecollectionsmodel.h"
26
27#include <QtCore/QDebug>
28#include <QtCore/QTimer>
29#include <QDragMoveEvent>
30#include <QMenu>
31
32#include <kdebug.h>
33#include <kxmlguiclient.h>
34#include <KXMLGUIFactory>
35
36#include <akonadi/collection.h>
37#include <akonadi/control.h>
38#include <akonadi/item.h>
39#include <akonadi/entitytreemodel.h>
40
41#include <progressspinnerdelegate_p.h>
42
43using namespace Akonadi;
44
45/**
46 * @internal
47 */
48class EntityListView::Private
49{
50public:
51 Private(EntityListView *parent)
52 : mParent(parent)
53#ifndef QT_NO_DRAGANDDROP
54 , mDragDropManager(new DragDropManager(mParent))
55#endif
56 , mXmlGuiClient(0)
57 {
58 }
59
60 void init();
61 void itemClicked(const QModelIndex &index);
62 void itemDoubleClicked(const QModelIndex &index);
63 void itemCurrentChanged(const QModelIndex &index);
64
65 EntityListView *mParent;
66 DragDropManager *mDragDropManager;
67 KXMLGUIClient *mXmlGuiClient;
68};
69
70void EntityListView::Private::init()
71{
72 mParent->setEditTriggers(QAbstractItemView::EditKeyPressed);
73 mParent->setAcceptDrops(true);
74#ifndef QT_NO_DRAGANDDROP
75 mParent->setDropIndicatorShown(true);
76 mParent->setDragDropMode(DragDrop);
77 mParent->setDragEnabled(true);
78#endif
79 mParent->connect(mParent, SIGNAL(clicked(QModelIndex)),
80 mParent, SLOT(itemClicked(QModelIndex)));
81 mParent->connect(mParent, SIGNAL(doubleClicked(QModelIndex)),
82 mParent, SLOT(itemDoubleClicked(QModelIndex)));
83
84 DelegateAnimator *animator = new DelegateAnimator(mParent);
85 ProgressSpinnerDelegate *customDelegate = new ProgressSpinnerDelegate(animator, mParent);
86 mParent->setItemDelegate(customDelegate);
87
88 Control::widgetNeedsAkonadi(mParent);
89}
90
91void EntityListView::Private::itemClicked(const QModelIndex &index)
92{
93 if (!index.isValid()) {
94 return;
95 }
96
97 const Collection collection = index.model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
98 if (collection.isValid()) {
99 emit mParent->clicked(collection);
100 } else {
101 const Item item = index.model()->data(index, EntityTreeModel::ItemRole).value<Item>();
102 if (item.isValid()) {
103 emit mParent->clicked(item);
104 }
105 }
106}
107
108void EntityListView::Private::itemDoubleClicked(const QModelIndex &index)
109{
110 if (!index.isValid()) {
111 return;
112 }
113
114 const Collection collection = index.model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
115 if (collection.isValid()) {
116 emit mParent->doubleClicked(collection);
117 } else {
118 const Item item = index.model()->data(index, EntityTreeModel::ItemRole).value<Item>();
119 if (item.isValid()) {
120 emit mParent->doubleClicked(item);
121 }
122 }
123}
124
125void EntityListView::Private::itemCurrentChanged(const QModelIndex &index)
126{
127 if (!index.isValid()) {
128 return;
129 }
130
131 const Collection collection = index.model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
132 if (collection.isValid()) {
133 emit mParent->currentChanged(collection);
134 } else {
135 const Item item = index.model()->data(index, EntityTreeModel::ItemRole).value<Item>();
136 if (item.isValid()) {
137 emit mParent->currentChanged(item);
138 }
139 }
140}
141
142EntityListView::EntityListView(QWidget *parent)
143 : QListView(parent)
144 , d(new Private(this))
145{
146 setSelectionMode(QAbstractItemView::SingleSelection);
147 d->init();
148}
149
150EntityListView::EntityListView(KXMLGUIClient *xmlGuiClient, QWidget *parent)
151 : QListView(parent)
152 , d(new Private(this))
153{
154 d->mXmlGuiClient = xmlGuiClient;
155 d->init();
156}
157
158EntityListView::~EntityListView()
159{
160 delete d->mDragDropManager;
161 delete d;
162}
163
164void EntityListView::setModel(QAbstractItemModel *model)
165{
166 if (selectionModel()) {
167 disconnect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
168 this, SLOT(itemCurrentChanged(QModelIndex)));
169 }
170
171 QListView::setModel(model);
172
173 connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
174 SLOT(itemCurrentChanged(QModelIndex)));
175}
176
177#ifndef QT_NO_DRAGANDDROP
178void EntityListView::dragMoveEvent(QDragMoveEvent *event)
179{
180 if (d->mDragDropManager->dropAllowed(event) ||
181 qobject_cast<Akonadi::FavoriteCollectionsModel *>(model())) {
182 // All urls are supported. process the event.
183 QListView::dragMoveEvent(event);
184 return;
185 }
186
187 event->setDropAction(Qt::IgnoreAction);
188}
189
190void EntityListView::dropEvent(QDropEvent *event)
191{
192 bool menuCanceled = false;
193 if (d->mDragDropManager->processDropEvent(event, menuCanceled) &&
194 !menuCanceled) {
195 if (menuCanceled) {
196 return;
197 }
198 QListView::dropEvent(event);
199 } else if (qobject_cast<Akonadi::FavoriteCollectionsModel *>(model()) &&
200 !menuCanceled) {
201 QListView::dropEvent(event);
202 }
203}
204#endif
205
206#ifndef QT_NO_CONTEXTMENU
207void EntityListView::contextMenuEvent(QContextMenuEvent *event)
208{
209 if (!d->mXmlGuiClient) {
210 return;
211 }
212
213 const QModelIndex index = indexAt(event->pos());
214
215 QMenu *popup = 0;
216
217 // check if the index under the cursor is a collection or item
218 const Collection collection = model()->data(index, EntityTreeModel::CollectionRole).value<Collection>();
219 if (collection.isValid()) {
220 popup = static_cast<QMenu *>(d->mXmlGuiClient->factory()->container(
221 QLatin1String("akonadi_favoriteview_contextmenu"), d->mXmlGuiClient));
222 } else {
223 popup = static_cast<QMenu *>(d->mXmlGuiClient->factory()->container(
224 QLatin1String("akonadi_favoriteview_emptyselection_contextmenu"), d->mXmlGuiClient));
225 }
226
227 if (popup) {
228 popup->exec(event->globalPos());
229 }
230}
231#endif
232
233void EntityListView::setXmlGuiClient(KXMLGUIClient *xmlGuiClient)
234{
235 d->mXmlGuiClient = xmlGuiClient;
236}
237
238KXMLGUIClient *EntityListView::xmlGuiClient() const
239{
240 return d->mXmlGuiClient;
241}
242
243#ifndef QT_NO_DRAGANDDROP
244void EntityListView::startDrag(Qt::DropActions supportedActions)
245{
246 d->mDragDropManager->startDrag(supportedActions);
247}
248#endif
249
250void EntityListView::setDropActionMenuEnabled(bool enabled)
251{
252#ifndef QT_NO_DRAGANDDROP
253 d->mDragDropManager->setShowDropActionMenu(enabled);
254#endif
255}
256
257bool EntityListView::isDropActionMenuEnabled() const
258{
259#ifndef QT_NO_DRAGANDDROP
260 return d->mDragDropManager->showDropActionMenu();
261#else
262 return false;
263#endif
264}
265
266#include "moc_entitylistview.cpp"
267