2 Copyright (C) 2013-2015 Laurent Montel <montel@kde.org>
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 #include "knotecollectionconfigwidget.h"
21 #include "NoteShared/ShowFolderNotesAttribute"
22 #include <Akonadi/Notes/NoteUtils>
23 #include "notesharedglobalconfig.h"
24 #include "AkonadiWidgets/ManageAccountWidget"
26 #include <AkonadiCore/CollectionModifyJob>
27 #include <AkonadiCore/CollectionFilterProxyModel>
28 #include <KRecursiveFilterProxyModel>
29 #include <QInputDialog>
31 #include <AkonadiWidgets/CollectionRequester>
32 #include <AkonadiCore/ChangeRecorder>
33 #include <AkonadiCore/EntityTreeModel>
34 #include <AkonadiCore/Collection>
35 #include <AkonadiWidgets/EntityTreeView>
36 #include <AkonadiCore/EntityDisplayAttribute>
38 #include <KMime/Message>
40 #include <KCheckableProxyModel>
42 #include <KLocalizedString>
43 #include <QPushButton>
45 #include "knotes_debug.h"
46 #include <KMessageBox>
48 #include <QVBoxLayout>
49 #include <QHBoxLayout>
53 KNoteCollectionConfigWidget::KNoteCollectionConfigWidget(QWidget
*parent
)
55 mCanUpdateStatus(false)
57 QHBoxLayout
*mainLayout
= new QHBoxLayout
;
58 setLayout(mainLayout
);
60 QTabWidget
*tabWidget
= new QTabWidget
;
61 mainLayout
->addWidget(tabWidget
);
63 QWidget
*collectionWidget
= new QWidget
;
64 QVBoxLayout
*vbox
= new QVBoxLayout
;
65 collectionWidget
->setLayout(vbox
);
66 tabWidget
->addTab(collectionWidget
, i18n("Folders"));
68 QLabel
*label
= new QLabel(i18n("Select which KNotes folders to show:"));
69 vbox
->addWidget(label
);
71 // Create a new change recorder.
72 mChangeRecorder
= new Akonadi::ChangeRecorder(this);
73 mChangeRecorder
->setMimeTypeMonitored(Akonadi::NoteUtils::noteMimeType());
74 mChangeRecorder
->fetchCollection(true);
75 mChangeRecorder
->setAllMonitored(true);
77 mModel
= new Akonadi::EntityTreeModel(mChangeRecorder
, this);
78 // Set the model to show only collections, not items.
79 mModel
->setItemPopulationStrategy(Akonadi::EntityTreeModel::NoItemPopulation
);
81 Akonadi::CollectionFilterProxyModel
*mimeTypeProxy
= new Akonadi::CollectionFilterProxyModel(this);
82 mimeTypeProxy
->setExcludeVirtualCollections(true);
83 mimeTypeProxy
->addMimeTypeFilters(QStringList() << Akonadi::NoteUtils::noteMimeType());
84 mimeTypeProxy
->setSourceModel(mModel
);
86 // Create the Check proxy model.
87 mSelectionModel
= new QItemSelectionModel(mimeTypeProxy
);
88 mCheckProxy
= new KCheckableProxyModel(this);
89 mCheckProxy
->setSelectionModel(mSelectionModel
);
90 mCheckProxy
->setSourceModel(mimeTypeProxy
);
92 connect(mModel
, &Akonadi::EntityTreeModel::rowsInserted
, this, &KNoteCollectionConfigWidget::slotCollectionsInserted
);
94 connect(mCheckProxy
, &KCheckableProxyModel::dataChanged
, this, &KNoteCollectionConfigWidget::slotDataChanged
);
95 mCollectionFilter
= new KRecursiveFilterProxyModel(this);
96 mCollectionFilter
->setSourceModel(mCheckProxy
);
97 mCollectionFilter
->setDynamicSortFilter(true);
98 mCollectionFilter
->setFilterCaseSensitivity(Qt::CaseInsensitive
);
100 QLineEdit
*searchLine
= new QLineEdit(this);
101 searchLine
->setPlaceholderText(i18n("Search..."));
102 searchLine
->setClearButtonEnabled(true);
103 connect(searchLine
, &QLineEdit::textChanged
, this, &KNoteCollectionConfigWidget::slotSetCollectionFilter
);
105 vbox
->addWidget(searchLine
);
107 mFolderView
= new Akonadi::EntityTreeView(this);
108 mFolderView
->setDragEnabled(false);
109 mFolderView
->setEditTriggers(QAbstractItemView::NoEditTriggers
);
110 mFolderView
->setAlternatingRowColors(true);
111 vbox
->addWidget(mFolderView
);
113 mFolderView
->setModel(mCollectionFilter
);
114 connect(mFolderView
->selectionModel(), &QItemSelectionModel::selectionChanged
, this, &KNoteCollectionConfigWidget::slotUpdateButtons
);
116 QHBoxLayout
*hbox
= new QHBoxLayout
;
117 vbox
->addLayout(hbox
);
119 QPushButton
*button
= new QPushButton(i18n("&Select All"), this);
120 connect(button
, &QPushButton::clicked
, this, &KNoteCollectionConfigWidget::slotSelectAllCollections
);
121 hbox
->addWidget(button
);
123 button
= new QPushButton(i18n("&Unselect All"), this);
124 connect(button
, &QPushButton::clicked
, this, &KNoteCollectionConfigWidget::slotUnselectAllCollections
);
125 hbox
->addWidget(button
);
128 mRenameCollection
= new QPushButton(i18n("Rename notes..."), this);
129 connect(mRenameCollection
, &QPushButton::clicked
, this, &KNoteCollectionConfigWidget::slotRenameCollection
);
130 hbox
->addWidget(mRenameCollection
);
132 vbox
->addWidget(new QLabel(i18nc("@info", "Select the folder where the note will be saved:")));
133 mDefaultSaveFolder
= new Akonadi::CollectionRequester(Akonadi::Collection(NoteShared::NoteSharedGlobalConfig::self()->defaultFolder()));
134 mDefaultSaveFolder
->setMimeTypeFilter(QStringList() << Akonadi::NoteUtils::noteMimeType());
135 mDefaultSaveFolder
->setContentMimeTypes(QStringList() << QStringLiteral("application/x-vnd.akonadi.note")
136 << QStringLiteral("text/x-vnd.akonadi.note")
137 << QStringLiteral("inode/directory"));
138 Akonadi::CollectionDialog::CollectionDialogOptions options
;
139 options
|= Akonadi::CollectionDialog::AllowToCreateNewChildCollection
;
140 options
|= Akonadi::CollectionDialog::KeepTreeExpanded
;
141 mDefaultSaveFolder
->changeCollectionDialogOptions(options
);
142 connect(mDefaultSaveFolder
, &Akonadi::CollectionRequester::collectionChanged
, this, &KNoteCollectionConfigWidget::slotDataChanged
);
144 vbox
->addWidget(mDefaultSaveFolder
);
146 QWidget
*accountWidget
= new QWidget
;
147 QVBoxLayout
*vboxAccountWidget
= new QVBoxLayout
;
148 accountWidget
->setLayout(vboxAccountWidget
);
150 Akonadi::ManageAccountWidget
*manageAccountWidget
= new Akonadi::ManageAccountWidget(this);
151 vboxAccountWidget
->addWidget(manageAccountWidget
);
153 manageAccountWidget
->setMimeTypeFilter(QStringList() << Akonadi::NoteUtils::noteMimeType());
154 manageAccountWidget
->setCapabilityFilter(QStringList() << QStringLiteral("Resource")); // show only resources, no agents
155 tabWidget
->addTab(accountWidget
, i18n("Accounts"));
157 QTimer::singleShot(1000, this, &KNoteCollectionConfigWidget::slotUpdateCollectionStatus
);
161 KNoteCollectionConfigWidget::~KNoteCollectionConfigWidget()
166 void KNoteCollectionConfigWidget::slotUpdateButtons()
168 mRenameCollection
->setEnabled(mFolderView
->selectionModel()->hasSelection());
171 void KNoteCollectionConfigWidget::slotRenameCollection()
173 const QModelIndexList rows
= mFolderView
->selectionModel()->selectedRows();
175 if (rows
.size() != 1) {
179 QModelIndex idx
= rows
.at(0);
181 QString title
= idx
.data().toString();
183 Akonadi::Collection col
= idx
.data(Akonadi::EntityTreeModel::CollectionRole
).value
<Akonadi::Collection
>();
184 Q_ASSERT(col
.isValid());
185 if (!col
.isValid()) {
190 const QString name
= QInputDialog::getText(this, i18n("Rename Notes"),
191 i18n("Name:"), QLineEdit::Normal
, title
, &ok
);
194 if (col
.hasAttribute
<Akonadi::EntityDisplayAttribute
>() &&
195 !col
.attribute
<Akonadi::EntityDisplayAttribute
>()->displayName().isEmpty()) {
196 col
.attribute
<Akonadi::EntityDisplayAttribute
>()->setDisplayName(name
);
197 } else if (!name
.isEmpty()) {
201 Akonadi::CollectionModifyJob
*job
= new Akonadi::CollectionModifyJob(col
, this);
202 connect(job
, &Akonadi::CollectionModifyJob::result
, this, &KNoteCollectionConfigWidget::slotCollectionModifyFinished
);
207 void KNoteCollectionConfigWidget::slotCollectionModifyFinished(KJob
*job
)
210 KMessageBox::error(this, i18n("An error was occurred during renaming: %1", job
->errorString()), i18n("Rename note"));
214 void KNoteCollectionConfigWidget::slotDataChanged()
216 Q_EMIT
emitChanged(true);
219 void KNoteCollectionConfigWidget::slotSetCollectionFilter(const QString
&filter
)
221 mCollectionFilter
->setFilterWildcard(filter
);
222 mFolderView
->expandAll();
225 void KNoteCollectionConfigWidget::slotUpdateCollectionStatus()
227 mCanUpdateStatus
= true;
228 updateStatus(QModelIndex());
231 void KNoteCollectionConfigWidget::slotSelectAllCollections()
233 forceStatus(QModelIndex(), true);
234 Q_EMIT
emitChanged(true);
237 void KNoteCollectionConfigWidget::slotUnselectAllCollections()
239 forceStatus(QModelIndex(), false);
240 Q_EMIT
emitChanged(true);
243 void KNoteCollectionConfigWidget::updateStatus(const QModelIndex
&parent
)
245 if (!mCanUpdateStatus
) {
249 const int nbCol
= mCheckProxy
->rowCount(parent
);
250 for (int i
= 0; i
< nbCol
; ++i
) {
251 const QModelIndex child
= mCheckProxy
->index(i
, 0, parent
);
253 const Akonadi::Collection collection
=
254 mCheckProxy
->data(child
, Akonadi::EntityTreeModel::CollectionRole
).value
<Akonadi::Collection
>();
256 NoteShared::ShowFolderNotesAttribute
*attr
= collection
.attribute
<NoteShared::ShowFolderNotesAttribute
>();
258 mCheckProxy
->setData(child
, Qt::Checked
, Qt::CheckStateRole
);
264 void KNoteCollectionConfigWidget::forceStatus(const QModelIndex
&parent
, bool status
)
266 const int nbCol
= mCheckProxy
->rowCount(parent
);
267 for (int i
= 0; i
< nbCol
; ++i
) {
268 const QModelIndex child
= mCheckProxy
->index(i
, 0, parent
);
269 mCheckProxy
->setData(child
, status
? Qt::Checked
: Qt::Unchecked
, Qt::CheckStateRole
);
270 forceStatus(child
, status
);
274 void KNoteCollectionConfigWidget::slotCollectionsInserted(const QModelIndex
&, int, int)
276 mFolderView
->expandAll();
279 void KNoteCollectionConfigWidget::save()
281 updateCollectionsRecursive(QModelIndex());
282 Akonadi::Collection col
= mDefaultSaveFolder
->collection();
284 NoteShared::NoteSharedGlobalConfig::self()->setDefaultFolder(col
.id());
285 NoteShared::NoteSharedGlobalConfig::self()->save();
289 void KNoteCollectionConfigWidget::updateCollectionsRecursive(const QModelIndex
&parent
)
291 const int nbCol
= mCheckProxy
->rowCount(parent
);
292 for (int i
= 0; i
< nbCol
; ++i
) {
293 const QModelIndex child
= mCheckProxy
->index(i
, 0, parent
);
295 Akonadi::Collection collection
=
296 mCheckProxy
->data(child
, Akonadi::EntityTreeModel::CollectionRole
).value
<Akonadi::Collection
>();
298 NoteShared::ShowFolderNotesAttribute
*attr
= collection
.attribute
<NoteShared::ShowFolderNotesAttribute
>();
299 Akonadi::CollectionModifyJob
*modifyJob
= 0;
300 const bool selected
= (mCheckProxy
->data(child
, Qt::CheckStateRole
).toInt() != 0);
301 if (selected
&& !attr
) {
302 attr
= collection
.attribute
<NoteShared::ShowFolderNotesAttribute
>(Akonadi::Collection::AddIfMissing
);
303 modifyJob
= new Akonadi::CollectionModifyJob(collection
);
304 modifyJob
->setProperty("AttributeAdded", true);
305 } else if (!selected
&& attr
) {
306 collection
.removeAttribute
<NoteShared::ShowFolderNotesAttribute
>();
307 modifyJob
= new Akonadi::CollectionModifyJob(collection
);
308 modifyJob
->setProperty("AttributeAdded", false);
312 connect(modifyJob
, &Akonadi::CollectionModifyJob::finished
, this, &KNoteCollectionConfigWidget::slotModifyJobDone
);
314 updateCollectionsRecursive(child
);
318 void KNoteCollectionConfigWidget::slotModifyJobDone(KJob
*job
)
320 Akonadi::CollectionModifyJob
*modifyJob
= qobject_cast
<Akonadi::CollectionModifyJob
*>(job
);
321 if (modifyJob
&& job
->error()) {
322 if (job
->property("AttributeAdded").toBool()) {
323 qCWarning(KNOTES_LOG
) << "Failed to append ShowFolderNotesAttribute to collection"
324 << modifyJob
->collection().id() << ":"
325 << job
->errorString();
327 qCWarning(KNOTES_LOG
) << "Failed to remove ShowFolderNotesAttribute from collection"
328 << modifyJob
->collection().id() << ":"
329 << job
->errorString();