Skip to content

Commit 638dbca

Browse files
committedApr 8, 2017
[FEATURE] new custom widget — combobox with checkable items
1 parent 61137dc commit 638dbca

File tree

3 files changed

+413
-0
lines changed

3 files changed

+413
-0
lines changed
 

‎src/gui/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ SET(QGIS_GUI_SRCS
172172
qgsbrowsertreeview.cpp
173173
qgsbusyindicatordialog.cpp
174174
qgscharacterselectdialog.cpp
175+
qgscheckablecombobox.cpp
175176
qgscodeeditor.cpp
176177
qgscodeeditorcss.cpp
177178
qgscodeeditorhtml.cpp
@@ -329,6 +330,7 @@ SET(QGIS_GUI_MOC_HDRS
329330
qgsbrowsertreeview.h
330331
qgsbusyindicatordialog.h
331332
qgscharacterselectdialog.h
333+
qgscheckablecombobox.h
332334
qgscodeeditor.h
333335
qgscodeeditorcss.h
334336
qgscodeeditorhtml.h

‎src/gui/qgscheckablecombobox.cpp

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/***************************************************************************
2+
qgscheckablecombobox.cpp
3+
------------------------
4+
begin : March 21, 2017
5+
copyright : (C) 2017 by Alexander Bruy
6+
email : alexander dot bruy at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgscheckablecombobox.h"
19+
20+
#include <QLineEdit>
21+
#include <QAbstractItemView>
22+
23+
24+
QgsCheckableItemModel::QgsCheckableItemModel( QObject *parent )
25+
: QStandardItemModel( 0, 1, parent )
26+
{
27+
}
28+
29+
Qt::ItemFlags QgsCheckableItemModel::flags( const QModelIndex &index ) const
30+
{
31+
return QStandardItemModel::flags( index ) | Qt::ItemIsUserCheckable;
32+
}
33+
34+
QVariant QgsCheckableItemModel::data( const QModelIndex &index, int role ) const
35+
{
36+
QVariant value = QStandardItemModel::data( index, role );
37+
38+
if ( index.isValid() && role == Qt::CheckStateRole && !value.isValid() )
39+
{
40+
value = Qt::Unchecked;
41+
}
42+
43+
return value;
44+
}
45+
46+
bool QgsCheckableItemModel::setData( const QModelIndex &index, const QVariant &value, int role )
47+
{
48+
bool ok = QStandardItemModel::setData( index, value, role );
49+
50+
if ( ok && role == Qt::CheckStateRole )
51+
{
52+
emit dataChanged( index, index );
53+
emit itemCheckStateChanged();
54+
}
55+
56+
return ok;
57+
}
58+
59+
60+
QgsCheckBoxDelegate::QgsCheckBoxDelegate( QObject *parent )
61+
: QStyledItemDelegate( parent )
62+
{
63+
}
64+
65+
void QgsCheckBoxDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
66+
{
67+
QStyleOptionViewItem &nonConstOpt = const_cast<QStyleOptionViewItem &>( option );
68+
nonConstOpt.showDecorationSelected = false;
69+
QStyledItemDelegate::paint( painter, nonConstOpt, index );
70+
}
71+
72+
73+
QgsCheckableComboBox::QgsCheckableComboBox( QWidget *parent )
74+
: QComboBox( parent )
75+
, mSeparator( ", " )
76+
, mDefaultText( "" )
77+
{
78+
setModel( new QgsCheckableItemModel( this ) );
79+
setItemDelegate( new QgsCheckBoxDelegate( this ) );
80+
81+
QLineEdit *lineEdit = new QLineEdit( this );
82+
lineEdit->setReadOnly( true );
83+
setLineEdit( lineEdit );
84+
85+
QgsCheckableItemModel *myModel = qobject_cast<QgsCheckableItemModel *>( model() );
86+
connect( myModel, &QgsCheckableItemModel::itemCheckStateChanged, this, &QgsCheckableComboBox::updateCheckedItems );
87+
connect( model(), &QStandardItemModel::rowsInserted, this, [ = ]( const QModelIndex &, int, int ) { updateCheckedItems(); } );
88+
connect( model(), &QStandardItemModel::rowsRemoved, this, [ = ]( const QModelIndex &, int, int ) { updateCheckedItems(); } );
89+
90+
connect( this, static_cast< void ( QComboBox::* )( int ) >( &QComboBox::activated ), this, &QgsCheckableComboBox::toggleItemCheckState );
91+
}
92+
93+
QString QgsCheckableComboBox::separator() const
94+
{
95+
return mSeparator;
96+
}
97+
98+
void QgsCheckableComboBox::setSeparator( const QString &separator )
99+
{
100+
if ( mSeparator != separator )
101+
{
102+
mSeparator = separator;
103+
updateDisplayText();
104+
}
105+
}
106+
107+
QString QgsCheckableComboBox::defaultText() const
108+
{
109+
return mDefaultText;
110+
}
111+
112+
void QgsCheckableComboBox::setDefaultText( const QString &text )
113+
{
114+
if ( mDefaultText != text )
115+
{
116+
mDefaultText = text;
117+
updateDisplayText();
118+
}
119+
}
120+
121+
QStringList QgsCheckableComboBox::checkedItems() const
122+
{
123+
QStringList items;
124+
125+
if ( model() )
126+
{
127+
QModelIndex index = model()->index( 0, modelColumn(), rootModelIndex() );
128+
QModelIndexList indexes = model()->match( index, Qt::CheckStateRole, Qt::Checked, -1, Qt::MatchExactly );
129+
Q_FOREACH ( const QModelIndex &index, indexes )
130+
{
131+
items += index.data().toString();
132+
}
133+
}
134+
135+
return items;
136+
}
137+
138+
Qt::CheckState QgsCheckableComboBox::itemCheckState( int index ) const
139+
{
140+
return static_cast<Qt::CheckState>( itemData( index, Qt::CheckStateRole ).toInt() );
141+
}
142+
143+
void QgsCheckableComboBox::setItemCheckState( int index, Qt::CheckState state )
144+
{
145+
setItemData( index, state, Qt::CheckStateRole );
146+
}
147+
148+
void QgsCheckableComboBox::toggleItemCheckState( int index )
149+
{
150+
QVariant value = itemData( index, Qt::CheckStateRole );
151+
if ( value.isValid() )
152+
{
153+
Qt::CheckState state = static_cast<Qt::CheckState>( value.toInt() );
154+
setItemData( index, ( state == Qt::Unchecked ? Qt::Checked : Qt::Unchecked ), Qt::CheckStateRole );
155+
}
156+
}
157+
158+
void QgsCheckableComboBox::hidePopup()
159+
{
160+
if ( !view()->underMouse() )
161+
{
162+
QComboBox::hidePopup();
163+
}
164+
}
165+
166+
void QgsCheckableComboBox::setCheckedItems( const QStringList &items )
167+
{
168+
Q_FOREACH ( const QString &text, items )
169+
{
170+
const int index = findText( text );
171+
setItemCheckState( index, index != -1 ? Qt::Checked : Qt::Unchecked );
172+
}
173+
}
174+
175+
void QgsCheckableComboBox::resizeEvent( QResizeEvent *event )
176+
{
177+
QComboBox::resizeEvent( event );
178+
updateDisplayText();
179+
}
180+
181+
void QgsCheckableComboBox::updateCheckedItems()
182+
{
183+
QStringList items = checkedItems();
184+
updateDisplayText();
185+
emit checkedItemsChanged( items );
186+
}
187+
188+
void QgsCheckableComboBox::updateDisplayText()
189+
{
190+
QString text;
191+
QStringList items = checkedItems();
192+
if ( items.isEmpty() )
193+
{
194+
text = mDefaultText;
195+
}
196+
else
197+
{
198+
text = items.join( mSeparator );
199+
}
200+
201+
QRect rect = lineEdit()->rect();
202+
QFontMetrics fontMetrics( font() );
203+
text = fontMetrics.elidedText( text, Qt::ElideRight, rect.width() );
204+
setEditText( text );
205+
}

‎src/gui/qgscheckablecombobox.h

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/***************************************************************************
2+
qgscheckablecombobox.h
3+
------------------------
4+
begin : March 21, 2017
5+
copyright : (C) 2017 by Alexander Bruy
6+
email : alexander dot bruy at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSCHECKABLECOMBOBOX_H
19+
#define QGSCHECKABLECOMBOBOX_H
20+
21+
#include <QComboBox>
22+
#include <QStandardItemModel>
23+
#include <QStyledItemDelegate>
24+
25+
#include "qgis_gui.h"
26+
27+
/** \class QgsCheckableItemModel
28+
* \ingroup gui
29+
* QStandardItemModel subclass which makes all items checkable
30+
* by default.
31+
* @note added in QGIS 3.0
32+
* @note not available in Python bindings
33+
**/
34+
class GUI_EXPORT QgsCheckableItemModel : public QStandardItemModel
35+
{
36+
Q_OBJECT
37+
38+
public:
39+
40+
/** Constructor for QgsCheckableItemModel.
41+
* @param parent parent object
42+
*/
43+
QgsCheckableItemModel( QObject *parent = nullptr );
44+
45+
/** Returns a combination of the item flags: items are enabled
46+
* (ItemIsEnabled), selectable (ItemIsSelectable) and checkable
47+
* (ItemIsUserCheckable).
48+
* @param index item index
49+
*/
50+
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
51+
52+
/** Returns the data stored under the given role for the item
53+
* referred to by the index.
54+
* @param index item index
55+
* @param role data role
56+
*/
57+
virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const;
58+
59+
/** Sets the role data for the item at index to value.
60+
* @param index item index
61+
* @param value data value
62+
* @param role data role
63+
* @returns true on success, false otherwise
64+
*/
65+
virtual bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole );
66+
67+
signals:
68+
69+
/** This signal is emitted whenever the items checkstate has changed.
70+
*/
71+
void itemCheckStateChanged();
72+
};
73+
74+
75+
/** \class QgsCheckBoxDelegate
76+
* \ingroup gui
77+
* QStyledItemDelegate subclass for QgsCheckableComboBox. Needed for
78+
* correct drawing of the checkable items on Mac and GTK.
79+
* @note added in QGIS 3.0
80+
* @note not available in Python bindings
81+
**/
82+
83+
class GUI_EXPORT QgsCheckBoxDelegate : public QStyledItemDelegate
84+
{
85+
Q_OBJECT
86+
87+
public:
88+
89+
/** Constructor for QgsCheckBoxDelegate.
90+
* @param parent parent object
91+
*/
92+
QgsCheckBoxDelegate( QObject *parent = nullptr );
93+
94+
/** Renders the delegate using the given painter and style option
95+
* for the item specified by index.
96+
* @param painter painter to use
97+
* @param option style option
98+
* @param index item index
99+
*/
100+
virtual void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const;
101+
};
102+
103+
104+
/** \class QgsCheckableComboBox
105+
* \ingroup gui
106+
* QComboBox subclass which allows selecting multiple items.
107+
* @note added in QGIS 3.0
108+
**/
109+
110+
class GUI_EXPORT QgsCheckableComboBox : public QComboBox
111+
{
112+
Q_OBJECT
113+
114+
Q_PROPERTY( QString separator READ separator WRITE setSeparator )
115+
Q_PROPERTY( QString defaultText READ defaultText WRITE setDefaultText )
116+
Q_PROPERTY( QStringList checkedItems READ checkedItems WRITE setCheckedItems )
117+
118+
public:
119+
120+
/** Constructor for QgsCheckableComboBox.
121+
* @param parent parent object
122+
*/
123+
QgsCheckableComboBox( QWidget *parent = nullptr );
124+
125+
/** Returns separator used to separate items in the display text.
126+
* @see setSeparator()
127+
*/
128+
QString separator() const;
129+
130+
/** Set separator used to separate items in the display text.
131+
* @param separator separator to use
132+
* @see separator()
133+
*/
134+
void setSeparator( const QString &separator );
135+
136+
/** Returns default text which will be displayed in the widget
137+
* when no items selected.
138+
* @see setDefaultText()
139+
*/
140+
QString defaultText() const;
141+
142+
/** Set default text which will be displayed in the widget when
143+
* no items selected.
144+
* @param text default text
145+
* @see defaultText()
146+
*/
147+
void setDefaultText( const QString &text );
148+
149+
/** Returns currently checked items.
150+
* @see setCheckedItems()
151+
*/
152+
QStringList checkedItems() const;
153+
154+
/** Returns the checked state of the item identified by index
155+
* @param index item index
156+
* @see setItemCheckState()
157+
* @see toggleItemCheckState()
158+
*/
159+
Qt::CheckState itemCheckState( int index ) const;
160+
161+
/** Sets the item check state to state
162+
* @param index item index
163+
* @param state check state
164+
* @see itemCheckState()
165+
* @see toggleItemCheckState()
166+
*/
167+
void setItemCheckState( int index, Qt::CheckState state );
168+
169+
/** Toggles the item check state
170+
* @param index item index
171+
* @see itemCheckState()
172+
* @see setItemCheckState()
173+
*/
174+
void toggleItemCheckState( int index );
175+
176+
/** Hides the list of items in the combobox if it is currently
177+
* visible and resets the internal state.
178+
*/
179+
virtual void hidePopup();
180+
181+
signals:
182+
183+
/** This signal is emitted whenever the checked items list changed.
184+
*/
185+
void checkedItemsChanged( const QStringList &items );
186+
187+
public slots:
188+
189+
/** Set items which should be checked/selected.
190+
* @param items items to select
191+
* @see checkedItems()
192+
*/
193+
void setCheckedItems( const QStringList &items );
194+
195+
protected:
196+
virtual void resizeEvent( QResizeEvent *event );
197+
198+
private:
199+
void updateCheckedItems();
200+
void updateDisplayText();
201+
202+
QString mSeparator;
203+
QString mDefaultText;
204+
};
205+
206+
#endif // QGSCHECKABLECOMBOBOX_H

0 commit comments

Comments
 (0)
Please sign in to comment.