/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "aspects.h" #include "algorithm.h" #include "fancylineedit.h" #include "layoutbuilder.h" #include "pathchooser.h" #include "qtcassert.h" #include "qtcprocess.h" #include "utilsicons.h" #include "variablechooser.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace Utils { namespace Internal { class BaseAspectPrivate { public: Utils::Id m_id; QVariant m_value; QVariant m_defaultValue; QString m_displayName; QString m_settingsKey; // Name of data in settings. QString m_tooltip; QString m_labelText; QPixmap m_labelPixmap; QPointer m_label; // Owned by configuration widget bool m_visible = true; bool m_enabled = true; bool m_readOnly = true; BaseAspect::ConfigWidgetCreator m_configWidgetCreator; QList> m_subWidgets; }; } // Internal /*! \class Utils::BaseAspect \inmodule QtCreator \brief The \c BaseAspect class provides a common base for classes implementing aspects. An aspect is a hunk of data like a property or collection of related properties of some object, together with a description of its behavior for common operations like visualizing or persisting. Simple aspects are for example a boolean property represented by a QCheckBox in the user interface, or a string property represented by a PathChooser, selecting directories in the filesystem. While aspects implementations usually have the ability to visualize and to persist their data, or use an ID, neither of these is mandatory. */ /*! Constructs a BaseAspect. */ BaseAspect::BaseAspect() : d(new Internal::BaseAspectPrivate) {} /*! Destructs a BaseAspect. */ BaseAspect::~BaseAspect() = default; Id BaseAspect::id() const { return d->m_id; } void BaseAspect::setId(Id id) { d->m_id = id; } QVariant BaseAspect::value() const { return d->m_value; } /*! Sets value. Emits changed() if the value changed. */ void BaseAspect::setValue(const QVariant &value) { if (setValueQuietly(value)) emit changed(); } /*! Sets value without emitting changed() Returns whether the value changed. */ bool BaseAspect::setValueQuietly(const QVariant &value) { if (d->m_value == value) return false; d->m_value = value; return true; } QVariant BaseAspect::defaultValue() const { return d->m_defaultValue; } /*! Sets a default value for this aspect. Default values will not be stored in settings. */ void BaseAspect::setDefaultValue(const QVariant &value) { d->m_defaultValue = value; } void BaseAspect::setDisplayName(const QString &displayName) { d->m_displayName = displayName; } bool BaseAspect::isVisible() const { return d->m_visible; } /*! Shows or hides the visual representation of this aspect depending on the value of \a visible. By default, it is visible. */ void BaseAspect::setVisible(bool visible) { d->m_visible = visible; for (QWidget *w : qAsConst(d->m_subWidgets)) { QTC_ASSERT(w, continue); w->setVisible(visible); } } void BaseAspect::setupLabel() { QTC_ASSERT(!d->m_label, delete d->m_label); d->m_label = new QLabel(d->m_labelText); d->m_label->setTextInteractionFlags(Qt::TextSelectableByMouse); if (!d->m_labelPixmap.isNull()) d->m_label->setPixmap(d->m_labelPixmap); registerSubWidget(d->m_label); } /*! Sets \a labelText as text for the separate label in the visual representation of this aspect. */ void BaseAspect::setLabelText(const QString &labelText) { d->m_labelText = labelText; if (d->m_label) d->m_label->setText(labelText); } /*! Sets \a labelPixmap as pixmap for the separate label in the visual representation of this aspect. */ void BaseAspect::setLabelPixmap(const QPixmap &labelPixmap) { d->m_labelPixmap = labelPixmap; if (d->m_label) d->m_label->setPixmap(labelPixmap); } /*! Returns the current text for the separate label in the visual representation of this aspect. */ QString BaseAspect::labelText() const { return d->m_labelText; } QLabel *BaseAspect::label() const { return d->m_label.data(); } QString BaseAspect::toolTip() const { return d->m_tooltip; } /*! Sets \a tooltip as tool tip for the visual representation of this aspect. */ void BaseAspect::setToolTip(const QString &tooltip) { d->m_tooltip = tooltip; for (QWidget *w : qAsConst(d->m_subWidgets)) { QTC_ASSERT(w, continue); w->setToolTip(tooltip); } } void BaseAspect::setEnabled(bool enabled) { d->m_enabled = enabled; for (QWidget *w : qAsConst(d->m_subWidgets)) { QTC_ASSERT(w, continue); w->setEnabled(enabled); } } void BaseAspect::setReadOnly(bool readOnly) { d->m_readOnly = readOnly; for (QWidget *w : qAsConst(d->m_subWidgets)) { QTC_ASSERT(w, continue); if (auto lineEdit = qobject_cast(w)) lineEdit->setReadOnly(readOnly); else if (auto textEdit = qobject_cast(w)) textEdit->setReadOnly(readOnly); } } /*! \internal */ void BaseAspect::setConfigWidgetCreator(const ConfigWidgetCreator &configWidgetCreator) { d->m_configWidgetCreator = configWidgetCreator; } /*! Returns the key to be used when accessing the settings. \sa setSettingsKey() */ QString BaseAspect::settingsKey() const { return d->m_settingsKey; } /*! Sets the key to be used when accessing the settings. \sa settingsKey() */ void BaseAspect::setSettingsKey(const QString &key) { d->m_settingsKey = key; } /*! Sets the key and group to be used when accessing the settings. \sa settingsKey() */ void BaseAspect::setSettingsKey(const QString &group, const QString &key) { d->m_settingsKey = group + "/" + key; } QString BaseAspect::displayName() const { return d->m_displayName; } /*! \internal */ QWidget *BaseAspect::createConfigWidget() const { return d->m_configWidgetCreator ? d->m_configWidgetCreator() : nullptr; } /*! Adds the visual representation of this aspect to a layout using a layout builder. */ void BaseAspect::addToLayout(LayoutBuilder &) { } void BaseAspect::registerSubWidget(QWidget *widget) { d->m_subWidgets.append(widget); connect(widget, &QObject::destroyed, this, [this, widget] { d->m_subWidgets.removeAll(widget); }); widget->setEnabled(d->m_enabled); widget->setToolTip(d->m_tooltip); // Visible is on by default. Not setting it explicitly avoid popping // it up when the parent is not set yet, the normal case. if (!d->m_visible) widget->setVisible(d->m_visible); } void BaseAspect::saveToMap(QVariantMap &data, const QVariant &value, const QVariant &defaultValue, const QString &keyExtension) const { if (settingsKey().isEmpty()) return; const QString key = settingsKey() + keyExtension; if (value == defaultValue) data.remove(key); else data.insert(key, value); } /*! Retrieves the internal value of this BaseAspect from a \c QVariantMap. */ void BaseAspect::fromMap(const QVariantMap &map) { setValue(map.value(settingsKey(), defaultValue())); } /*! Stores the internal value of this BaseAspect into a \c QVariantMap. */ void BaseAspect::toMap(QVariantMap &map) const { saveToMap(map, d->m_value, d->m_defaultValue); } /*! \internal */ void BaseAspect::acquaintSiblings(const BaseAspects &) {} // BaseAspects /*! \class BaseAspects \inmodule QtCreator \brief This class represent a collection of one or more aspects. A BaseAspects object assumes ownership on its aspects. */ /*! Constructs a BaseAspects object. */ BaseAspects::BaseAspects() = default; /*! Destructs a BaseAspects object. */ BaseAspects::~BaseAspects() { qDeleteAll(m_aspects); } /*! Retrieves a BaseAspect with a given \a id, or nullptr if no such aspect is contained. \sa BaseAspect. */ BaseAspect *BaseAspects::aspect(Utils::Id id) const { return Utils::findOrDefault(m_aspects, Utils::equal(&BaseAspect::id, id)); } /*! \internal */ void BaseAspects::fromMap(const QVariantMap &map) const { for (BaseAspect *aspect : m_aspects) aspect->fromMap(map); } /*! \internal */ void BaseAspects::toMap(QVariantMap &map) const { for (BaseAspect *aspect : m_aspects) aspect->toMap(map); } namespace Internal { class BoolAspectPrivate { public: BoolAspect::LabelPlacement m_labelPlacement = BoolAspect::LabelPlacement::AtCheckBox; QPointer m_checkBox; // Owned by configuration widget }; class SelectionAspectPrivate { public: SelectionAspect::DisplayStyle m_displayStyle = SelectionAspect::DisplayStyle::RadioButtons; struct Option { QString displayName; QString tooltip; }; QVector