diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index 7a45abcc6..fc8e1b3d2 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -16,6 +16,7 @@ set(sdrgui_SOURCES gui/basicfeaturesettingsdialog.cpp gui/buttonswitch.cpp gui/channeladddialog.cpp + gui/checklist.cpp gui/clickablelabel.cpp gui/colordialog.cpp gui/colormapper.cpp @@ -146,6 +147,7 @@ set(sdrgui_HEADERS gui/basicfeaturesettingsdialog.h gui/buttonswitch.h gui/channeladddialog.h + gui/checklist.h gui/colordialog.h gui/colormapper.h gui/commanditem.h diff --git a/sdrgui/gui/checklist.cpp b/sdrgui/gui/checklist.cpp new file mode 100644 index 000000000..419599523 --- /dev/null +++ b/sdrgui/gui/checklist.cpp @@ -0,0 +1,172 @@ +#include "checklist.h" + +CheckList::CheckList(QWidget* parent) : + QComboBox(parent) +{ + m_model = new QStandardItemModel(); + setModel(m_model); + + setEditable(true); + lineEdit()->setReadOnly(true); + lineEdit()->installEventFilter(this); + setItemDelegate(new QCheckListStyledItemDelegate(this)); + + connect(lineEdit(), &QLineEdit::selectionChanged, lineEdit(), &QLineEdit::deselect); + connect((QListView*) view(), SIGNAL(pressed(QModelIndex)), this, SLOT(on_itemPressed(QModelIndex))); + connect(m_model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QVector)), this, SLOT(on_modelDataChanged())); +} + +CheckList::~CheckList() +{ + delete m_model; +} + +void CheckList::setText(const QString &text) +{ + m_text = text; + updateText(); +} + +void CheckList::setAllCheckedText(const QString &text) +{ + m_allCheckedText = text; + updateText(); +} + +void CheckList::setNoneCheckedText(const QString &text) +{ + m_noneCheckedText = text; + updateText(); +} + +void CheckList::setUnknownlyCheckedText(const QString &text) +{ + m_unknownlyCheckedText = text; + updateText(); +} + +void CheckList::setSortRole(int role) +{ + m_model->setSortRole(role); +} + +QStandardItem* CheckList::addCheckItem(const QString &label, const QVariant &data, const Qt::CheckState checkState) +{ + QStandardItem* item = new QStandardItem(label); + item->setCheckState(checkState); + item->setData(data); + item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); + + m_model->appendRow(item); + + updateText(); + + return item; +} + +int CheckList::globalCheckState() +{ + int nbRows = m_model->rowCount(), nbChecked = 0, nbUnchecked = 0; + + if (nbRows == 0) + { + return StateUnknown; + } + + for (int i = 0; i < nbRows; i++) + { + if (m_model->item(i)->checkState() == Qt::Checked) + { + nbChecked++; + } + else if (m_model->item(i)->checkState() == Qt::Unchecked) + { + nbUnchecked++; + } + else + { + return StateUnknown; + } + } + + return nbChecked == nbRows ? Qt::Checked : nbUnchecked == nbRows ? Qt::Unchecked : Qt::PartiallyChecked; +} + +bool CheckList::eventFilter(QObject* _object, QEvent* _event) +{ + if (_object == lineEdit() && _event->type() == QEvent::MouseButtonPress) + { + showPopup(); + return true; + } + + return false; +} + +void CheckList::updateText() +{ + QString text; + + if (m_text.isEmpty()) + { + switch (globalCheckState()) + { + case Qt::Checked: + text = m_allCheckedText; + break; + + case Qt::Unchecked: + text = m_noneCheckedText; + break; + + case Qt::PartiallyChecked: + for (int i = 0; i < m_model->rowCount(); i++) + { + if (m_model->item(i)->checkState() == Qt::Checked) + { + if (!text.isEmpty()) + { + text+= ", "; + } + + text+= m_model->item(i)->text(); + } + } + break; + + default: + text = m_unknownlyCheckedText; + } + } + else + { + text = m_text; + } + + lineEdit()->setText(text); +} + +void CheckList::on_modelDataChanged() +{ + updateText(); + emit globalCheckStateChanged(globalCheckState()); +} + +void CheckList::on_itemPressed(const QModelIndex &index) +{ + QStandardItem* item = m_model->itemFromIndex(index); + + if (item->checkState() == Qt::Checked) + { + item->setCheckState(Qt::Unchecked); + } + else + { + item->setCheckState(Qt::Checked); + } +} + +bool CheckList::isChecked(int index) const +{ + return m_model->item(index)->checkState() == Qt::Checked; +} diff --git a/sdrgui/gui/checklist.h b/sdrgui/gui/checklist.h new file mode 100644 index 000000000..08b8c732f --- /dev/null +++ b/sdrgui/gui/checklist.h @@ -0,0 +1,105 @@ +#ifndef CHECKLIST +#define CHECKLIST + +#include +#include +#include +#include +#include +#include +#include + +#include "export.h" + +/** +* @brief QComboBox with support of checkboxes +* http://stackoverflow.com/questions/8422760/combobox-of-checkboxes +*/ +class SDRGUI_API CheckList : public QComboBox +{ + Q_OBJECT + +public: + /** + * @brief Additional value to Qt::CheckState when some checkboxes are Qt::PartiallyChecked + */ + static const int StateUnknown = 3; + +private: + QStandardItemModel* m_model; + /** + * @brief Text to display regardless of what is checked + */ + QString m_text; + /** + * @brief Text displayed when no item is checked + */ + QString m_noneCheckedText; + /** + * @brief Text displayed when all items are checked + */ + QString m_allCheckedText; + /** + * @brief Text displayed when some items are partially checked + */ + QString m_unknownlyCheckedText; + +signals: + void globalCheckStateChanged(int); + +public: + CheckList(QWidget* parent = nullptr); + ~CheckList(); + + void setText(const QString &text); + void setAllCheckedText(const QString &text); + void setNoneCheckedText(const QString &text); + void setUnknownlyCheckedText(const QString &text); + + bool isChecked(int index) const; + + void setSortRole(int role); + + /** + * @brief Adds a item to the checklist + * @return the new QStandardItem + */ + QStandardItem* addCheckItem(const QString &label, const QVariant &data, const Qt::CheckState checkState); + + /** + * @brief Computes the global state of the checklist : + * - if there is no item: StateUnknown + * - if there is at least one item partially checked: StateUnknown + * - if all items are checked: Qt::Checked + * - if no item is checked: Qt::Unchecked + * - else: Qt::PartiallyChecked + */ + int globalCheckState(); + +protected: + bool eventFilter(QObject* _object, QEvent* _event); + +private: + void updateText(); + +private slots: + void on_modelDataChanged(); + + void on_itemPressed(const QModelIndex &index); + +public: + class QCheckListStyledItemDelegate : public QStyledItemDelegate + { + public: + QCheckListStyledItemDelegate(QObject* parent = 0) : QStyledItemDelegate(parent) {} + + void paint(QPainter * painter_, const QStyleOptionViewItem & option_, const QModelIndex & index_) const + { + QStyleOptionViewItem & refToNonConstOption = const_cast(option_); + refToNonConstOption.showDecorationSelected = false; + QStyledItemDelegate::paint(painter_, refToNonConstOption, index_); + } + }; +}; + +#endif