From 76b76f2723d9709133ce9a7be057b092609096ba Mon Sep 17 00:00:00 2001 From: Alexander Drozdov Date: Mon, 10 Oct 2016 09:49:46 +1000 Subject: [PATCH] CMakeProjectManager: Support drop down selector for options CMake provides "hack" for cmake-gui, that allows set options variants and select then from drop down list. Allows Qt Creator re-use this solution. See: - https://blog.kitware.com/constraining-values-with-comboboxes-in-cmake-cmake-gui/ - http://blog.bethcodes.com/cmake-tips-tricks-drop-down-list Drop down values can be added to option via: SET_PROPERTY(CACHE OptionName PROPERTY STRINGS Option1 Option2 Option3) This solution should not restrict to provide any other value, it provides only suggestion for user to select one of prdefined values. Change-Id: I8fc52155775f1e04979db8206bb42363df9359e8 Reviewed-by: Tobias Hunger --- .../cmakeprojectmanager/builddirmanager.cpp | 10 +++ .../cmakebuildconfiguration.cpp | 2 + .../cmakebuildsettingswidget.cpp | 2 + .../cmakeprojectmanager/cmakeconfigitem.cpp | 2 +- .../cmakeprojectmanager/cmakeconfigitem.h | 1 + .../cmakeprojectmanager.pro | 6 +- .../cmakeprojectmanager.qbs | 4 +- .../cmakeprojectmanager/configmodel.cpp | 17 ++-- src/plugins/cmakeprojectmanager/configmodel.h | 9 ++- .../configmodelitemdelegate.cpp | 78 +++++++++++++++++++ .../configmodelitemdelegate.h | 37 +++++++++ 11 files changed, 158 insertions(+), 10 deletions(-) create mode 100644 src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp create mode 100644 src/plugins/cmakeprojectmanager/configmodelitemdelegate.h diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index 266b6512bb1..5dfcf666fe7 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -794,6 +794,7 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile } QSet advancedSet; + QMap valuesMap; QByteArray documentation; while (!cache.atEnd()) { const QByteArray line = trimCMakeCacheLine(cache.readLine()); @@ -817,6 +818,8 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile if (key.endsWith("-ADVANCED") && value == "1") { advancedSet.insert(key.left(key.count() - 9 /* "-ADVANCED" */)); + } else if (key.endsWith("-STRINGS") && fromByteArray(type) == CMakeConfigItem::INTERNAL) { + valuesMap[key.left(key.count() - 8) /* "-STRINGS" */] = value; } else { CMakeConfigItem::Type t = fromByteArray(type); result << CMakeConfigItem(key, t, documentation, value); @@ -827,6 +830,13 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile for (int i = 0; i < result.count(); ++i) { CMakeConfigItem &item = result[i]; item.isAdvanced = advancedSet.contains(item.key); + + if (valuesMap.contains(item.key)) { + item.values = CMakeConfigItem::cmakeSplitValue(QString::fromUtf8(valuesMap[item.key])); + } else if (item.key == "CMAKE_BUILD_TYPE") { + // WA for known options + item.values << "" << "Debug" << "Release" << "MinSizeRel" << "RelWithDebInfo"; + } } Utils::sort(result, CMakeConfigItem::sortOperator()); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 6cdde4147c5..c5d6bdafc4b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -245,6 +245,7 @@ QList CMakeBuildConfiguration::completeCMakeConfiguration j.key = QString::fromUtf8(i.key); j.value = QString::fromUtf8(i.value); j.description = QString::fromUtf8(i.documentation); + j.values = i.values; j.isAdvanced = i.isAdvanced || i.type == CMakeConfigItem::INTERNAL; switch (i.type) { @@ -280,6 +281,7 @@ void CMakeBuildConfiguration::setCurrentCMakeConfiguration(const QListsetSelectionBehavior(QAbstractItemView::SelectItems); m_configView->setFrameShape(QFrame::NoFrame); m_configView->hideColumn(2); // Hide isAdvanced column + m_configView->setItemDelegate(new ConfigModelItemDelegate(m_configView)); QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored); findWrapper->setFrameStyle(QFrame::StyledPanel); diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index 6115b318679..ff1011ef819 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -42,7 +42,7 @@ CMakeConfigItem::CMakeConfigItem() = default; CMakeConfigItem::CMakeConfigItem(const CMakeConfigItem &other) : key(other.key), type(other.type), isAdvanced(other.isAdvanced), - value(other.value), documentation(other.documentation) + value(other.value), documentation(other.documentation), values(other.values) { } CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t, diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index b800a547a21..1484cffda3e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -61,6 +61,7 @@ public: bool isAdvanced = false; QByteArray value; // converted to string as needed QByteArray documentation; + QStringList values; }; using CMakeConfig = QList; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro index 4621c40c15d..82cd93df82a 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro @@ -28,7 +28,8 @@ HEADERS = builddirmanager.h \ cmakebuildsettingswidget.h \ cmakeindenter.h \ cmakeautocompleter.h \ - configmodel.h + configmodel.h \ + configmodelitemdelegate.h SOURCES = builddirmanager.cpp \ cmakebuildstep.cpp \ @@ -54,6 +55,7 @@ SOURCES = builddirmanager.cpp \ cmakebuildsettingswidget.cpp \ cmakeindenter.cpp \ cmakeautocompleter.cpp \ - configmodel.cpp + configmodel.cpp \ + configmodelitemdelegate.cpp RESOURCES += cmakeproject.qrc diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs index b199483eaa0..99fe635b277 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs @@ -71,6 +71,8 @@ QtcPlugin { "cmakeautocompleter.h", "cmakeautocompleter.cpp", "configmodel.cpp", - "configmodel.h" + "configmodel.h", + "configmodelitemdelegate.cpp", + "configmodelitemdelegate.h" ] } diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 292cd933bf5..4ef34dd7fab 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -88,6 +88,15 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const const InternalDataItem &item = m_configuration[index.row()]; + if (index.column() < 2) { + switch (role) { + case ItemTypeRole: + return item.type; + case ItemValuesRole: + return item.values; + } + } + switch (index.column()) { case 0: switch (role) { @@ -97,8 +106,6 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const return item.key; case Qt::ToolTipRole: return item.description; - case Qt::UserRole: - return item.type; case Qt::FontRole: { QFont font; font.setItalic(item.isCMakeChanged); @@ -126,8 +133,6 @@ QVariant ConfigModel::data(const QModelIndex &index, int role) const } case Qt::ToolTipRole: return item.description; - case Qt::UserRole: - return item.type; default: return QVariant(); } @@ -209,13 +214,15 @@ QVariant ConfigModel::headerData(int section, Qt::Orientation orientation, int r void ConfigModel::appendConfiguration(const QString &key, const QString &value, const ConfigModel::DataItem::Type type, - const QString &description) + const QString &description, + const QStringList &values) { DataItem item; item.key = key; item.type = type; item.value = value; item.description = description; + item.values = values; InternalDataItem internalItem(item); internalItem.isUserNew = true; diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 5fe63baa0fe..05424817188 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -34,6 +34,11 @@ class ConfigModel : public QAbstractTableModel Q_OBJECT public: + enum Roles { + ItemTypeRole = Qt::UserRole, + ItemValuesRole + }; + class DataItem { public: enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN}; @@ -43,6 +48,7 @@ public: bool isAdvanced = false; QString value; QString description; + QStringList values; }; explicit ConfigModel(QObject *parent = nullptr); @@ -58,7 +64,8 @@ public: void appendConfiguration(const QString &key, const QString &value = QString(), const DataItem::Type type = DataItem::UNKNOWN, - const QString &description = QString()); + const QString &description = QString(), + const QStringList &values = QStringList()); void setConfiguration(const QList &config); void flush(); void resetAllChanges(); diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp new file mode 100644 index 00000000000..b2b19b837e2 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Alexander Drozdov. +** Contact: adrozdoff@gmail.com +** +** This file is part of CMakeProjectManager2 plugin. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "configmodelitemdelegate.h" +#include "configmodel.h" + +#include + +namespace CMakeProjectManager { + +ConfigModelItemDelegate::ConfigModelItemDelegate(QObject* parent) + : QStyledItemDelegate(parent) +{ } + +ConfigModelItemDelegate::~ConfigModelItemDelegate() +{ } + +QWidget* ConfigModelItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + // ComboBox ony in column 2 + if (index.column() != 1) + return QStyledItemDelegate::createEditor(parent, option, index); + + auto model = index.model(); + auto values = model->data(index, ConfigModel::ItemValuesRole).toStringList(); + if (values.isEmpty()) + return QStyledItemDelegate::createEditor(parent, option, index); + + // Create the combobox and populate it + auto cb = new QComboBox(parent); + cb->addItems(values); + cb->setEditable(true); + + return cb; +} + +void ConfigModelItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const +{ + if (QComboBox* cb = qobject_cast(editor)) { + // get the index of the text in the combobox that matches the current value of the itenm + QString currentText = index.data(Qt::EditRole).toString(); + int cbIndex = cb->findText(currentText); + // if it is valid, adjust the combobox + if (cbIndex >= 0) + cb->setCurrentIndex(cbIndex); + else + cb->setEditText(currentText); + } else { + QStyledItemDelegate::setEditorData(editor, index); + } +} + +void ConfigModelItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +{ + if (QComboBox* cb = qobject_cast(editor)) + // save the current text of the combo box as the current value of the item + model->setData(index, cb->currentText(), Qt::EditRole); + else + QStyledItemDelegate::setModelData(editor, model, index); +} + +} // namespace CMakeProjectManager + diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h new file mode 100644 index 00000000000..8c20f7b8313 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Alexander Drozdov. +** Contact: adrozdoff@gmail.com +** +** This file is part of CMakeProjectManager2 plugin. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace CMakeProjectManager { + +class ConfigModelItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + ConfigModelItemDelegate(QObject* parent=0); + ~ConfigModelItemDelegate(); + + QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + void setEditorData(QWidget* editor, const QModelIndex& index) const override; + void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; +}; + +} // namespace CMakeProjectManager