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

akonadi

  • akonadi
tageditwidget.cpp
1/*
2 This file is part of Akonadi
3
4 Copyright (c) 2014 Christian Mollekopf <mollekopf@kolabsys.com>
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#include "tageditwidget.h"
22
23#include <kicon.h>
24#include <klineedit.h>
25#include <klocalizedstring.h>
26#include <kmessagebox.h>
27#include <kcheckableproxymodel.h>
28
29#include <akonadi/changerecorder.h>
30#include <akonadi/tagcreatejob.h>
31#include <akonadi/tagdeletejob.h>
32#include <akonadi/tagfetchscope.h>
33#include <akonadi/tagattribute.h>
34#include "tagmodel.h"
35
36#include <QEvent>
37#include <QHBoxLayout>
38#include <QLabel>
39#include <QListWidget>
40#include <QPushButton>
41#include <QTimer>
42#include <QVBoxLayout>
43#include <QWidget>
44
45using namespace Akonadi;
46
47class TagEditWidget::Private : public QObject
48{
49 Q_OBJECT
50public:
51 Private(Akonadi::TagModel *model, QWidget *parent);
52
53public Q_SLOTS:
54 void slotTextEdited(const QString &text);
55 void slotItemEntered(const QModelIndex &index);
56 void showDeleteButton();
57 void deleteTag();
58 void slotCreateTag();
59 void slotCreateTagFinished(KJob *job);
60 void onRowsInserted(const QModelIndex &parent, int start, int end);
61
62public:
63 void select(const QModelIndex &parent, int start, int end, QItemSelectionModel::SelectionFlag selectionFlag);
64 enum ItemType {
65 UrlTag = Qt::UserRole + 1
66 };
67
68 QWidget *d;
69 Akonadi::Tag::List m_tags;
70 Akonadi::TagModel *m_model;
71 QListView *m_tagsView;
72 KCheckableProxyModel *m_checkableProxy;
73 QModelIndex m_deleteCandidate;
74 QPushButton *m_newTagButton;
75 KLineEdit *m_newTagEdit;
76
77 QPushButton *m_deleteButton;
78 QTimer *m_deleteButtonTimer;
79};
80
81TagEditWidget::Private::Private(Akonadi::TagModel *model, QWidget *parent)
82 : QObject()
83 , d(parent)
84 , m_model(model)
85 , m_tagsView(0)
86 , m_newTagButton(0)
87 , m_newTagEdit(0)
88 , m_deleteButton(0)
89 , m_deleteButtonTimer(0)
90{
91
92}
93
94void TagEditWidget::Private::select(const QModelIndex &parent, int start, int end, QItemSelectionModel::SelectionFlag selectionFlag)
95{
96 QItemSelection selection;
97 for (int i = start; i <= end; i++) {
98 const QModelIndex index = m_model->index(i, 0, parent);
99 const Akonadi::Tag insertedTag = index.data(Akonadi::TagModel::TagRole).value<Akonadi::Tag>();
100 if (m_tags.contains(insertedTag)) {
101 selection.select(index, index);
102 }
103 }
104 m_checkableProxy->selectionModel()->select(selection, selectionFlag);
105}
106
107void TagEditWidget::Private::onRowsInserted(const QModelIndex &parent, int start, int end)
108{
109 select(parent, start, end, QItemSelectionModel::Select);
110}
111
112void TagEditWidget::Private::slotCreateTag()
113{
114 if (m_newTagButton->isEnabled()) {
115 Akonadi::TagCreateJob *createJob = new Akonadi::TagCreateJob(Akonadi::Tag(m_newTagEdit->text()), this);
116 connect(createJob, SIGNAL(finished(KJob*)),
117 this, SLOT(slotCreateTagFinished(KJob*)));
118
119 m_newTagEdit->clear();
120 m_newTagEdit->setEnabled(false);
121 m_newTagButton->setEnabled(false);
122 }
123}
124
125void TagEditWidget::Private::slotCreateTagFinished(KJob *job)
126{
127 if (job->error()) {
128 KMessageBox::error(d, i18n("An error occurred while creating a new tag"),
129 i18n("Failed to create a new tag"));
130 }
131
132 m_newTagEdit->setEnabled(true);
133}
134
135void TagEditWidget::Private::slotTextEdited(const QString &text)
136{
137 // Remove unnecessary spaces from a new tag is
138 // mandatory, as the user cannot see the difference
139 // between a tag "Test" and "Test ".
140 const QString tagText = text.simplified();
141 if (tagText.isEmpty()) {
142 m_newTagButton->setEnabled(false);
143 return;
144 }
145
146 // Check whether the new tag already exists
147 const int count = m_model->rowCount();
148 bool exists = false;
149 for (int i = 0; i < count; ++i) {
150 const QModelIndex index = m_model->index(i, 0, QModelIndex());
151 if (index.data(Qt::DisplayRole).toString() == tagText) {
152 exists = true;
153 break;
154 }
155 }
156 m_newTagButton->setEnabled(!exists);
157}
158
159void TagEditWidget::Private::slotItemEntered(const QModelIndex &index)
160{
161 // align the delete-button to stay on the right border
162 // of the item
163 const QRect rect = m_tagsView->visualRect(index);
164 const int size = rect.height();
165 const int x = rect.right() - size;
166 const int y = rect.top();
167 m_deleteButton->move(x, y);
168 m_deleteButton->resize(size, size);
169
170 m_deleteCandidate = index;
171 m_deleteButtonTimer->start();
172}
173
174void TagEditWidget::Private::showDeleteButton()
175{
176 m_deleteButton->show();
177}
178
179void TagEditWidget::Private::deleteTag()
180{
181 Q_ASSERT(m_deleteCandidate.isValid());
182 const Akonadi::Tag tag = m_deleteCandidate.data(Akonadi::TagModel::TagRole).value<Akonadi::Tag>();
183 const QString text = i18nc("@info",
184 "Do you really want to remove the tag <resource>%1</resource>?",
185 tag.name());
186 const QString caption = i18nc("@title", "Delete tag");
187 const KGuiItem deleteItem(i18nc("@action:button", "Delete"), KIcon(QLatin1String("edit-delete")));
188 const KGuiItem cancelItem(i18nc("@action:button", "Cancel"), KIcon(QLatin1String("dialog-cancel")));
189 if (KMessageBox::warningYesNo(d, text, caption, deleteItem, cancelItem) == KMessageBox::Yes) {
190 new Akonadi::TagDeleteJob(tag, this);
191 }
192}
193
194TagEditWidget::TagEditWidget(Akonadi::TagModel *model, QWidget *parent, bool enableSelection)
195 : QWidget(parent)
196 , d(new Private(model, this))
197{
198 QVBoxLayout *topLayout = new QVBoxLayout(this);
199
200 QItemSelectionModel *selectionModel = new QItemSelectionModel(d->m_model, this);
201 d->m_checkableProxy = new KCheckableProxyModel(this);
202 d->m_checkableProxy->setSourceModel(d->m_model);
203 d->m_checkableProxy->setSelectionModel(selectionModel);
204 connect(d->m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), d.data(), SLOT(onRowsInserted(QModelIndex,int,int)));
205
206 d->m_tagsView = new QListView(this);
207 d->m_tagsView->setMouseTracking(true);
208 d->m_tagsView->setSelectionMode(QAbstractItemView::NoSelection);
209 d->m_tagsView->installEventFilter(this);
210 if (enableSelection) {
211 d->m_tagsView->setModel(d->m_checkableProxy);
212 } else {
213 d->m_tagsView->setModel(d->m_model);
214 }
215 connect(d->m_tagsView, SIGNAL(entered(QModelIndex)),
216 d.data(), SLOT(slotItemEntered(QModelIndex)));
217
218 d->m_newTagEdit = new KLineEdit(this);
219 d->m_newTagEdit->setTrapReturnKey(true);
220 d->m_newTagEdit->setClearButtonShown(true);
221 connect(d->m_newTagEdit, SIGNAL(textEdited(QString)),
222 d.data(), SLOT(slotTextEdited(QString)));
223 connect(d->m_newTagEdit, SIGNAL(returnPressed()),
224 d.data(), SLOT(slotCreateTag()));
225
226 d->m_newTagButton = new QPushButton(i18nc("@label", "Create new tag"));
227 d->m_newTagButton->setEnabled(false);
228 connect(d->m_newTagButton , SIGNAL(clicked(bool)),
229 d.data(), SLOT(slotCreateTag()));
230
231 QHBoxLayout *newTagLayout = new QHBoxLayout();
232 newTagLayout->addWidget(d->m_newTagEdit, 1);
233 newTagLayout->addWidget(d->m_newTagButton);
234
235 if (enableSelection) {
236 QLabel *label = new QLabel(i18nc("@label:textbox",
237 "Configure which tags should "
238 "be applied."), this);
239 topLayout->addWidget(label);
240 }
241 topLayout->addWidget(d->m_tagsView);
242 topLayout->addLayout(newTagLayout);
243
244 setLayout(topLayout);
245
246 // create the delete button, which is shown when
247 // hovering the items
248 d->m_deleteButton = new QPushButton(d->m_tagsView->viewport());
249 d->m_deleteButton->setIcon(KIcon(QLatin1String("edit-delete")));
250 d->m_deleteButton->setToolTip(i18nc("@info", "Delete tag"));
251 d->m_deleteButton->hide();
252 connect(d->m_deleteButton, SIGNAL(clicked()), d.data(), SLOT(deleteTag()));
253
254 d->m_deleteButtonTimer = new QTimer(this);
255 d->m_deleteButtonTimer->setSingleShot(true);
256 d->m_deleteButtonTimer->setInterval(500);
257 connect(d->m_deleteButtonTimer, SIGNAL(timeout()), d.data(), SLOT(showDeleteButton()));
258}
259
260TagEditWidget::~TagEditWidget()
261{
262
263}
264
265void TagEditWidget::setSelection(const Akonadi::Tag::List &tags)
266{
267 d->m_tags = tags;
268 d->select(QModelIndex(), 0, d->m_model->rowCount() - 1, QItemSelectionModel::ClearAndSelect);
269}
270
271Akonadi::Tag::List TagEditWidget::selection() const
272{
273 Akonadi::Tag::List list;
274 for (int i = 0; i < d->m_checkableProxy->rowCount(); ++i) {
275 if (d->m_checkableProxy->selectionModel()->isRowSelected(i, QModelIndex())) {
276 const QModelIndex index = d->m_checkableProxy->index(i, 0, QModelIndex());
277 const Akonadi::Tag tag = index.data(Akonadi::TagModel::TagRole).value<Akonadi::Tag>();
278 list << tag;
279 }
280 }
281 return list;
282}
283
284bool TagEditWidget::eventFilter(QObject *watched, QEvent *event)
285{
286 if ((watched == d->m_tagsView) && (event->type() == QEvent::Leave)) {
287 d->m_deleteButtonTimer->stop();
288 d->m_deleteButton->hide();
289 }
290 return QWidget::eventFilter(watched, event);
291}
292
293#include "tageditwidget.moc"
Akonadi::TagCreateJob
Job that creates a new tag in the Akonadi storage.
Definition tagcreatejob.h:35
Akonadi::TagDeleteJob
Job that deletes tags.
Definition tagdeletejob.h:36
Akonadi::Tag
An Akonadi Tag.
Definition tag.h:44
Akonadi
FreeBusyManager::Singleton.
Definition actionstatemanager_p.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Wed Jan 24 2024 00:00:00 by doxygen 1.10.0 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
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 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