// Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once #include "filepath.h" #include "guiutils.h" #include "id.h" #include "infolabel.h" #include "pathchooser.h" #include "qtcsettings.h" #include "store.h" #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QAction; class QSettings; class QUndoStack; class QStandardItem; class QStandardItemModel; class QItemSelectionModel; QT_END_NAMESPACE namespace Layouting { class Layout; } namespace Utils { class AspectContainer; class BoolAspect; class CheckableDecider; class MacroExpander; namespace Internal { class AspectContainerPrivate; class BaseAspectPrivate; class ToggleAspectPrivate; class BoolAspectPrivate; class ColorAspectPrivate; class DoubleAspectPrivate; class FilePathAspectPrivate; class FilePathListAspectPrivate; class IntegerAspectPrivate; class MultiSelectionAspectPrivate; class SelectionAspectPrivate; class StringAspectPrivate; class StringListAspectPrivate; class TextDisplayPrivate; class CheckableAspectImplementation; class AspectListPrivate; } // Internal class QTCREATOR_UTILS_EXPORT BaseAspect : public QObject { Q_OBJECT public: BaseAspect(AspectContainer *container = nullptr); BaseAspect(const BaseAspect &) = delete; ~BaseAspect() override; Id id() const; void setId(Id id); enum Announcement { DoEmit, BeQuiet }; virtual QVariant volatileVariantValue() const; virtual QVariant variantValue() const; virtual void setVariantValue(const QVariant &value, Announcement = DoEmit); virtual QVariant defaultVariantValue() const; virtual void setDefaultVariantValue(const QVariant &value); virtual bool isDefaultValue() const; Key settingsKey() const; void setSettingsKey(const Key &settingsKey); void setSettingsKey(const Key &group, const Key &key); QString displayName() const; void setDisplayName(const QString &displayName); QString toolTip() const; void setToolTip(const QString &tooltip); bool isVisible() const; void setVisible(bool visible); bool isAutoApply() const; virtual void setAutoApply(bool on); virtual void setUndoStack(QUndoStack *undoStack); QUndoStack *undoStack() const; bool isEnabled() const; virtual void setEnabled(bool enabled); void setEnabler(BoolAspect *checker); bool isReadOnly() const; void setReadOnly(bool enabled); void setSpan(int x, int y = 1); bool isSaveAlways() const; void setSaveAlways(bool saveAlways); QString labelText() const; void setLabelText(const QString &labelText); void setLabelPixmap(const QPixmap &labelPixmap); void setIcon(const QIcon &labelIcon); QIcon icon() const; using ConfigWidgetCreator = std::function; void setConfigWidgetCreator(const ConfigWidgetCreator &configWidgetCreator); QWidget *createConfigWidget() const; virtual QAction *action(); AspectContainer *container() const; virtual void fromMap(const Store &map); virtual void toMap(Store &map) const; virtual void toActiveMap(Store &map) const { toMap(map); } virtual void volatileToMap(Store &map) const; void addToLayout(Layouting::Layout &parent) const; virtual void readSettings(); virtual void writeSettings() const; using SavedValueTransformation = std::function; void setFromSettingsTransformation(const SavedValueTransformation &transform); void setToSettingsTransformation(const SavedValueTransformation &transform); QVariant toSettingsValue(const QVariant &val) const; QVariant fromSettingsValue(const QVariant &val) const; virtual void apply(); virtual void cancel(); virtual void finish(); virtual bool isDirty(); bool hasAction() const; struct QTCREATOR_UTILS_EXPORT Changes { Changes(); unsigned internalFromOutside : 1; unsigned internalFromBuffer : 1; unsigned bufferFromOutside : 1; unsigned bufferFromInternal : 1; unsigned bufferFromGui : 1; }; virtual void announceChanges(Changes changes, Announcement howToAnnounce = DoEmit); class QTCREATOR_UTILS_EXPORT Data { public: // The (unique) address of the "owning" aspect's meta object is used as identifier. using ClassId = const void *; virtual ~Data(); Id id() const { return m_id; } ClassId classId() const { return m_classId; } Data *clone() const { return m_cloner(this); } QVariant value; class Ptr { public: Ptr() = default; explicit Ptr(const Data *data) : m_data(data) {} Ptr(const Ptr &other) { m_data = other.m_data->clone(); } ~Ptr() { delete m_data; } void operator=(const Ptr &other); void assign(const Data *other) { delete m_data; m_data = other; } const Data *get() const { return m_data; } private: const Data *m_data = nullptr; }; protected: friend class BaseAspect; Id m_id; ClassId m_classId = 0; std::function m_cloner; }; using DataCreator = std::function; using DataCloner = std::function; using DataExtractor = std::function; Data::Ptr extractData() const; static void setQtcSettings(QtcSettings *settings); static QtcSettings *qtcSettings(); // This is expensive. Do not use without good reason void writeToSettingsImmediatly() const; void setMacroExpander(MacroExpander *expander); MacroExpander *macroExpander() const; using Callback = std::function; void addOnChanged(QObject *guard, const Callback &callback); void addOnVolatileValueChanged(QObject *guard, const Callback &callback); void addOnCheckedChanged(QObject *guard, const Callback &callback); void addOnEnabledChanged(QObject *guard, const Callback &callback); void addOnLabelTextChanged(QObject *guard, const Callback &callback); void addOnLabelPixmapChanged(QObject *guard, const Callback &callback); signals: void changed(); void volatileValueChanged(); void labelLinkActivated(const QString &link); void checkedChanged(); void enabledChanged(); void labelTextChanged(); void labelPixmapChanged(); protected: virtual void addToLayoutImpl(Layouting::Layout &parent); virtual bool internalToBuffer(); virtual bool bufferToInternal(); virtual void bufferToGui(); virtual bool guiToBuffer(); virtual void handleGuiChanged(); void addMacroExpansion(QWidget *w); QLabel *createLabel(); void addLabeledItem(Layouting::Layout &parent, QWidget *widget); void addLabeledItems(Layouting::Layout &parent, const QList &widgets); void setDataCreatorHelper(const DataCreator &creator) const; void setDataClonerHelper(const DataCloner &cloner) const; void addDataExtractorHelper(const DataExtractor &extractor) const; template void addDataExtractor(AspectClass *aspect, Type(AspectClass::*p)() const, Type DataClass::*q) { setDataCreatorHelper([] { return new DataClass; }); setDataClonerHelper([](const Data *data) { return new DataClass(*static_cast(data)); }); addDataExtractorHelper([aspect, p, q](Data *data) { static_cast(data)->*q = (aspect->*p)(); }); } template Widget *createSubWidget(Args && ...args) { auto w = new Widget(args...); registerSubWidget(w); if constexpr (std::is_base_of_v || std::is_base_of_v) { setWheelScrollingWithoutFocusBlocked(w); } return w; } void registerSubWidget(QWidget *widget); void forEachSubWidget(const std::function &func); void saveToMap(Store &data, const QVariant &value, const QVariant &defaultValue, const Key &key) const; bool skipSave() const; protected: template static bool updateStorage(Value &target, const Value &val) { if (target == val) return false; target = val; return true; } private: friend class Internal::CheckableAspectImplementation; friend class AspectContainer; void setContainer(AspectContainer *container); std::unique_ptr d; }; QTCREATOR_UTILS_EXPORT void addToLayout(Layouting::Layout *layout, const BaseAspect *aspect); QTCREATOR_UTILS_EXPORT void addToLayout(Layouting::Layout *layout, const BaseAspect &aspect); template class #ifndef Q_OS_WIN QTCREATOR_UTILS_EXPORT #endif TypedAspect : public BaseAspect { public: using valueType = ValueType; TypedAspect(AspectContainer *container = nullptr) : BaseAspect(container) { addDataExtractor(this, &TypedAspect::value, &Data::value); } struct Data : BaseAspect::Data { ValueType value; }; ValueType operator()() const { return m_internal; } ValueType value() const { return m_internal; } ValueType defaultValue() const { return m_default; } ValueType volatileValue() const { return m_buffer; } // We assume that this is only used in the ctor and no signalling is needed. // If it is used elsewhere changes have to be detected and signalled externally. void setDefaultValue(const ValueType &value) { m_default = value; m_internal = value; if (internalToBuffer()) // Might be more than a plain copy. bufferToGui(); } bool isDefaultValue() const override { return m_default == m_internal; } void setValue(const ValueType &value, Announcement howToAnnounce = DoEmit) { Changes changes; changes.internalFromOutside = updateStorage(m_internal, value); if (internalToBuffer()) { changes.bufferFromInternal = true; bufferToGui(); } announceChanges(changes, howToAnnounce); } void setVolatileValue(const ValueType &value, Announcement howToAnnounce = DoEmit) { Changes changes; if (updateStorage(m_buffer, value)) { changes.bufferFromOutside = true; bufferToGui(); } if (isAutoApply() && bufferToInternal()) changes.internalFromBuffer = true; announceChanges(changes, howToAnnounce); } protected: bool isDirty() override { return m_internal != m_buffer; } bool internalToBuffer() override { return updateStorage(m_buffer, m_internal); } bool bufferToInternal() override { return updateStorage(m_internal, m_buffer); } QVariant variantValue() const override { return QVariant::fromValue(m_internal); } QVariant volatileVariantValue() const override { return QVariant::fromValue(m_buffer); } void setVariantValue(const QVariant &value, Announcement howToAnnounce = DoEmit) override { setValue(value.value(), howToAnnounce); } QVariant defaultVariantValue() const override { return QVariant::fromValue(m_default); } void setDefaultVariantValue(const QVariant &value) override { setDefaultValue(value.value()); } ValueType m_default{}; ValueType m_internal{}; ValueType m_buffer{}; }; template class FlexibleTypedAspect : public TypedAspect { public: using Base = TypedAspect; using Updater = std::function; using Base::Base; void setInternalToBuffer(const Updater &updater) { m_internalToBuffer = updater; } void setBufferToInternal(const Updater &updater) { m_bufferToInternal = updater; } void setInternalToExternal(const Updater &updater) { m_internalToExternal = updater; } protected: bool internalToBuffer() override { if (m_internalToBuffer) return m_internalToBuffer(Base::m_buffer, Base::m_internal); return Base::internalToBuffer(); } bool bufferToInternal() override { if (m_bufferToInternal) return m_bufferToInternal(Base::m_internal, Base::m_buffer); return Base::bufferToInternal(); } ValueType expandedValue() { if (!m_internalToExternal) return Base::m_internal; ValueType val; m_internalToExternal(val, Base::m_internal); return val; } Updater m_internalToBuffer; Updater m_bufferToInternal; Updater m_internalToExternal; }; class QTCREATOR_UTILS_EXPORT BoolAspect : public TypedAspect { Q_OBJECT public: BoolAspect(AspectContainer *container = nullptr); ~BoolAspect() override; void addToLayoutImpl(Layouting::Layout &parent) override; std::function groupChecker(); Utils::CheckableDecider askAgainCheckableDecider(); Utils::CheckableDecider doNotAskAgainCheckableDecider(); QAction *action() override; enum class LabelPlacement { AtCheckBox, Compact, InExtraLabel, ShowTip }; void setLabel(const QString &labelText, LabelPlacement labelPlacement = LabelPlacement::InExtraLabel); void setLabelPlacement(LabelPlacement labelPlacement); std::function adoptButton(QAbstractButton *button); private: void addToLayoutHelper(Layouting::Layout &parent, QAbstractButton *button); void bufferToGui() override; bool guiToBuffer() override; std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT ToggleAspect : public BoolAspect { public: ToggleAspect(AspectContainer *container = nullptr); ~ToggleAspect(); void setOffIcon(const QIcon &icon); QIcon offIcon() const; void setOffTooltip(const QString &tooltip); QString offTooltip() const; void setOnIcon(const QIcon &icon); QIcon onIcon() const; void setOnTooltip(const QString &tooltip); QString onTooltip() const; void setOnText(const QString &text); QString onText() const; void setOffText(const QString &text); QString offText() const; QAction *action() override; protected: void announceChanges(Changes changes, Announcement howToAnnounce = DoEmit) override; private: std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT ColorAspect : public TypedAspect { Q_OBJECT public: ColorAspect(AspectContainer *container = nullptr); ~ColorAspect() override; void addToLayoutImpl(Layouting::Layout &parent) override; void setMinimumSize(const QSize &size); private: void bufferToGui() override; bool guiToBuffer() override; std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT SelectionAspect : public TypedAspect { Q_OBJECT public: SelectionAspect(AspectContainer *container = nullptr); ~SelectionAspect() override; void finish() override; QString stringValue() const; void setStringValue(const QString &val); void setDefaultValue(const QString &val); void setDefaultValue(int val); QVariant itemValue() const; enum class DisplayStyle { RadioButtons, ComboBox }; void setDisplayStyle(DisplayStyle style); void setUseDataAsSavedValue(); class Option { public: Option(const QString &displayName, const QString &toolTip, const QVariant &itemData) : displayName(displayName), tooltip(toolTip), itemData(itemData) {} QString displayName; QString tooltip; QVariant itemData; bool enabled = true; }; void addOption(const QString &displayName, const QString &toolTip = {}); void addOption(const Option &option); int indexForDisplay(const QString &displayName) const; QString displayForIndex(int index) const; int indexForItemValue(const QVariant &value) const; QVariant itemValueForIndex(int index) const; protected: void addToLayoutImpl(Layouting::Layout &parent) override; void bufferToGui() override; bool guiToBuffer() override; std::unique_ptr d; }; template class TypedSelectionAspect : public SelectionAspect { public: using SelectionAspect::SelectionAspect; ValueType operator()() const { return static_cast(SelectionAspect::operator()()); } ValueType value() const { return static_cast(SelectionAspect::value()); } ValueType defaultValue() const { return static_cast(SelectionAspect::defaultValue()); } ValueType volatileValue() const { return static_cast(SelectionAspect::volatileValue()); } }; class QTCREATOR_UTILS_EXPORT MultiSelectionAspect : public TypedAspect { Q_OBJECT public: MultiSelectionAspect(AspectContainer *container = nullptr); ~MultiSelectionAspect() override; enum class DisplayStyle { ListView }; void setDisplayStyle(DisplayStyle style); QStringList allValues() const; void setAllValues(const QStringList &val); protected: void addToLayoutImpl(Layouting::Layout &parent) override; void bufferToGui() override; bool guiToBuffer() override; private: std::unique_ptr d; }; enum class UncheckedSemantics { Disabled, ReadOnly }; enum class CheckBoxPlacement { Top, Right }; class QTCREATOR_UTILS_EXPORT StringAspect : public TypedAspect { Q_OBJECT public: StringAspect(AspectContainer *container = nullptr); ~StringAspect() override; QString operator()() const { return expandedValue(); } QString expandedValue() const; // Hook between UI and StringAspect: using ValueAcceptor = std::function(const QString &, const QString &)>; void setValueAcceptor(ValueAcceptor &&acceptor); void setShowToolTipOnLabel(bool show); void setDisplayFilter(const std::function &displayFilter); void setPlaceHolderText(const QString &placeHolderText); void setHistoryCompleter(const Key &historyCompleterKey); void setAcceptRichText(bool acceptRichText); void setUseResetButton(); void setValidationFunction(const FancyLineEdit::ValidationFunction &validator); void setValidatorFactory(const std::function &validatorFactory); void setAutoApplyOnEditingFinished(bool applyOnEditingFinished); void setElideMode(Qt::TextElideMode elideMode); void makeCheckable(CheckBoxPlacement checkBoxPlacement, const QString &optionalLabel, const Key &optionalBaseKey); bool isChecked() const; void setChecked(bool checked); void setRightSideIconPath(const FilePath &path); void addOnRightSideIconClicked(QObject *guard, const std::function &); void setMinimumHeight(int); void setCompleter(QCompleter *completer); enum DisplayStyle { LabelDisplay, LineEditDisplay, TextEditDisplay, PasswordLineEditDisplay, }; void setDisplayStyle(DisplayStyle style); void fromMap(const Utils::Store &map) override; void toMap(Utils::Store &map) const override; void volatileToMap(Utils::Store &map) const override; signals: void validChanged(bool validState); void elideModeChanged(Qt::TextElideMode elideMode); void historyCompleterKeyChanged(const Key &historyCompleterKey); void acceptRichTextChanged(bool acceptRichText); void validationFunctionChanged(const FancyLineEdit::ValidationFunction &validator); void placeholderTextChanged(const QString &placeholderText); void rightSideIconClicked(); protected: void addToLayoutImpl(Layouting::Layout &parent) override; void bufferToGui() override; bool guiToBuffer() override; bool internalToBuffer() override; bool bufferToInternal() override; std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT FilePathAspect : public TypedAspect { Q_OBJECT public: FilePathAspect(AspectContainer *container = nullptr); ~FilePathAspect(); struct Data : BaseAspect::Data { QString value; FilePath filePath; }; FilePath operator()() const; FilePath effectiveBinary() const; FilePath expandedValue() const; QString value() const; void setValue(const FilePath &filePath, Announcement howToAnnounce = DoEmit); void setValue(const QString &filePath, Announcement howToAnnounce = DoEmit); void setDefaultValue(const QString &filePath); void setDefaultPathValue(const FilePath &filePath); void setPromptDialogFilter(const QString &filter); void setPromptDialogTitle(const QString &title); void setCommandVersionArguments(const QStringList &arguments); void setAllowPathFromDevice(bool allowPathFromDevice); void setValidatePlaceHolder(bool validatePlaceHolder); void setOpenTerminalHandler(const std::function &openTerminal); void setExpectedKind(const PathChooser::Kind expectedKind); void setEnvironment(const Environment &env); void setBaseFileName(const FilePath &baseFileName); void setPlaceHolderText(const QString &placeHolderText); void setValidationFunction(const FancyLineEdit::ValidationFunction &validator); void setDisplayFilter(const std::function &displayFilter); void setHistoryCompleter(const Key &historyCompleterKey); void setShowToolTipOnLabel(bool show); void setAutoApplyOnEditingFinished(bool applyOnEditingFinished); void validateInput(); void makeCheckable(CheckBoxPlacement checkBoxPlacement, const QString &optionalLabel, const Key &optionalBaseKey); bool isChecked() const; void setChecked(bool checked); // Hook between UI and StringAspect: using ValueAcceptor = std::function(const QString &, const QString &)>; void setValueAcceptor(ValueAcceptor &&acceptor); PathChooser *pathChooser() const; // Avoid to use. void addToLayoutImpl(Layouting::Layout &parent) override; void fromMap(const Utils::Store &map) override; void toMap(Utils::Store &map) const override; void volatileToMap(Utils::Store &map) const override; signals: void validChanged(bool validState); protected: void bufferToGui() override; bool guiToBuffer() override; bool internalToBuffer() override; bool bufferToInternal() override; std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT IntegerAspect : public TypedAspect { Q_OBJECT public: IntegerAspect(AspectContainer *container = nullptr); ~IntegerAspect() override; void addToLayoutImpl(Layouting::Layout &parent) override; void setRange(qint64 min, qint64 max); void setLabel(const QString &label); // FIXME: Use setLabelText void setPrefix(const QString &prefix); void setSuffix(const QString &suffix); void setDisplayIntegerBase(int base); void setDisplayScaleFactor(qint64 factor); void setSpecialValueText(const QString &specialText); void setSingleStep(qint64 step); struct Data : BaseAspect::Data { qint64 value = 0; }; protected: void bufferToGui() override; bool guiToBuffer() override; private: std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT DoubleAspect : public TypedAspect { Q_OBJECT public: DoubleAspect(AspectContainer *container = nullptr); ~DoubleAspect() override; void addToLayoutImpl(Layouting::Layout &parent) override; void setRange(double min, double max); void setPrefix(const QString &prefix); void setSuffix(const QString &suffix); void setSpecialValueText(const QString &specialText); void setSingleStep(double step); protected: void bufferToGui() override; bool guiToBuffer() override; private: std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT TriState { public: enum Value { EnabledValue, DisabledValue, DefaultValue }; TriState() = default; explicit TriState(Value v) : m_value(v) {} int toInt() const { return int(m_value); } QVariant toVariant() const { return int(m_value); } static TriState fromInt(int value); static TriState fromVariant(const QVariant &variant); static const TriState Enabled; static const TriState Disabled; static const TriState Default; friend bool operator==(TriState a, TriState b) { return a.m_value == b.m_value; } friend bool operator!=(TriState a, TriState b) { return a.m_value != b.m_value; } private: Value m_value = DefaultValue; }; class QTCREATOR_UTILS_EXPORT TriStateAspect : public SelectionAspect { Q_OBJECT public: TriStateAspect(AspectContainer *container = nullptr, const QString &enabledDisplay = {}, const QString &disabledDisplay = {}, const QString &defaultDisplay = {}); TriState operator()() const { return value(); } TriState value() const; void setValue(TriState setting); TriState defaultValue() const; void setDefaultValue(TriState setting); void setOptionText(const TriState::Value tristate, const QString &display); private: void addOption(const QString &displayName, const QString &toolTip = {}) = delete; void addOption(const Option &option) = delete; }; class QTCREATOR_UTILS_EXPORT StringListAspect : public TypedAspect { Q_OBJECT public: StringListAspect(AspectContainer *container = nullptr); ~StringListAspect() override; bool guiToBuffer() override; void bufferToGui() override; void addToLayoutImpl(Layouting::Layout &parent) override; void appendValue(const QString &value, bool allowDuplicates = true); void removeValue(const QString &value); void appendValues(const QStringList &values, bool allowDuplicates = true); void removeValues(const QStringList &values); void setUiAllowAdding(bool allowAdding); void setUiAllowRemoving(bool allowRemoving); void setUiAllowEditing(bool allowEditing); bool uiAllowAdding() const; bool uiAllowRemoving() const; bool uiAllowEditing() const; private: std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT FilePathListAspect : public TypedAspect { Q_OBJECT public: FilePathListAspect(AspectContainer *container = nullptr); ~FilePathListAspect() override; FilePaths operator()() const; bool guiToBuffer() override; void bufferToGui() override; void addToLayoutImpl(Layouting::Layout &parent) override; void setPlaceHolderText(const QString &placeHolderText); void appendValue(const FilePath &path, bool allowDuplicates = true); void removeValue(const FilePath &path); void appendValues(const FilePaths &values, bool allowDuplicates = true); void removeValues(const FilePaths &values); private: std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT IntegersAspect : public TypedAspect> { Q_OBJECT public: IntegersAspect(AspectContainer *container = nullptr); ~IntegersAspect() override; void addToLayoutImpl(Layouting::Layout &parent) override; }; class QTCREATOR_UTILS_EXPORT TextDisplay : public BaseAspect { Q_OBJECT public: explicit TextDisplay(AspectContainer *container = nullptr, const QString &message = {}, InfoLabel::InfoType type = InfoLabel::None); ~TextDisplay() override; void addToLayoutImpl(Layouting::Layout &parent) override; void setIconType(InfoLabel::InfoType t); void setText(const QString &message); private: std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT AspectContainerData { public: AspectContainerData() = default; const BaseAspect::Data *aspect(Id instanceId) const; const BaseAspect::Data *aspect(BaseAspect::Data::ClassId classId) const; void append(const BaseAspect::Data::Ptr &data); template const typename T::Data *aspect() const { return static_cast(aspect(&T::staticMetaObject)); } private: QList m_data; // Owned. }; class QTCREATOR_UTILS_EXPORT SettingsGroupNester { Q_DISABLE_COPY_MOVE(SettingsGroupNester) public: explicit SettingsGroupNester(const QStringList &groups); ~SettingsGroupNester(); private: const int m_groupCount; }; class QTCREATOR_UTILS_EXPORT AspectContainer : public BaseAspect { Q_OBJECT public: AspectContainer(); ~AspectContainer(); AspectContainer(const AspectContainer &) = delete; AspectContainer &operator=(const AspectContainer &) = delete; void addToLayoutImpl(Layouting::Layout &parent) override; void registerAspect(BaseAspect *aspect, bool takeOwnership = false); void registerAspects(const AspectContainer &aspects); void fromMap(const Utils::Store &map) override; void toMap(Utils::Store &map) const override; void volatileToMap(Utils::Store &map) const override; void readSettings() override; void writeSettings() const override; void setSettingsGroup(const QString &groupKey); void setSettingsGroups(const QString &groupKey, const QString &subGroupKey); QStringList settingsGroups() const; void apply() override; void cancel() override; void finish() override; void reset(); bool equals(const AspectContainer &other) const; void copyFrom(const AspectContainer &other); void setAutoApply(bool on) override; bool isDirty() override; void setUndoStack(QUndoStack *undoStack) override; void setEnabled(bool enabled) override; template T *aspect() const { for (BaseAspect *aspect : aspects()) if (T *result = qobject_cast(aspect)) return result; return nullptr; } BaseAspect *aspect(Id id) const; template T *aspect(Id id) const { return qobject_cast(aspect(id)); } void forEachAspect(const std::function &run) const; const QList &aspects() const; using const_iterator = QList::const_iterator; using value_type = QList::value_type; const_iterator begin() const; const_iterator end() const; void setLayouter(const std::function &layouter); std::function layouter() const; signals: void applied(); void fromMapFinished(); private: std::unique_ptr d; }; // Because QObject cannot be a template class QTCREATOR_UTILS_EXPORT UndoSignaller : public QObject { Q_OBJECT public: void emitChanged() { emit changed(); } signals: void changed(); }; template class QTCREATOR_UTILS_EXPORT UndoableValue { public: class UndoCmd : public QUndoCommand { public: UndoCmd(UndoableValue *value, const T &oldValue, const T &newValue) : m_value(value) , m_oldValue(oldValue) , m_newValue(newValue) {} void undo() override { m_value->setInternal(m_oldValue); } void redo() override { m_value->setInternal(m_newValue); } private: UndoableValue *m_value; T m_oldValue; T m_newValue; }; void set(QUndoStack *stack, const T &value) { if (m_value == value) return; if (stack) stack->push(new UndoCmd(this, m_value, value)); else setInternal(value); } void setSilently(const T &value) { m_value = value; } void setWithoutUndo(const T &value) { setInternal(value); } T get() const { return m_value; } UndoSignaller m_signal; private: void setInternal(const T &value) { m_value = value; m_signal.emitChanged(); } private: T m_value; }; class QTCREATOR_UTILS_EXPORT AspectList : public Utils::BaseAspect { public: using CreateItem = std::function()>; using ItemCallback = std::function)>; AspectList(Utils::AspectContainer *container = nullptr); ~AspectList() override; void fromMap(const Utils::Store &map) override; void toMap(Utils::Store &map) const override; void volatileToMap(Utils::Store &map) const override; QVariantList toList(bool v) const; QList> items() const; QList> volatileItems() const; std::shared_ptr createAndAddItem(); std::shared_ptr addItem(const std::shared_ptr &item); std::shared_ptr actualAddItem(const std::shared_ptr &item); void removeItem(const std::shared_ptr &item); void actualRemoveItem(const std::shared_ptr &item); void clear(); void apply() override; void setCreateItemFunction(CreateItem createItem); template void forEachItem(std::function &)> callback) const { for (const auto &item : volatileItems()) callback(std::static_pointer_cast(item)); } template void forEachItem(std::function &, int)> callback) const { int idx = 0; for (const auto &item : volatileItems()) callback(std::static_pointer_cast(item), idx++); } void setItemAddedCallback(const ItemCallback &callback); void setItemRemovedCallback(const ItemCallback &callback); template void setItemAddedCallback(const std::function)> &callback) { setItemAddedCallback([callback](const std::shared_ptr &item) { callback(std::static_pointer_cast(item)); }); } template void setItemRemovedCallback(const std::function)> &callback) { setItemRemovedCallback([callback](const std::shared_ptr &item) { callback(std::static_pointer_cast(item)); }); } qsizetype size() const; bool isDirty() override; QVariant volatileVariantValue() const override { return {}; } void addToLayoutImpl(Layouting::Layout &parent) override; private: std::unique_ptr d; }; class QTCREATOR_UTILS_EXPORT StringSelectionAspect : public Utils::TypedAspect { Q_OBJECT public: StringSelectionAspect(Utils::AspectContainer *container = nullptr); void addToLayoutImpl(Layouting::Layout &parent) override; using ResultCallback = std::function items)>; using FillCallback = std::function; void setFillCallback(FillCallback callback) { m_fillCallback = callback; } void refill() { emit refillRequested(); } void bufferToGui() override; bool guiToBuffer() override; void setComboBoxEditable(bool editable) { m_comboBoxEditable = editable; } signals: void refillRequested(); private: QStandardItem *itemById(const QString &id); FillCallback m_fillCallback; QStandardItemModel *m_model{nullptr}; QItemSelectionModel *m_selectionModel{nullptr}; bool m_comboBoxEditable{true}; Utils::UndoableValue m_undoable; }; } // namespace Utils