• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kaddressbook

  • sources
  • kde-4.14
  • kdepim
  • kaddressbook
categoryselectwidget.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2014 Jonathan Marten <jjm@keelhaul.me.uk>
3 
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.
8 
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.
13 
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
17  02110-1301, USA.
18 */
19 
20 #include "categoryselectwidget.h"
21 
22 #include <kicon.h>
23 #include <klocale.h>
24 #include <kdebug.h>
25 #include <kdialog.h>
26 
27 #include <qtoolbutton.h>
28 #include <qlayout.h>
29 #include <qstandarditemmodel.h>
30 #include <qtimer.h>
31 
32 #include <akonadi/monitor.h>
33 #include <akonadi/tagmodel.h>
34 
35 #include <widgets/kcheckcombobox.h>
36 
37 using namespace Akonadi;
38 
39 
40 static const int FILTER_ROLE = Qt::UserRole+1;
41 
42 
43 class CategorySelectWidgetPrivate : public QObject
44 {
45  Q_OBJECT
46  Q_DECLARE_PUBLIC(CategorySelectWidget)
47 
48 public:
49  explicit CategorySelectWidgetPrivate(CategorySelectWidget *parent);
50 
51  Akonadi::TagModel *tagModel;
52  int rowOffset;
53  QTimer *updateTimer;
54  KPIM::KCheckComboBox *checkCombo;
55 
56  void init();
57  QStandardItemModel *itemModel() const;
58  void selectAll(Qt::CheckState state) const;
59  QList<Akonadi::Tag::Id> filterTags() const;
60 
61 public slots:
62  void slotSelectAll();
63  void slotSelectNone();
64 
65  void slotTagsInserted(const QModelIndex &parent, int start, int end);
66  void slotTagsRemoved(const QModelIndex &parent, int start, int end);
67  void slotTagsChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
68 
69  void slotCheckedItemsChanged();
70  void slotCheckedItemsTimer();
71 
72 private:
73  CategorySelectWidget *q_ptr;
74 };
75 
76 
77 CategorySelectWidgetPrivate::CategorySelectWidgetPrivate(CategorySelectWidget *parent)
78  : QObject(),
79  tagModel(0),
80  rowOffset(0),
81  updateTimer(0),
82  checkCombo(0),
83  q_ptr(parent)
84 {
85 }
86 
87 
88 void CategorySelectWidgetPrivate::init()
89 {
90  Q_Q(CategorySelectWidget);
91 
92  QHBoxLayout *hbox = new QHBoxLayout(q);
93  hbox->setSpacing(0);
94 
95  checkCombo = new KPIM::KCheckComboBox;
96  checkCombo->setMinimumWidth(150);
97  checkCombo->setSqueezeText(true);
98  connect(checkCombo, SIGNAL(checkedItemsChanged(QStringList)),
99  SLOT(slotCheckedItemsChanged()));
100  hbox->addWidget(checkCombo);
101 
102  Monitor *monitor = new Monitor(this);
103  monitor->setTypeMonitored(Monitor::Tags);
104  tagModel = new Akonadi::TagModel(monitor, this);
105 
106  connect(tagModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
107  SLOT(slotTagsInserted(QModelIndex,int,int)));
108  connect(tagModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
109  SLOT(slotTagsRemoved(QModelIndex,int,int)));
110  connect(tagModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
111  SLOT(slotTagsChanged(QModelIndex,QModelIndex)));
112 
113  updateTimer = new QTimer(this);
114  updateTimer->setSingleShot(true);
115  updateTimer->setInterval(200);
116  connect(updateTimer, SIGNAL(timeout()), SLOT(slotCheckedItemsTimer()));
117 
118  hbox->addSpacing(KDialog::spacingHint());
119 
120  QToolButton *but = new QToolButton(q);
121  but ->setAutoRaise(true);
122  but->setIcon(KIcon(QLatin1String("edit-undo")));
123  but->setToolTip(i18nc("@action:button", "Reset category filter"));
124  connect(but, SIGNAL(clicked(bool)), SLOT(slotSelectAll()));
125  hbox->addWidget(but);
126 
127  but = new QToolButton(q);
128  but->setAutoRaise(true);
129  but->setIcon(KIcon(QLatin1String("edit-clear")));
130  but->setToolTip(i18nc("@action:button", "Clear category filter"));
131  connect(but, SIGNAL(clicked(bool)), SLOT(slotSelectNone()));
132  hbox->addWidget(but);
133 
134  QStandardItem *item = new QStandardItem(i18n("(Untagged)"));
135  item->setCheckState(Qt::Checked);
136  item->setData(CategorySelectWidget::FilterUntagged, FILTER_ROLE);
137  itemModel()->appendRow(item);
138 
139  item = new QStandardItem(i18n("(Groups)"));
140  item->setCheckState(Qt::Checked);
141  item->setData(CategorySelectWidget::FilterGroups, FILTER_ROLE);
142  itemModel()->appendRow(item);
143 
144  rowOffset = itemModel()->rowCount();
145 }
146 
147 
148 QStandardItemModel *CategorySelectWidgetPrivate::itemModel() const
149 {
150  QStandardItemModel *m = qobject_cast<QStandardItemModel *>(checkCombo->model());
151  Q_ASSERT(m!=NULL);
152  return m;
153 }
154 
155 
156 void CategorySelectWidgetPrivate::slotTagsRemoved(const QModelIndex &parent, int start, int end)
157 {
158  itemModel()->removeRows(start+rowOffset, end+rowOffset, parent);
159 }
160 
161 
162 void CategorySelectWidgetPrivate::slotTagsChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
163 {
164  for (int row = topLeft.row(); row<=bottomRight.row(); ++row) {
165  QStandardItem *it = itemModel()->item(row+rowOffset);
166  Q_ASSERT(it!=NULL);
167 
168  QModelIndex idx = tagModel->index(row, 0);
169  it->setText(tagModel->data(idx, TagModel::NameRole).toString());
170  it->setIcon(tagModel->data(idx, Qt::DecorationRole).value<QIcon>());
171  it->setData(tagModel->data(idx, TagModel::IdRole), FILTER_ROLE);
172  }
173 }
174 
175 
176 void CategorySelectWidgetPrivate::slotTagsInserted(const QModelIndex &parent, int start, int end)
177 {
178  for (int row = start; row<=end; ++row) {
179  QModelIndex idx = tagModel->index(row, 0, parent);
180 #if 0
181  kDebug() << "idx" << idx << "=" << tagModel->data(idx, Qt::DisplayRole).toString()
182  << "name" << tagModel->data(idx, TagModel::NameRole).toString()
183  << "tag" << tagModel->data(idx, TagModel::TagRole)
184  << "id" << tagModel->data(idx, TagModel::IdRole).toInt();
185 #endif
186  QStandardItem *it = new QStandardItem(tagModel->data(idx, TagModel::NameRole).toString());
187  it->setIcon(tagModel->data(idx, Qt::DecorationRole).value<QIcon>());
188  it->setData(tagModel->data(idx, TagModel::IdRole), FILTER_ROLE);
189  it->setCheckState(Qt::Checked);
190 
191  // If a tag with a parent arrives from the model, we know that its parent
192  // must already have arrived. So there is no need for a list of pending
193  // tags, as is required in Akonadi::TagModel.
194  //
195  // FIXME: not tested (no way to create hierarchial tags at present)
196  if (parent!=QModelIndex()) {
197  const Tag::Id parentId = tagModel->data(idx, TagModel::IdRole).value<Tag::Id>();
198  QModelIndexList matchList = itemModel()->match(itemModel()->index(0, 0), FILTER_ROLE,
199  parentId, 1,
200  Qt::MatchExactly|Qt::MatchRecursive);
201  if (matchList.count()==1) { // found the parent tag
202  QModelIndex parentIndex = matchList.first();
203  itemModel()->itemFromIndex(parentIndex)->appendRow(it);
204  } else {
205  kWarning() << "Cannot find parent with ID" << parentId;
206  itemModel()->insertRow(row+rowOffset, it);
207  }
208  } else {
209  itemModel()->insertRow(row+rowOffset, it);
210  }
211  }
212 }
213 
214 
215 void CategorySelectWidgetPrivate::selectAll(Qt::CheckState state) const
216 {
217  for (int row = 0; row<itemModel()->rowCount(); ++row) {
218  QStandardItem *it = itemModel()->item(row);
219  it->setCheckState(state);
220  }
221 }
222 
223 
224 void CategorySelectWidgetPrivate::slotSelectAll()
225 {
226  selectAll(Qt::Checked);
227 }
228 
229 
230 void CategorySelectWidgetPrivate::slotSelectNone()
231 {
232  selectAll(Qt::Unchecked);
233 }
234 
235 
236 void CategorySelectWidgetPrivate::slotCheckedItemsChanged()
237 {
238  updateTimer->start();
239 }
240 
241 
242 void CategorySelectWidgetPrivate::slotCheckedItemsTimer()
243 {
244  Q_Q(CategorySelectWidget);
245 
246  bool allOn = true;
247  for (int row = 0; row<itemModel()->rowCount(); ++row) {
248  const QStandardItem *it = itemModel()->item(row);
249  Qt::CheckState rowState = static_cast<Qt::CheckState>(it->data(Qt::CheckStateRole).toInt());
250  if (rowState!=Qt::Checked) {
251  allOn = false;
252  break;
253  }
254  }
255 
256  if (allOn) {
257  checkCombo->setAlwaysShowDefaultText(true);
258  checkCombo->setDefaultText(i18n("(All)"));
259  } else {
260  checkCombo->setAlwaysShowDefaultText(false);
261  checkCombo->setDefaultText(i18n("(None)"));
262  }
263 
264  const QStringList checkedList = checkCombo->checkedItems();
265  if (!checkedList.isEmpty()) {
266  checkCombo->setToolTip(i18n("<qt>Category filter: %1", checkedList.join(i18n(", "))));
267  } else {
268  checkCombo->setToolTip(QString());
269  }
270 
271  emit q->filterChanged(filterTags());
272 }
273 
274 
275 QList<Akonadi::Tag::Id> CategorySelectWidgetPrivate::filterTags() const
276 {
277  QList<Tag::Id> filter;
278  bool allOn = true;
279  for (int row = 0; row<itemModel()->rowCount(); ++row) {
280  const QStandardItem *it = itemModel()->item(row);
281  Q_ASSERT(it!=NULL);
282  if (it->checkState()==Qt::Checked) {
283  Tag::Id id = it->data(FILTER_ROLE).toInt();
284  if (id!=0) filter.append(id);
285  } else {
286  allOn = false;
287  }
288  }
289 
290  if (allOn) {
291  filter.clear();
292  filter.append(CategorySelectWidget::FilterAll);
293  }
294 
295  //kDebug() << "filter" << filter;
296  return filter;
297 }
298 
299 
300 CategorySelectWidget::CategorySelectWidget(QWidget *parent)
301  : QWidget(parent),
302  d_ptr(new CategorySelectWidgetPrivate(this))
303 {
304  Q_D(CategorySelectWidget);
305  d->init();
306 }
307 
308 
309 CategorySelectWidget::~CategorySelectWidget()
310 {
311  delete d_ptr;
312 }
313 
314 
315 QList<Akonadi::Tag::Id> CategorySelectWidget::filterTags() const
316 {
317  Q_D(const CategorySelectWidget);
318  return d->filterTags();
319 }
320 
321 
322 #include "categoryselectwidget.moc"
QList::clear
void clear()
QModelIndex
CategorySelectWidget::filterTags
QList< Akonadi::Tag::Id > filterTags() const
Get the current tag filter list.
Definition: categoryselectwidget.cpp:315
QStandardItemModel
QWidget
QStandardItem::setIcon
void setIcon(const QIcon &icon)
CategorySelectWidget::FilterGroups
Contact groups.
Definition: categoryselectwidget.h:60
CategorySelectWidget
A widget to specify a category (tag) filter.
Definition: categoryselectwidget.h:35
CategorySelectWidget::~CategorySelectWidget
virtual ~CategorySelectWidget()
Destructor.
Definition: categoryselectwidget.cpp:309
QStandardItemModel::removeRows
virtual bool removeRows(int row, int count, const QModelIndex &parent)
QHBoxLayout
QStringList::join
QString join(const QString &separator) const
QBoxLayout::addSpacing
void addSpacing(int size)
QAbstractButton::setIcon
void setIcon(const QIcon &icon)
QStandardItem::checkState
Qt::CheckState checkState() const
QStandardItem::setData
virtual void setData(const QVariant &value, int role)
CategorySelectWidget::CategorySelectWidget
CategorySelectWidget(QWidget *parent=0)
Constructor.
Definition: categoryselectwidget.cpp:300
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
QList::append
void append(const T &value)
categoryselectwidget.h
QTimer
QVariant::toInt
int toInt(bool *ok) const
QObject
CategorySelectWidget::FilterAll
All items.
Definition: categoryselectwidget.h:58
QList::isEmpty
bool isEmpty() const
QModelIndex::row
int row() const
QString
QList
QToolButton::setAutoRaise
void setAutoRaise(bool enable)
QStringList
QToolButton
QStandardItem::setText
void setText(const QString &text)
QModelIndex::data
QVariant data(int role) const
QLatin1String
CategorySelectWidget::FilterUntagged
Untagged items.
Definition: categoryselectwidget.h:59
QtConcurrent::filter
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
QStandardItem::setCheckState
void setCheckState(Qt::CheckState state)
FILTER_ROLE
static const int FILTER_ROLE
Definition: categoryselectwidget.cpp:40
QStandardItem
QWidget::setToolTip
void setToolTip(const QString &)
QString::data
QChar * data()
QVariant::toString
QString toString() const
QStandardItem::data
virtual QVariant data(int role) const
QBoxLayout::setSpacing
void setSpacing(int spacing)
QIcon
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:32:34 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kaddressbook

Skip menu "kaddressbook"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



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