1/*
2 This file is part of Akonadi Contact.
3
4 Copyright (c) 2007-2009 Tobias Koenig <tokoe@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 "collectioncombobox.h"
23#include "collectioncombobox_p.h"
24
25#include "asyncselectionhandler_p.h"
26#include "collectiondialog.h"
27
28#include <akonadi/changerecorder.h>
29#include <akonadi/collectionfetchscope.h>
30#include <akonadi/collectionfilterproxymodel.h>
31#include <akonadi/entityrightsfiltermodel.h>
32#include <akonadi/entitytreemodel.h>
33#include <akonadi/session.h>
34
35#include <kdescendantsproxymodel.h>
36#include "collectionutils_p.h"
37
38#include <QtCore/QAbstractItemModel>
39#include <QtCore/QEvent>
40#include <QPointer>
41#include <QMouseEvent>
42
43using namespace Akonadi;
44
45class CollectionComboBox::Private
46{
47public:
48 Private(QAbstractItemModel *customModel, CollectionComboBox *parent)
49 : mParent(parent)
50 , mMonitor(0)
51 , mModel(0)
52 {
53 if (customModel) {
54 mBaseModel = customModel;
55 } else {
56 mMonitor = new Akonadi::ChangeRecorder(mParent);
57 mMonitor->fetchCollection(true);
58 mMonitor->setCollectionMonitored(Akonadi::Collection::root());
59
60 mModel = new EntityTreeModel(mMonitor, mParent);
61 mModel->setItemPopulationStrategy(EntityTreeModel::NoItemPopulation);
62
63 mBaseModel = mModel;
64 }
65
66 KDescendantsProxyModel *proxyModel = new KDescendantsProxyModel(parent);
67 proxyModel->setDisplayAncestorData(true);
68 proxyModel->setSourceModel(mBaseModel);
69
70 mMimeTypeFilterModel = new CollectionFilterProxyModel(parent);
71 mMimeTypeFilterModel->setSourceModel(proxyModel);
72
73 mRightsFilterModel = new EntityRightsFilterModel(parent);
74 mRightsFilterModel->setSourceModel(mMimeTypeFilterModel);
75
76 mParent->setModel(mRightsFilterModel);
77 mParent->model()->sort(mParent->modelColumn());
78
79 mSelectionHandler = new AsyncSelectionHandler(mRightsFilterModel, mParent);
80 mParent->connect(mSelectionHandler, SIGNAL(collectionAvailable(QModelIndex)),
81 mParent, SLOT(activated(QModelIndex)));
82
83 mParent->connect(mParent, SIGNAL(activated(int)),
84 mParent, SLOT(activated(int)));
85 }
86
87 ~Private()
88 {
89 }
90
91 void activated(int index);
92 void activated(const QModelIndex &index);
93
94 CollectionComboBox *mParent;
95
96 ChangeRecorder *mMonitor;
97 EntityTreeModel *mModel;
98 QAbstractItemModel *mBaseModel;
99 CollectionFilterProxyModel *mMimeTypeFilterModel;
100 EntityRightsFilterModel *mRightsFilterModel;
101 AsyncSelectionHandler *mSelectionHandler;
102};
103
104void CollectionComboBox::Private::activated(int index)
105{
106 const QModelIndex modelIndex = mParent->model()->index(index, 0);
107 if (modelIndex.isValid()) {
108 emit mParent->currentChanged(modelIndex.data(EntityTreeModel::CollectionRole).value<Collection>());
109 }
110}
111
112void CollectionComboBox::Private::activated(const QModelIndex &index)
113{
114 mParent->setCurrentIndex(index.row());
115}
116
117MobileEventHandler::MobileEventHandler(CollectionComboBox *comboBox, CollectionFilterProxyModel *mimeTypeFilter,
118 EntityRightsFilterModel *accessRightsFilter, QAbstractItemModel *customModel)
119 : QObject(comboBox)
120 , mComboBox(comboBox)
121 , mMimeTypeFilter(mimeTypeFilter)
122 , mAccessRightsFilter(accessRightsFilter)
123 , mCustomModel(customModel)
124{
125}
126
127bool MobileEventHandler::eventFilter(QObject *object, QEvent *event)
128{
129 if (object == mComboBox && mComboBox->isEnabled() && event->type() == QEvent::MouseButtonPress) {
130
131 const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
132
133 // we receive mouse events from other widgets as well, so check for ours
134 if (mComboBox->rect().contains(mouseEvent->pos())) {
135 QMetaObject::invokeMethod(this, "openDialog", Qt::QueuedConnection);
136 }
137
138 return true;
139 }
140
141 return QObject::eventFilter(object, event);
142}
143
144void MobileEventHandler::openDialog()
145{
146 QPointer<Akonadi::CollectionDialog> dialog(new Akonadi::CollectionDialog(mCustomModel));
147 dialog->setMimeTypeFilter(mMimeTypeFilter->mimeTypeFilters());
148 dialog->setAccessRightsFilter(mAccessRightsFilter->accessRights());
149
150 if (dialog->exec() == QDialog::Accepted && dialog != 0) {
151 const Akonadi::Collection collection = dialog->selectedCollection();
152 const QModelIndex index = Akonadi::EntityTreeModel::modelIndexForCollection(mComboBox->model(), collection);
153 mComboBox->setCurrentIndex(index.row());
154 }
155 delete dialog;
156}
157
158CollectionComboBox::CollectionComboBox(QWidget *parent)
159 : KComboBox(parent)
160 , d(new Private(0, this))
161{
162#ifdef KDEPIM_MOBILE_UI
163 MobileEventHandler *handler = new MobileEventHandler(this, d->mMimeTypeFilterModel, d->mRightsFilterModel, d->mBaseModel);
164 installEventFilter(handler);
165#endif
166}
167
168CollectionComboBox::CollectionComboBox(QAbstractItemModel *model, QWidget *parent)
169 : KComboBox(parent)
170 , d(new Private(model, this))
171{
172#ifdef KDEPIM_MOBILE_UI
173 MobileEventHandler *handler = new MobileEventHandler(this, d->mMimeTypeFilterModel, d->mRightsFilterModel, d->mBaseModel);
174 installEventFilter(handler);
175#endif
176}
177
178CollectionComboBox::~CollectionComboBox()
179{
180 delete d;
181}
182
183void CollectionComboBox::setMimeTypeFilter(const QStringList &contentMimeTypes)
184{
185 d->mMimeTypeFilterModel->clearFilters();
186 d->mMimeTypeFilterModel->addMimeTypeFilters(contentMimeTypes);
187
188 if (d->mMonitor) {
189 foreach (const QString &mimeType, contentMimeTypes) {
190 d->mMonitor->setMimeTypeMonitored(mimeType, true);
191 }
192 }
193}
194
195QStringList CollectionComboBox::mimeTypeFilter() const
196{
197 return d->mMimeTypeFilterModel->mimeTypeFilters();
198}
199
200void CollectionComboBox::setAccessRightsFilter(Collection::Rights rights)
201{
202 d->mRightsFilterModel->setAccessRights(rights);
203}
204
205Akonadi::Collection::Rights CollectionComboBox::accessRightsFilter() const
206{
207 return d->mRightsFilterModel->accessRights();
208}
209
210void CollectionComboBox::setDefaultCollection(const Collection &collection)
211{
212 d->mSelectionHandler->waitForCollection(collection);
213}
214
215Akonadi::Collection CollectionComboBox::currentCollection() const
216{
217 const QModelIndex modelIndex = model()->index(currentIndex(), 0);
218 if (modelIndex.isValid()) {
219 return modelIndex.data(Akonadi::EntityTreeModel::CollectionRole).value<Collection>();
220 } else {
221 return Akonadi::Collection();
222 }
223}
224
225void CollectionComboBox::setExcludeVirtualCollections(bool b)
226{
227 d->mMimeTypeFilterModel->setExcludeVirtualCollections(b);
228}
229
230bool CollectionComboBox::excludeVirtualCollections() const
231{
232 return d->mMimeTypeFilterModel->excludeVirtualCollections();
233}
234
235#include "moc_collectioncombobox.cpp"
236#include "moc_collectioncombobox_p.cpp"
237