1 /****************************************************************************
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
5 ** This file is part of the QxtGui module of the Qt eXTension library
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
21 ** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
23 ****************************************************************************/
24 #include "qxtcheckcombobox.h"
25 #include "qxtcheckcombobox_p.h"
26 #include <QStyleOptionButton>
27 #include <QMouseEvent>
31 QxtCheckComboBoxPrivate::QxtCheckComboBoxPrivate()
33 separator = QLatin1String(",");
36 void QxtCheckComboBoxPrivate::hidePopup()
41 void QxtCheckComboBoxPrivate::updateCheckedItems()
44 for (int i = 0; i < qxt_p().model()->rowCount(); ++i)
46 const QModelIndex& index = qxt_p().model()->index(i, 0);
47 const QVariant& data = index.data(Qt::CheckStateRole);
48 const Qt::CheckState state = static_cast<Qt::CheckState>(data.toInt());
49 if (state == Qt::Checked)
51 checkedItems += index.data().toString();
55 if (checkedItems.count() > 0)
56 qxt_p().lineEdit()->setText(checkedItems.join(separator));
58 qxt_p().lineEdit()->setText(defaultText);
60 // TODO: find a way to recalculate a meaningful size hint
62 emit qxt_p().checkedItemsChanged(checkedItems);
65 QxtCheckComboView::QxtCheckComboView(QWidget* parent)
66 : QListView(parent), mode(QxtCheckComboBox::CheckIndicator)
69 QxtCheckComboView::~QxtCheckComboView()
72 bool QxtCheckComboView::eventFilter(QObject* object, QEvent* event)
75 if (event->type() == QEvent::MouseButtonRelease)
77 QMouseEvent* mouse = static_cast<QMouseEvent*>(event);
78 const QModelIndex& index = indexAt(mouse->pos());
84 case QxtCheckComboBox::CheckIndicator:
85 change = handleIndicatorRelease(mouse, index);
88 case QxtCheckComboBox::CheckWholeItem:
89 change = handleItemRelease(mouse, index);
93 qWarning("QxtCheckComboView::eventFilter(): unknown mode");
99 // the check state is about to change, bypass
100 // combobox and deliver the event just for the listview
101 QListView::mouseReleaseEvent(mouse);
105 // otherwise it's ok to close
106 emit hideRequested();
114 bool QxtCheckComboView::handleIndicatorRelease(QMouseEvent* event, const QModelIndex& index)
116 // check if the mouse was released over the checkbox
117 QStyleOptionButton option;
118 option.QStyleOption::operator=(viewOptions());
119 option.rect = visualRect(index);
120 const QRect& rect = style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &option);
121 return rect.contains(event->pos());
124 bool QxtCheckComboView::handleItemRelease(QMouseEvent* event, const QModelIndex& index)
126 // check if the mouse was released outside the checkbox
127 QStyleOptionButton option;
128 option.QStyleOption::operator=(viewOptions());
129 option.rect = visualRect(index);
130 const QRect& rect = style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &option);
131 if (!rect.contains(event->pos()))
133 Qt::CheckState state = (Qt::CheckState) index.data(Qt::CheckStateRole).toInt();
141 state = Qt::Unchecked;
145 qWarning("QxtCheckComboView::handleItemRelease(): partially checked item");
148 model()->setData(index, state, Qt::CheckStateRole);
153 QxtCheckComboModel::QxtCheckComboModel(QObject* parent)
154 : QStandardItemModel(0, 1, parent) // rows,cols
158 QxtCheckComboModel::~QxtCheckComboModel()
161 Qt::ItemFlags QxtCheckComboModel::flags(const QModelIndex& index) const
163 return QStandardItemModel::flags(index) | Qt::ItemIsUserCheckable;
166 QVariant QxtCheckComboModel::data(const QModelIndex& index, int role) const
168 QVariant value = QStandardItemModel::data(index, role);
169 if (role == Qt::CheckStateRole && !value.isValid())
170 value = Qt::Unchecked;
174 bool QxtCheckComboModel::setData(const QModelIndex& index, const QVariant& value, int role)
176 bool ok = QStandardItemModel::setData(index, value, role);
179 if (role == Qt::CheckStateRole)
181 emit checkStateChanged();
188 \class QxtCheckComboBox QxtCheckComboBox
190 \brief An extended QComboBox with checkable items.
192 QxtComboBox is a specialized combo box with checkable items.
193 Checked items are collected together in the line edit.
195 \image html qxtcheckcombobox.png "QxtCheckComboBox in Plastique style."
199 \enum QxtCheckComboBox::CheckMode
201 This enum describes the check mode.
203 \sa QxtCheckComboBox::checkMode
207 \var QxtCheckComboBox::CheckMode QxtCheckComboBox::CheckIndicator
209 The check state changes only via the check indicator (like in item views).
213 \var QxtCheckComboBox::CheckMode QxtCheckComboBox::CheckWholeItem
215 The check state changes via the whole item (like with a combo box).
219 \fn QxtCheckComboBox::checkedItemsChanged(const QStringList& items)
221 This signal is emitted whenever the checked items have been changed.
225 Constructs a new QxtCheckComboBox with \a parent.
227 QxtCheckComboBox::QxtCheckComboBox(QWidget* parent) : QComboBox(parent)
229 QXT_INIT_PRIVATE(QxtCheckComboBox);
230 QxtCheckComboModel* model = new QxtCheckComboModel(this);
231 QxtCheckComboView* view = new QxtCheckComboView(this);
236 // these 2 lines below are important and must be
237 // applied AFTER QComboBox::setView() because
238 // QComboBox installs its own filter on the view
239 view->installEventFilter(view); // <--- !!!
240 view->viewport()->installEventFilter(view); // <--- !!!
242 // read-only contents
243 QLineEdit* lineEdit = new QLineEdit(this);
244 lineEdit->setReadOnly(true);
245 setLineEdit(lineEdit);
247 connect(view, SIGNAL(hideRequested()), &qxt_d(), SLOT(hidePopup()));
248 connect(model, SIGNAL(checkStateChanged()), &qxt_d(), SLOT(updateCheckedItems()));
249 QTimer::singleShot(0, &qxt_d(), SLOT(updateCheckedItems()));
253 Destructs the combo box.
255 QxtCheckComboBox::~QxtCheckComboBox()
259 Returns the check state of the item at \a index.
261 Qt::CheckState QxtCheckComboBox::itemCheckState(int index) const
263 return static_cast<Qt::CheckState>(itemData(index, Qt::CheckStateRole).toInt());
267 Sets the check state of the item at \a index to \a state.
269 void QxtCheckComboBox::setItemCheckState(int index, Qt::CheckState state)
271 setItemData(index, state, Qt::CheckStateRole);
275 \property QxtCheckComboBox::checkedItems
276 \brief This property holds the checked items.
278 QStringList QxtCheckComboBox::checkedItems() const
280 return qxt_d().checkedItems;
283 void QxtCheckComboBox::setCheckedItems(const QStringList& items)
285 // not the most efficient solution but most likely nobody
286 // will put too many items into a combo box anyway so...
287 foreach (const QString& text, items)
289 const int index = findText(text);
290 setItemCheckState(index, index != -1 ? Qt::Checked : Qt::Unchecked);
295 \property QxtCheckComboBox::defaultText
296 \brief This property holds the default text.
298 The default text is shown when there are no checked items.
299 The default value is an empty string.
301 QString QxtCheckComboBox::defaultText() const
303 return qxt_d().defaultText;
306 void QxtCheckComboBox::setDefaultText(const QString& text)
308 if (qxt_d().defaultText != text)
310 qxt_d().defaultText = text;
311 qxt_d().updateCheckedItems();
316 \property QxtCheckComboBox::separator
317 \brief This property holds the default separator.
319 The checked items are joined together with the separator string.
320 The default value is a comma (",").
322 QString QxtCheckComboBox::separator() const
324 return qxt_d().separator;
327 void QxtCheckComboBox::setSeparator(const QString& separator)
329 if (qxt_d().separator != separator)
331 qxt_d().separator = separator;
332 qxt_d().updateCheckedItems();
337 \property QxtCheckComboBox::checkMode
338 \brief This property holds the check mode.
340 The check mode describes item checking behaviour.
341 The default value is \b QxtCheckComboBox::CheckIndicator.
343 \sa QxtCheckComboBox::CheckMode
345 QxtCheckComboBox::CheckMode QxtCheckComboBox::checkMode() const
347 return qxt_d().view->mode;
350 void QxtCheckComboBox::setCheckMode(QxtCheckComboBox::CheckMode mode)
352 if (qxt_d().view->mode != mode)
354 qxt_d().view->mode = mode;
358 void QxtCheckComboBox::keyPressEvent(QKeyEvent* event)
360 if (event->key() != Qt::Key_Up && event->key() != Qt::Key_Down)
362 QComboBox::keyPressEvent(event);
370 void QxtCheckComboBox::keyReleaseEvent(QKeyEvent* event)
372 if (event->key() != Qt::Key_Up && event->key() != Qt::Key_Down)
374 QComboBox::keyReleaseEvent(event);