diff options
Diffstat (limited to 'src/plugins/qmldesigner/components/propertyeditor')
29 files changed, 1941 insertions, 366 deletions
diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp index 5d7b1aeaaf..245d604707 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp @@ -85,6 +85,11 @@ QUrl FileResourcesModel::path() const return m_path; } +QUrl FileResourcesModel::dirPath() const +{ + return QUrl::fromLocalFile(m_dirPath.path()); +} + void FileResourcesModel::setFilter(const QString &filter) { if (m_filter != filter) { @@ -162,16 +167,14 @@ void FileResourcesModel::setupModel() m_lock = true; m_model.clear(); - QDir dir; - - dir = QFileInfo(m_path.toLocalFile()).dir(); + m_dirPath = QFileInfo(m_path.toLocalFile()).dir(); QStringList filterList = m_filter.split(QLatin1Char(' ')); - QDirIterator it(dir.absolutePath(), filterList, QDir::Files, QDirIterator::Subdirectories); + QDirIterator it(m_dirPath.absolutePath(), filterList, QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) { QString absolutePath = it.next(); - m_model.append(dir.relativeFilePath(absolutePath)); + m_model.append(m_dirPath.relativeFilePath(absolutePath)); } m_lock = false; diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h index e0d6fc9725..f686631079 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h @@ -27,6 +27,7 @@ #include <qmlitemnode.h> +#include <QDir> #include <QObject> #include <QStringList> #include <QUrl> @@ -40,6 +41,7 @@ class FileResourcesModel : public QObject Q_PROPERTY(QString filter READ filter WRITE setFilter) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QUrl path READ path WRITE setPath) + Q_PROPERTY(QUrl dirPath READ dirPath) Q_PROPERTY(QStringList fileModel READ fileModel NOTIFY fileModelChanged) public: @@ -51,6 +53,7 @@ public: void setFileNameStr(const QString &fileName); void setPath(const QUrl &url); QUrl path() const; + QUrl dirPath() const; void setFilter(const QString &filter); QString filter() const; QStringList fileModel() const; @@ -71,6 +74,7 @@ private: private: QUrl m_fileName; QUrl m_path; + QDir m_dirPath; QString m_filter; bool m_lock; QString m_currentPath; diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp index 6bb3153bea..d4b1f47184 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp @@ -27,6 +27,8 @@ #include "qmlanchorbindingproxy.h" #include "propertyeditorview.h" +#include "gradientpresetitem.h" +#include "gradientpresetcustomlistmodel.h" #include <exception.h> #include <nodeproperty.h> @@ -34,14 +36,14 @@ #include <variantproperty.h> #include <abstractview.h> #include <nodemetainfo.h> -#include <rewritertransaction.h> +#include <exception.h> #include <utils/qtcassert.h> #include <QTimer> GradientModel::GradientModel(QObject *parent) : - QAbstractListModel(parent), m_gradientTypeName("Gradient"), m_locked(false) + QAbstractListModel(parent) { } @@ -145,18 +147,16 @@ void GradientModel::addGradient() return; if (!m_itemNode.modelNode().hasNodeProperty(gradientPropertyName().toUtf8())) { - try { + if (m_gradientTypeName != "Gradient") + ensureShapesImport(); + + view()->executeInTransaction("GradientModel::addGradient", [this](){ QColor color = m_itemNode.instanceValue("color").value<QColor>(); if (!color.isValid()) color = QColor(Qt::white); - if (m_gradientTypeName != "Gradient") - ensureShapesImport(); - - QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::addGradient")); - QmlDesigner::ModelNode gradientNode = createGradientNode(); m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).reparentHere(gradientNode); @@ -170,16 +170,12 @@ void GradientModel::addGradient() gradientStopNode.variantProperty("position").setValue(1.0); gradientStopNode.variantProperty("color").setValue(QColor(Qt::black)); gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); - - } catch (const QmlDesigner::Exception &e) { - e.showException(); - } - + }); } setupModel(); if (m_gradientTypeName != "Gradient") - QTimer::singleShot(100, [this](){ view()->resetPuppet(); }); /*Unfortunately required */ + resetPuppet(); /*Unfortunately required */ emit hasGradientChanged(); emit gradientTypeChanged(); } @@ -242,18 +238,18 @@ qreal GradientModel::getPosition(int index) const void GradientModel::removeStop(int index) { if (index < rowCount() - 1 && index != 0) { - QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::removeStop")); - QmlDesigner::ModelNode gradientNode = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode(); - QmlDesigner::QmlObjectNode stop = gradientNode.nodeListProperty("stops").at(index); - if (stop.isValid()) { - stop.destroy(); - setupModel(); - } + view()->executeInTransaction("GradientModel::removeStop", [this, index](){ + QmlDesigner::ModelNode gradientNode = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode(); + QmlDesigner::QmlObjectNode stop = gradientNode.nodeListProperty("stops").at(index); + if (stop.isValid()) { + stop.destroy(); + setupModel(); + } + }); } qWarning() << Q_FUNC_INFO << "invalid index"; } - void GradientModel::deleteGradient() { if (!m_itemNode.isValid()) @@ -262,16 +258,7 @@ void GradientModel::deleteGradient() if (!m_itemNode.modelNode().metaInfo().hasProperty(gradientPropertyName().toUtf8())) return; - QmlDesigner::ModelNode modelNode = m_itemNode.modelNode(); - - if (m_itemNode.isInBaseState()) { - if (modelNode.hasProperty(gradientPropertyName().toUtf8())) { - QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::deleteGradient")); - QmlDesigner::ModelNode gradientNode = modelNode.nodeProperty(gradientPropertyName().toUtf8()).modelNode(); - if (QmlDesigner::QmlObjectNode(gradientNode).isValid()) - QmlDesigner::QmlObjectNode(gradientNode).destroy(); - } - } + deleteGradientNode(true); emit hasGradientChanged(); emit gradientTypeChanged(); @@ -392,7 +379,11 @@ void GradientModel::ensureShapesImport() { if (!hasShapesImport()) { QmlDesigner::Import timelineImport = QmlDesigner::Import::createLibraryImport("QtQuick.Shapes", "1.0"); - model()->changeImports({timelineImport}, {}); + try { + model()->changeImports({timelineImport}, {}); + } catch (const QmlDesigner::Exception &) { + QTC_ASSERT(false, return); + } } } @@ -444,6 +435,11 @@ QmlDesigner::AbstractView *GradientModel::view() const return m_itemNode.view(); } +void GradientModel::resetPuppet() +{ + QTimer::singleShot(1000, [this]() { view()->resetPuppet(); }); +} + QmlDesigner::ModelNode GradientModel::createGradientNode() { QByteArray fullTypeName = m_gradientTypeName.toUtf8(); @@ -477,6 +473,23 @@ QmlDesigner::ModelNode GradientModel::createGradientStopNode() return view()->createModelNode(fullTypeName, majorVersion, minorVersion); } +void GradientModel::deleteGradientNode(bool saveTransaction) +{ + QmlDesigner::ModelNode modelNode = m_itemNode.modelNode(); + + if (m_itemNode.isInBaseState()) { + if (modelNode.hasProperty(gradientPropertyName().toUtf8())) { + if (saveTransaction) + QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction( + QByteArrayLiteral("GradientModel::deleteGradient")); + QmlDesigner::ModelNode gradientNode + = modelNode.nodeProperty(gradientPropertyName().toUtf8()).modelNode(); + if (QmlDesigner::QmlObjectNode(gradientNode).isValid()) + QmlDesigner::QmlObjectNode(gradientNode).destroy(); + } + } +} + void GradientModel::setGradientProperty(const QString &propertyName, qreal value) { QTC_ASSERT(m_itemNode.isValid(), return); @@ -494,3 +507,102 @@ void GradientModel::setGradientProperty(const QString &propertyName, qreal value e.showException(); } } + +void GradientModel::setPresetByID(int presetID) +{ + const QGradient gradient(GradientPresetItem::createGradientFromPreset( + static_cast<GradientPresetItem::Preset>(presetID))); + const QList<QGradientStop> gradientStops = gradient.stops().toList(); + + QList<qreal> stopsPositions; + QList<QString> stopsColors; + for (const QGradientStop &stop : gradientStops) { + stopsPositions.append(stop.first); + stopsColors.append(stop.second.name()); + } + + setPresetByStops(stopsPositions, stopsColors, gradientStops.size()); +} + +void GradientModel::setPresetByStops(const QList<qreal> &stopsPositions, + const QList<QString> &stopsColors, + int stopsCount) +{ + if (m_locked) + return; + + if (!m_itemNode.isValid() || gradientPropertyName().isEmpty()) + return; + + QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction( + QByteArrayLiteral("GradientModel::setCustomPreset")); + + deleteGradientNode(false); + + if (!m_itemNode.modelNode().hasNodeProperty(gradientPropertyName().toUtf8())) { + try { + + if (m_gradientTypeName != "Gradient") + ensureShapesImport(); + + QmlDesigner::ModelNode gradientNode = createGradientNode(); + + m_itemNode.modelNode() + .nodeProperty(gradientPropertyName().toUtf8()) + .reparentHere(gradientNode); + + for (int i = 0; i < stopsCount; i++) { + QmlDesigner::ModelNode gradientStopNode = createGradientStopNode(); + gradientStopNode.variantProperty("position").setValue(stopsPositions.at(i)); + gradientStopNode.variantProperty("color").setValue(stopsColors.at(i)); + gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); + } + + } catch (const QmlDesigner::Exception &e) { + e.showException(); + } + } + setupModel(); + + if (m_gradientTypeName != "Gradient") + resetPuppet(); /*Unfortunately required */ + + emit hasGradientChanged(); + emit gradientTypeChanged(); +} + +void GradientModel::savePreset() +{ + //preparing qgradient: + QGradient currentGradient; + QGradientStops currentStops; + QGradientStop stop; //double, color + + for (int i = 0; i < rowCount(); i++) { + stop.first = getPosition(i); + stop.second = getColor(i); + currentStops.append(stop); + } + currentGradient.setStops(currentStops); + const GradientPresetItem item(currentGradient, "Custom Gradient"); + + //reading the custom gradient file + //filling the file with old data + new data + const QString filename(GradientPresetCustomListModel::getFilename()); + QList<GradientPresetItem> items = GradientPresetCustomListModel::storedPresets(filename); + items.append(item); + GradientPresetCustomListModel::storePresets(filename, items); +} + +void GradientModel::updateGradient() +{ + QList<qreal> stops; + QList<QString> colors; + int stopsCount = rowCount(); + for (int i = 0; i < stopsCount; i++) { + stops.append(getPosition(i)); + colors.append(getColor(i).name(QColor::HexArgb)); + } + + setPresetByStops(stops, colors, stopsCount); +} diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h index 48514ae688..c54526838e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h @@ -70,6 +70,15 @@ public: Q_INVOKABLE void setGradientProperty(const QString &propertyName, qreal value); + Q_INVOKABLE void setPresetByID(int presetID); + Q_INVOKABLE void setPresetByStops(const QList<qreal> &stopsPositions, + const QList<QString> &stopsColors, + int stopsCount); + + Q_INVOKABLE void savePreset(); + + Q_INVOKABLE void updateGradient(); + signals: void anchorBackendChanged(); void hasGradientChanged(); @@ -87,17 +96,19 @@ private: bool locked() const; QmlDesigner::ModelNode createGradientNode(); QmlDesigner::ModelNode createGradientStopNode(); + void deleteGradientNode(bool saveTransaction); private: QmlDesigner::QmlItemNode m_itemNode; QString m_gradientPropertyName; - QString m_gradientTypeName; - bool m_locked; + QString m_gradientTypeName = {"Gradient"}; + bool m_locked = false; bool hasShapesImport() const; void ensureShapesImport(); void setupGradientProperties(const QmlDesigner::ModelNode &gradient); QmlDesigner::Model *model() const; QmlDesigner::AbstractView *view() const; + void resetPuppet(); }; QML_DECLARE_TYPE(GradientModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp new file mode 100644 index 0000000000..a1599a7099 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "gradientpresetcustomlistmodel.h" +#include "gradientpresetitem.h" + +#include <coreplugin/icore.h> +#include <utils/qtcassert.h> +#include <utils/algorithm.h> + +#include <QHash> +#include <QByteArray> +#include <QDebug> +#include <QSettings> +#include <QFile> + +namespace Internal { + +static const char settingsKey[] = "GradientPresetCustomList"; +static const char settingsFileName[] = "/GradientPresets.ini"; + +QString settingsFullFilePath(const QSettings::Scope &scope) +{ + if (scope == QSettings::SystemScope) + return Core::ICore::installerResourcePath() + settingsFileName; + + return Core::ICore::userResourcePath() + settingsFileName; +} + +} // namespace Internal + +GradientPresetCustomListModel::GradientPresetCustomListModel(QObject *parent) + : GradientPresetListModel(parent) + , m_filename(getFilename()) +{ + qRegisterMetaTypeStreamOperators<GradientPresetItem>("GradientPresetItem"); + readPresets(); +} + +GradientPresetCustomListModel::~GradientPresetCustomListModel() {} + +void GradientPresetCustomListModel::registerDeclarativeType() +{ + qmlRegisterType<GradientPresetCustomListModel>("HelperWidgets", + 2, + 0, + "GradientPresetCustomListModel"); +} + +QString GradientPresetCustomListModel::getFilename() +{ + return Internal::settingsFullFilePath(QSettings::UserScope); +} + +void GradientPresetCustomListModel::storePresets(const QString &filename, + const QList<GradientPresetItem> &items) +{ + const QList<QVariant> presets + = Utils::transform<QList<QVariant>>(items, [](const GradientPresetItem &item) { + return QVariant::fromValue(item); + }); + + QSettings settings(filename, QSettings::IniFormat); + settings.clear(); + settings.setValue(Internal::settingsKey, QVariant::fromValue(presets)); +} + +QList<GradientPresetItem> GradientPresetCustomListModel::storedPresets(const QString &filename) +{ + const QSettings settings(filename, QSettings::IniFormat); + const QVariant presetSettings = settings.value(Internal::settingsKey); + + if (!presetSettings.isValid()) + return {}; + + const QList<QVariant> presets = presetSettings.toList(); + + QList<GradientPresetItem> out; + for (const QVariant &preset : presets) { + if (preset.isValid()) { + out.append(preset.value<GradientPresetItem>()); + } + } + + return out; +} + +void GradientPresetCustomListModel::addGradient(const QList<qreal> &stopsPositions, + const QList<QString> &stopsColors, + int stopsCount) +{ + QGradient tempGradient; + QGradientStops gradientStops; + QGradientStop gradientStop; + for (int i = 0; i < stopsCount; i++) { + gradientStop.first = stopsPositions.at(i); + gradientStop.second = stopsColors.at(i); + gradientStops.push_back(gradientStop); + } + + tempGradient.setStops(gradientStops); + + addItem(GradientPresetItem(tempGradient)); +} + +void GradientPresetCustomListModel::changePresetName(int id, const QString &newName) +{ + QTC_ASSERT(id >= 0, return); + QTC_ASSERT(id < m_items.size(), return); + m_items[id].setPresetName(newName); + writePresets(); +} + +void GradientPresetCustomListModel::deletePreset(int id) +{ + QTC_ASSERT(id >= 0, return); + QTC_ASSERT(id < m_items.size(), return); + beginResetModel(); + m_items.removeAt(id); + writePresets(); + endResetModel(); +} + +void GradientPresetCustomListModel::writePresets() +{ + storePresets(m_filename, m_items); +} + +void GradientPresetCustomListModel::readPresets() +{ + const QList<GradientPresetItem> presets = storedPresets(m_filename); + beginResetModel(); + m_items.clear(); + + for (const GradientPresetItem &preset : presets) { + addItem(preset); + } + endResetModel(); +} diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.h b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.h new file mode 100644 index 0000000000..382b651e3b --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetcustomlistmodel.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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. +** +****************************************************************************/ + +#pragma once + +#include "gradientpresetlistmodel.h" + +#include <QObject> +#include <QAbstractListModel> +#include <QtQml/qqml.h> + +class GradientPresetCustomListModel : public GradientPresetListModel +{ + Q_OBJECT + +public: + explicit GradientPresetCustomListModel(QObject *parent = nullptr); + ~GradientPresetCustomListModel() override; + + static void registerDeclarativeType(); + + static QString getFilename(); + static void storePresets(const QString &filename, const QList<GradientPresetItem> &items); + static QList<GradientPresetItem> storedPresets(const QString &filename); + + Q_INVOKABLE void addGradient(const QList<qreal> &stopsPositions, + const QList<QString> &stopsColors, + int stopsCount); + + Q_INVOKABLE void changePresetName(int id, const QString &newName); + Q_INVOKABLE void deletePreset(int id); + + Q_INVOKABLE void writePresets(); + Q_INVOKABLE void readPresets(); + +private: + QString m_filename; +}; + +QML_DECLARE_TYPE(GradientPresetCustomListModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetdefaultlistmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetdefaultlistmodel.cpp new file mode 100644 index 0000000000..8237390de9 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetdefaultlistmodel.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "gradientpresetdefaultlistmodel.h" +#include "gradientpresetitem.h" + +#include <QHash> +#include <QByteArray> +#include <QDebug> +#include <QFile> + +GradientPresetDefaultListModel::GradientPresetDefaultListModel(QObject *parent) + : GradientPresetListModel(parent) +{ + addAllPresets(); +} + +GradientPresetDefaultListModel::~GradientPresetDefaultListModel() {} + +void GradientPresetDefaultListModel::registerDeclarativeType() +{ + qmlRegisterType<GradientPresetDefaultListModel>("HelperWidgets", + 2, + 0, + "GradientPresetDefaultListModel"); +} + +void GradientPresetDefaultListModel::addAllPresets() +{ + const QMetaObject &metaObj = QGradient::staticMetaObject; + const QMetaEnum metaEnum = metaObj.enumerator(metaObj.indexOfEnumerator("Preset")); + + if (!metaEnum.isValid()) + return; + + for (int i = 0; i < metaEnum.keyCount(); i++) { + addItem(GradientPresetItem(GradientPresetItem::Preset(metaEnum.value(i)))); + } +} diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetdefaultlistmodel.h b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetdefaultlistmodel.h new file mode 100644 index 0000000000..831135e052 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetdefaultlistmodel.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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. +** +****************************************************************************/ + +#pragma once + +#include "gradientpresetlistmodel.h" + +#include <QObject> +#include <QAbstractListModel> +#include <QtQml/qqml.h> + +class GradientPresetDefaultListModel : public GradientPresetListModel +{ + Q_OBJECT + +public: + explicit GradientPresetDefaultListModel(QObject *parent = nullptr); + ~GradientPresetDefaultListModel() override; + + static void registerDeclarativeType(); + +private: + void addAllPresets(); +}; + +QML_DECLARE_TYPE(GradientPresetDefaultListModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp new file mode 100644 index 0000000000..9d2454c4e9 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.cpp @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "gradientpresetitem.h" + +#include <utils/qtcassert.h> +#include <utils/algorithm.h> + +#include <QVariant> +#include <QMetaObject> +#include <QMetaEnum> +#include <algorithm> +#include <QDebug> + + +GradientPresetItem::GradientPresetItem() + : m_gradientVal(QGradient()) + , m_gradientID(Preset(0)) + , m_presetName(QString()) +{} + +GradientPresetItem::GradientPresetItem(const QGradient &value, const QString &name) + : m_gradientVal(value) + , m_gradientID(Preset(0)) + , m_presetName(name) +{} + +GradientPresetItem::GradientPresetItem(const Preset value) + : m_gradientVal(createGradientFromPreset(value)) + , m_gradientID(value) + , m_presetName(getNameByPreset(value)) +{} + +GradientPresetItem::~GradientPresetItem() = default; + +QVariant GradientPresetItem::getProperty(GradientPresetItem::Property id) const +{ + QVariant out; + + switch (id) { + case objectNameRole: + out.setValue(QString()); + break; + case stopsPosListRole: + out.setValue(stopsPosList()); + break; + case stopsColorListRole: + out.setValue(stopsColorList()); + break; + case stopListSizeRole: + out.setValue(stopListSize()); + break; + case presetNameRole: + out.setValue(presetName()); + break; + case presetIDRole: + out.setValue(presetID()); + break; + default: + qWarning() << "GradientPresetItem Property switch default case"; + break; //replace with assert before switch? + } + + return out; +} + +QGradient GradientPresetItem::gradientVal() const +{ + return m_gradientVal; +} + +void GradientPresetItem::setGradient(const QGradient &value) +{ + m_gradientVal = value; + m_gradientID = Preset(0); + m_presetName = QString(); +} + +void GradientPresetItem::setGradient(const Preset value) +{ + m_gradientID = value; + m_gradientVal = createGradientFromPreset(value); + m_presetName = getNameByPreset(value); +} + +QList<qreal> GradientPresetItem::stopsPosList() const +{ + const QList<QPair<qreal, QColor>> subres = m_gradientVal.stops().toList(); + const QList<qreal> result = Utils::transform<QList<qreal>>(subres, + [](const QPair<qreal, QColor> &item) { + return item.first; + }); + return result; +} + +QList<QString> GradientPresetItem::stopsColorList() const +{ + const QList<QPair<qreal, QColor>> subres = m_gradientVal.stops().toList(); + const QList<QString> result + = Utils::transform<QList<QString>>(subres, [](const QPair<qreal, QColor> &item) { + return item.second.name(); + }); + return result; +} + +int GradientPresetItem::stopListSize() const +{ + return m_gradientVal.stops().size(); +} + +void GradientPresetItem::setPresetName(const QString &value) +{ + m_presetName = value; +} + +QString GradientPresetItem::presetName() const +{ + return m_presetName; +} + +int GradientPresetItem::presetID() const +{ + return static_cast<int>(m_gradientID); +} + +QString GradientPresetItem::getNameByPreset(Preset value) +{ + const QMetaObject &metaObj = QGradient::staticMetaObject; + const QMetaEnum metaEnum = metaObj.enumerator(metaObj.indexOfEnumerator("Preset")); + + if (!metaEnum.isValid()) + return QString("Custom"); + + QString enumName = QString::fromUtf8(metaEnum.valueToKey(static_cast<int>(value))); + + const QStringList sl = enumName.split(QRegExp("(?=[A-Z])"), QString::SkipEmptyParts); + + enumName.clear(); + std::for_each(sl.begin(), sl.end(), [&enumName](const QString &s) { enumName += (s + " "); }); + enumName.chop(1); //let's remove the last empty space + + return (enumName.isEmpty() ? QString("Custom") : enumName); +} + +QGradient GradientPresetItem::createGradientFromPreset(Preset value) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + return QGradient(value); +#else + Q_UNUSED(value); + return {}; +#endif +} + +QDebug &operator<<(QDebug &stream, const GradientPresetItem &gradient) +{ + stream << "\"stops:" << gradient.m_gradientVal.stops() << "\""; + stream << "\"preset:" << gradient.m_gradientID << "\""; + stream << "\"name:" << gradient.m_presetName << "\""; + return stream; +} + +QDataStream &operator<<(QDataStream &stream, const GradientPresetItem &gradient) +{ + stream << gradient.m_gradientVal.stops(); + + stream << static_cast<int>(gradient.m_gradientID); + stream << gradient.m_presetName; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, GradientPresetItem &gradient) +{ + QGradientStops stops; + stream >> stops; + gradient.m_gradientVal.setStops(stops); + + int gradientID; + stream >> gradientID; + gradient.m_gradientID = static_cast<GradientPresetItem::Preset>(gradientID); + + stream >> gradient.m_presetName; + return stream; +} diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h new file mode 100644 index 0000000000..cd0f0017e0 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetitem.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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. +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QGradient> + +class GradientPresetItem +{ + Q_GADGET + + Q_PROPERTY(QList<qreal> stopsPosList READ stopsPosList FINAL) + Q_PROPERTY(QList<QString> stopsColorList READ stopsColorList FINAL) + Q_PROPERTY(int stopListSize READ stopListSize FINAL) + Q_PROPERTY(QString presetName READ presetName FINAL) + Q_PROPERTY(int presetID READ presetID FINAL) + +public: +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) + using Preset = QGradient::Preset; +#else + enum Preset {}; +#endif + + explicit GradientPresetItem(); + explicit GradientPresetItem(const QGradient &value, const QString &name = QString()); + explicit GradientPresetItem(const Preset number); + ~GradientPresetItem(); + + enum Property { + objectNameRole = 0, + stopsPosListRole = 1, + stopsColorListRole = 2, + stopListSizeRole = 3, + presetNameRole = 4, + presetIDRole = 5 + }; + + QVariant getProperty(Property id) const; + + QGradient gradientVal() const; + + void setGradient(const QGradient &value); + void setGradient(const Preset value); + + QList<qreal> stopsPosList() const; + QList<QString> stopsColorList() const; + int stopListSize() const; + + void setPresetName(const QString &value); + QString presetName() const; + int presetID() const; + + static QString getNameByPreset(Preset value); + + friend QDebug &operator<<(QDebug &stream, const GradientPresetItem &gradient); + + friend QDataStream &operator<<(QDataStream &stream, const GradientPresetItem &gradient); + friend QDataStream &operator>>(QDataStream &stream, GradientPresetItem &gradient); + + static QGradient createGradientFromPreset(Preset value); + +private: + QGradient m_gradientVal; + Preset m_gradientID; + QString m_presetName; +}; + +Q_DECLARE_METATYPE(GradientPresetItem) diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetlistmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetlistmodel.cpp new file mode 100644 index 0000000000..1ed95f8719 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetlistmodel.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "gradientpresetlistmodel.h" +#include "gradientpresetitem.h" + +#include <QHash> +#include <QByteArray> +#include <QDebug> +#include <QSettings> + +GradientPresetListModel::GradientPresetListModel(QObject *parent) + : QAbstractListModel(parent) +{ + m_roleNames + = {{static_cast<int>(GradientPresetItem::Property::objectNameRole), "objectName"}, + {static_cast<int>(GradientPresetItem::Property::stopsPosListRole), "stopsPosList"}, + {static_cast<int>(GradientPresetItem::Property::stopsColorListRole), "stopsColorList"}, + {static_cast<int>(GradientPresetItem::Property::stopListSizeRole), "stopListSize"}, + {static_cast<int>(GradientPresetItem::Property::presetNameRole), "presetName"}, + {static_cast<int>(GradientPresetItem::Property::presetIDRole), "presetID"}}; +} + +GradientPresetListModel::~GradientPresetListModel() +{ + clearItems(); +} + +int GradientPresetListModel::rowCount(const QModelIndex & /*parent*/) const +{ + return m_items.count(); +} + +QVariant GradientPresetListModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && (index.row() >= 0) && (index.row() < m_items.count())) { + if (m_roleNames.contains(role)) { + QVariant value = m_items.at(index.row()) + .getProperty(static_cast<GradientPresetItem::Property>(role)); + + if (auto model = qobject_cast<GradientPresetListModel *>(value.value<QObject *>())) + return QVariant::fromValue(model); + + return value; + } + + qWarning() << Q_FUNC_INFO << "invalid role requested"; + return QVariant(); + } + + qWarning() << Q_FUNC_INFO << "invalid index requested"; + return QVariant(); +} + +QHash<int, QByteArray> GradientPresetListModel::roleNames() const +{ + return m_roleNames; +} + +void GradientPresetListModel::clearItems() +{ + beginResetModel(); + m_items.clear(); + endResetModel(); +} + +void GradientPresetListModel::addItem(const GradientPresetItem &element) +{ + beginResetModel(); + m_items.append(element); + endResetModel(); +} + +const QList<GradientPresetItem> &GradientPresetListModel::items() const +{ + return m_items; +} + +void GradientPresetListModel::sortItems() +{ + auto itemSort = [](const GradientPresetItem &first, const GradientPresetItem &second) { + return (static_cast<int>(first.presetID()) < static_cast<int>(second.presetID())); + }; + + std::sort(m_items.begin(), m_items.end(), itemSort); +} + +void GradientPresetListModel::registerDeclarativeType() +{ + qmlRegisterType<GradientPresetListModel>("HelperWidgets", 2, 0, "GradientPresetListModel"); +} diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientpresetlistmodel.h b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetlistmodel.h new file mode 100644 index 0000000000..7fce2243dd --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientpresetlistmodel.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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. +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QAbstractListModel> +#include <QtQml/qqml.h> + +class GradientPresetItem; + +class GradientPresetListModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit GradientPresetListModel(QObject *parent = nullptr); + ~GradientPresetListModel() override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; + + void clearItems(); + void addItem(const GradientPresetItem &element); + + const QList<GradientPresetItem> &items() const; + + void sortItems(); + + static void registerDeclarativeType(); + +protected: + QList<GradientPresetItem> m_items; + QHash<int, QByteArray> m_roleNames; +}; + +//QML_DECLARE_TYPE(GradientPresetListModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri b/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri index d822fbb70d..b32a744016 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri @@ -11,7 +11,14 @@ SOURCES += propertyeditorview.cpp \ propertyeditorwidget.cpp \ fileresourcesmodel.cpp \ gradientmodel.cpp \ - qmlmodelnodeproxy.cpp + qmlmodelnodeproxy.cpp \ + gradientpresetitem.cpp \ + gradientpresetlistmodel.cpp \ + gradientpresetdefaultlistmodel.cpp \ + gradientpresetcustomlistmodel.cpp \ + simplecolorpalette.cpp \ + simplecolorpalettemodel.cpp \ + simplecolorpalettesingleton.cpp HEADERS += propertyeditorview.h \ qmlanchorbindingproxy.h \ @@ -24,6 +31,13 @@ HEADERS += propertyeditorview.h \ propertyeditorwidget.h \ fileresourcesmodel.h \ gradientmodel.h \ - qmlmodelnodeproxy.h + qmlmodelnodeproxy.h \ + gradientpresetitem.h \ + gradientpresetlistmodel.h \ + gradientpresetdefaultlistmodel.h \ + gradientpresetcustomlistmodel.h \ + simplecolorpalette.h \ + simplecolorpalettemodel.h \ + simplecolorpalettesingleton.h QT += qml quick diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index dc8243e1c8..8fdab5a821 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -152,22 +152,14 @@ void PropertyEditorContextObject::toogleExportAlias() PropertyName modelNodeId = selectedNode.id().toUtf8(); ModelNode rootModelNode = rewriterView->rootModelNode(); - try { - RewriterTransaction transaction = - rewriterView->beginRewriterTransaction(QByteArrayLiteral("PropertyEditorContextObject:toogleExportAlias")); - + rewriterView->executeInTransaction("PropertyEditorContextObject:toogleExportAlias", [&objectNode, &rootModelNode, modelNodeId](){ if (!objectNode.isAliasExported()) objectNode.ensureAliasExport(); else if (rootModelNode.hasProperty(modelNodeId)) rootModelNode.removeProperty(modelNodeId); - - transaction.commit(); - } catch (RewritingException &exception) { //better safe than sorry! There always might be cases where we fail - exception.showException(); - } + }); } - } void PropertyEditorContextObject::changeTypeName(const QString &typeName) @@ -181,11 +173,8 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName) QTC_ASSERT(!rewriterView->selectedModelNodes().isEmpty(), return); - ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst(); - - try { - RewriterTransaction transaction = - rewriterView->beginRewriterTransaction(QByteArrayLiteral("PropertyEditorContextObject:changeTypeName")); + rewriterView->executeInTransaction("PropertyEditorContextObject:changeTypeName", [this, rewriterView, typeName](){ + ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst(); NodeMetaInfo metaInfo = m_model->metaInfo(typeName.toLatin1()); if (!metaInfo.isValid()) { @@ -193,16 +182,10 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName) return; } if (selectedNode.isRootNode()) - rewriterView->changeRootNodeType(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); + rewriterView->changeRootNodeType(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); else selectedNode.changeType(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); - - transaction.commit(); - } catch (RewritingException &exception) { //better safe than sorry! There always might be cases where we fail - exception.showException(); - } - - + }); } void PropertyEditorContextObject::insertKeyframe(const QString &propertyName) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 284b6948ee..12f12ed2bc 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -40,6 +40,7 @@ #include <coreplugin/icore.h> #include <qmljs/qmljssimplereader.h> +#include <utils/qtcassert.h> #include <utils/algorithm.h> #include <utils/fileutils.h> @@ -281,13 +282,17 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q setupLayoutAttachedProperties(qmlObjectNode, propertyEditor); + // model node + m_backendModelNode.setup(qmlObjectNode.modelNode()); + context()->setContextProperty(QLatin1String("modelNodeBackend"), &m_backendModelNode); + // className auto valueObject = qobject_cast<PropertyEditorValue*>(variantToQObject(m_backendValuesPropertyMap.value(QLatin1String("className")))); if (!valueObject) valueObject = new PropertyEditorValue(&m_backendValuesPropertyMap); valueObject->setName("className"); valueObject->setModelNode(qmlObjectNode.modelNode()); - valueObject->setValue(qmlObjectNode.modelNode().simplifiedTypeName()); + valueObject->setValue(m_backendModelNode.simplifiedTypeName()); QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged); m_backendValuesPropertyMap.insert(QLatin1String("className"), QVariant::fromValue(valueObject)); @@ -296,7 +301,7 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q if (!valueObject) valueObject = new PropertyEditorValue(&m_backendValuesPropertyMap); valueObject->setName("id"); - valueObject->setValue(qmlObjectNode.id()); + valueObject->setValue(m_backendModelNode.nodeId()); QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged); m_backendValuesPropertyMap.insert(QLatin1String("id"), QVariant::fromValue(valueObject)); @@ -310,10 +315,6 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q qCInfo(propertyEditorBenchmark) << "anchors:" << time.elapsed(); - // model node - m_backendModelNode.setup(qmlObjectNode.modelNode()); - context()->setContextProperty(QLatin1String("modelNodeBackend"), &m_backendModelNode); - qCInfo(propertyEditorBenchmark) << "context:" << time.elapsed(); contextObject()->setSpecificsUrl(qmlSpecificsFile); @@ -402,23 +403,49 @@ QString PropertyEditorQmlBackend::propertyEditorResourcesPath() { QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type, const NodeMetaInfo &superType, - const QmlObjectNode &objectNode) + const QmlObjectNode &node) { if (!templateConfiguration() || !templateConfiguration()->isValid()) return QString(); + const auto nodes = templateConfiguration()->children(); + + QStringList sectorTypes; + + for (const QmlJS::SimpleReaderNode::Ptr &node : nodes) { + if (node->propertyNames().contains("separateSection")) + sectorTypes.append(variantToStringList(node->property("typeNames"))); + } + QStringList imports = variantToStringList(templateConfiguration()->property(QStringLiteral("imports"))); QString qmlTemplate = imports.join(QLatin1Char('\n')) + QLatin1Char('\n'); - qmlTemplate += QStringLiteral("Section {\n"); - qmlTemplate += QStringLiteral("caption: \"%1\"\n").arg(objectNode.modelNode().simplifiedTypeName()); - qmlTemplate += QStringLiteral("SectionLayout {\n"); + + qmlTemplate += "Column {\n"; + qmlTemplate += "anchors.left: parent.left\n"; + qmlTemplate += "anchors.right: parent.right\n"; QList<PropertyName> orderedList = type.propertyNames(); - Utils::sort(orderedList); + Utils::sort(orderedList, [type, §orTypes](const PropertyName &left, const PropertyName &right){ + const QString typeNameLeft = QString::fromLatin1(type.propertyTypeName(left)); + const QString typeNameRight = QString::fromLatin1(type.propertyTypeName(right)); + if (typeNameLeft == typeNameRight) + return left > right; + + if (sectorTypes.contains(typeNameLeft)) { + if (sectorTypes.contains(typeNameRight)) + return left > right; + return true; + } else if (sectorTypes.contains(typeNameRight)) { + return false; + } + return left > right; + }); bool emptyTemplate = true; + bool sectionStarted = false; + foreach (const PropertyName &name, orderedList) { if (name.startsWith("__")) @@ -429,18 +456,38 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type, TypeName typeName = type.propertyTypeName(name); //alias resolution only possible with instance - if (typeName == "alias" && objectNode.isValid()) - typeName = objectNode.instanceType(name); + if (typeName == "alias" && node.isValid()) + typeName = node.instanceType(name); + + auto nodes = templateConfiguration()->children(); if (!superType.hasProperty(name) && type.propertyIsWritable(name) && !name.contains(".")) { - foreach (const QmlJS::SimpleReaderNode::Ptr &node, templateConfiguration()->children()) + + foreach (const QmlJS::SimpleReaderNode::Ptr &node, nodes) if (variantToStringList(node->property(QStringLiteral("typeNames"))).contains(QString::fromLatin1(typeName))) { const QString fileName = propertyTemplatesPath() + node->property(QStringLiteral("sourceFile")).toString(); QFile file(fileName); if (file.open(QIODevice::ReadOnly)) { QString source = QString::fromUtf8(file.readAll()); file.close(); + const bool section = node->propertyNames().contains("separateSection"); + if (section) { + qmlTemplate += "Section {\n"; + qmlTemplate += "anchors.left: parent.left\n"; + qmlTemplate += "anchors.right: parent.right\n"; + qmlTemplate += QString("caption: \"%1\"\n").arg(QString::fromUtf8(properName)); + } else if (!sectionStarted) { + qmlTemplate += QStringLiteral("Section {\n"); + qmlTemplate += QStringLiteral("caption: \"%1\"\n").arg(QString::fromUtf8(type.simplifiedTypeName())); + qmlTemplate += "anchors.left: parent.left\n"; + qmlTemplate += "anchors.right: parent.right\n"; + qmlTemplate += QStringLiteral("SectionLayout {\n"); + sectionStarted = true; + } + qmlTemplate += source.arg(QString::fromUtf8(name)).arg(QString::fromUtf8(properName)); + if (section) + qmlTemplate += "}\n"; emptyTemplate = false; } else { qWarning().nospace() << "template definition source file not found:" << fileName; @@ -448,8 +495,12 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type, } } } - qmlTemplate += QStringLiteral("}\n"); //Section - qmlTemplate += QStringLiteral("}\n"); //SectionLayout + if (sectionStarted) { + qmlTemplate += QStringLiteral("}\n"); //Section + qmlTemplate += QStringLiteral("}\n"); //SectionLayout + } + + qmlTemplate += "}\n"; if (emptyTemplate) return QString(); @@ -469,6 +520,36 @@ TypeName PropertyEditorQmlBackend::fixTypeNameForPanes(const TypeName &typeName) return fixedTypeName; } +static NodeMetaInfo findCommonSuperClass(const NodeMetaInfo &first, const NodeMetaInfo &second) +{ + for (const NodeMetaInfo &info : first.superClasses()) { + if (second.isSubclassOf(info.typeName())) + return info; + } + return first; +} + +NodeMetaInfo PropertyEditorQmlBackend::findCommonAncestor(const ModelNode &node) +{ + if (!node.isValid()) + return {}; + + QTC_ASSERT(node.metaInfo().isValid(), return {}); + + AbstractView *view = node.view(); + + if (view->selectedModelNodes().count() > 1) { + NodeMetaInfo commonClass = node.metaInfo(); + for (const ModelNode ¤tNode : view->selectedModelNodes()) { + if (currentNode.metaInfo().isValid() && !currentNode.isSubclassOf(commonClass.typeName(), -1, -1)) + commonClass = findCommonSuperClass(currentNode.metaInfo(), commonClass); + } + return commonClass; + } + + return node.metaInfo(); +} + TypeName PropertyEditorQmlBackend::qmlFileName(const NodeMetaInfo &nodeInfo) { const TypeName fixedTypeName = fixTypeNameForPanes(nodeInfo.typeName()); @@ -526,10 +607,10 @@ void PropertyEditorQmlBackend::setValueforLayoutAttachedProperties(const QmlObje setValue(qmlObjectNode, name, properDefaultLayoutAttachedProperties(qmlObjectNode, propertyName)); } -QUrl PropertyEditorQmlBackend::getQmlUrlForModelNode(const ModelNode &modelNode, TypeName &className) +QUrl PropertyEditorQmlBackend::getQmlUrlForMetaInfo(const NodeMetaInfo &metaInfo, TypeName &className) { - if (modelNode.isValid()) { - foreach (const NodeMetaInfo &info, modelNode.metaInfo().classHierarchy()) { + if (metaInfo.isValid()) { + foreach (const NodeMetaInfo &info, metaInfo.classHierarchy()) { QUrl fileUrl = fileToUrl(locateQmlFile(info, QString::fromUtf8(qmlFileName(info)))); if (fileUrl.isValid()) { className = info.typeName(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h index a0012a1cc1..51279a1fc6 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h @@ -68,11 +68,10 @@ public: PropertyEditorValue *propertyValueForName(const QString &propertyName); static QString propertyEditorResourcesPath(); - static QString templateGeneration(const NodeMetaInfo &type, const NodeMetaInfo &superType, - const QmlObjectNode &objectNode); + static QString templateGeneration(const NodeMetaInfo &type, const NodeMetaInfo &superType, const QmlObjectNode &node); static QUrl getQmlFileUrl(const TypeName &relativeTypeName, const NodeMetaInfo &info = NodeMetaInfo()); - static QUrl getQmlUrlForModelNode(const ModelNode &modelNode, TypeName &className); + static QUrl getQmlUrlForMetaInfo(const NodeMetaInfo &modelNode, TypeName &className); static bool checkIfUrlExists(const QUrl &url); @@ -83,6 +82,8 @@ public: void setupLayoutAttachedProperties(const QmlObjectNode &qmlObjectNode, PropertyEditorView *propertyEditor); + static NodeMetaInfo findCommonAncestor(const ModelNode &node); + private: void createPropertyEditorValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value, diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 0467355bf4..9dd0a2da24 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -213,20 +213,13 @@ void PropertyEditorView::changeValue(const QString &name) castedValue = QVariant(newColor); } - try { - if (!value->value().isValid()) { //reset - qmlObjectNode.removeProperty(propertyName); - } else { - if (castedValue.isValid() && !castedValue.isNull()) { - m_locked = true; - qmlObjectNode.setVariantProperty(propertyName, castedValue); - m_locked = false; - } + if (!value->value().isValid()) { //reset + removePropertyFromModel(propertyName); + } else { + if (castedValue.isValid() && !castedValue.isNull()) { + commitVariantValueToModel(propertyName, castedValue); } } - catch (const RewritingException &e) { - e.showException(); - } } void PropertyEditorView::changeExpression(const QString &propertyName) @@ -242,9 +235,7 @@ void PropertyEditorView::changeExpression(const QString &propertyName) if (!m_selectedNode.isValid()) return; - RewriterTransaction transaction = beginRewriterTransaction(QByteArrayLiteral("PropertyEditorView::changeExpression")); - - try { + executeInTransaction("PropertyEditorView::changeExpression", [this, name](){ PropertyName underscoreName(name); underscoreName.replace('.', '_'); @@ -260,7 +251,6 @@ void PropertyEditorView::changeExpression(const QString &propertyName) if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "QColor") { if (QColor(value->expression().remove('"')).isValid()) { qmlObjectNode.setVariantProperty(name, QColor(value->expression().remove('"'))); - transaction.commit(); //committing in the try block return; } } else if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "bool") { @@ -270,7 +260,6 @@ void PropertyEditorView::changeExpression(const QString &propertyName) qmlObjectNode.setVariantProperty(name, true); else qmlObjectNode.setVariantProperty(name, false); - transaction.commit(); //committing in the try block return; } } else if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "int") { @@ -278,7 +267,6 @@ void PropertyEditorView::changeExpression(const QString &propertyName) int intValue = value->expression().toInt(&ok); if (ok) { qmlObjectNode.setVariantProperty(name, intValue); - transaction.commit(); //committing in the try block return; } } else if (qmlObjectNode.modelNode().metaInfo().propertyTypeName(name) == "qreal") { @@ -286,7 +274,6 @@ void PropertyEditorView::changeExpression(const QString &propertyName) qreal realValue = value->expression().toDouble(&ok); if (ok) { qmlObjectNode.setVariantProperty(name, realValue); - transaction.commit(); //committing in the try block return; } } @@ -298,12 +285,7 @@ void PropertyEditorView::changeExpression(const QString &propertyName) if (qmlObjectNode.expression(name) != value->expression() || !qmlObjectNode.propertyAffectedByCurrentState(name)) qmlObjectNode.setBindingProperty(name, value->expression()); - transaction.commit(); //committing in the try block - } - - catch (const RewritingException &e) { - e.showException(); - } + }); /* end of transaction */ } void PropertyEditorView::exportPopertyAsAlias(const QString &name) @@ -317,9 +299,7 @@ void PropertyEditorView::exportPopertyAsAlias(const QString &name) if (!m_selectedNode.isValid()) return; - RewriterTransaction transaction = beginRewriterTransaction(QByteArrayLiteral("PropertyEditorView::exportPopertyAsAlias")); - - try { + executeInTransaction("PropertyEditorView::exportPopertyAsAlias", [this, name](){ const QString id = m_selectedNode.validId(); QString upperCasePropertyName = name; upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper()); @@ -333,11 +313,7 @@ void PropertyEditorView::exportPopertyAsAlias(const QString &name) return; } rootModelNode().bindingProperty(propertyName).setDynamicTypeNameAndExpression("alias", id + "." + name); - - transaction.commit(); //committing in the try block - } catch (const RewritingException &e) { - e.showException(); - } + }); } void PropertyEditorView::removeAliasExport(const QString &name) @@ -351,9 +327,7 @@ void PropertyEditorView::removeAliasExport(const QString &name) if (!m_selectedNode.isValid()) return; - RewriterTransaction transaction = beginRewriterTransaction(QByteArrayLiteral("PropertyEditorView::exportPopertyAsAlias")); - - try { + executeInTransaction("PropertyEditorView::exportPopertyAsAlias", [this, name](){ const QString id = m_selectedNode.validId(); for (const BindingProperty &property : rootModelNode().bindingProperties()) @@ -361,10 +335,7 @@ void PropertyEditorView::removeAliasExport(const QString &name) rootModelNode().removeProperty(property.name()); break; } - transaction.commit(); //committing in the try block - } catch (const RewritingException &e) { - e.showException(); - } + }); } bool PropertyEditorView::locked() const @@ -446,13 +417,16 @@ void PropertyEditorView::resetView() void PropertyEditorView::setupQmlBackend() { TypeName specificsClassName; - QUrl qmlFile(PropertyEditorQmlBackend::getQmlUrlForModelNode(m_selectedNode, specificsClassName)); + + const NodeMetaInfo commonAncestor = PropertyEditorQmlBackend::findCommonAncestor(m_selectedNode); + + const QUrl qmlFile(PropertyEditorQmlBackend::getQmlUrlForMetaInfo(commonAncestor, specificsClassName)); QUrl qmlSpecificsFile; TypeName diffClassName; - if (m_selectedNode.isValid()) { - diffClassName = m_selectedNode.metaInfo().typeName(); - foreach (const NodeMetaInfo &metaInfo, m_selectedNode.metaInfo().classHierarchy()) { + if (commonAncestor.isValid()) { + diffClassName = commonAncestor.typeName(); + foreach (const NodeMetaInfo &metaInfo, commonAncestor.classHierarchy()) { if (PropertyEditorQmlBackend::checkIfUrlExists(qmlSpecificsFile)) break; qmlSpecificsFile = PropertyEditorQmlBackend::getQmlFileUrl(metaInfo.typeName() + "Specifics", metaInfo); @@ -465,8 +439,8 @@ void PropertyEditorView::setupQmlBackend() QString specificQmlData; - if (m_selectedNode.isValid() && m_selectedNode.metaInfo().isValid() && diffClassName != m_selectedNode.type()) - specificQmlData = PropertyEditorQmlBackend::templateGeneration(m_selectedNode.metaInfo(), model()->metaInfo(diffClassName), m_selectedNode); + if (commonAncestor.isValid() && m_selectedNode.metaInfo().isValid() && diffClassName != m_selectedNode.type()) + specificQmlData = PropertyEditorQmlBackend::templateGeneration(commonAncestor, model()->metaInfo(diffClassName), m_selectedNode); PropertyEditorQmlBackend *currentQmlBackend = m_qmlBackendHash.value(qmlFile.toString()); @@ -515,14 +489,51 @@ void PropertyEditorView::setupQmlBackend() } +void PropertyEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value) +{ + m_locked = true; + try { + RewriterTransaction transaction = beginRewriterTransaction("PropertyEditorView::commitVariantValueToMode"); + + for (const ModelNode &node : m_selectedNode.view()->selectedModelNodes()) { + if (QmlObjectNode::isValidQmlObjectNode(node)) + QmlObjectNode(node).setVariantProperty(propertyName, value); + } + transaction.commit(); + } + catch (const RewritingException &e) { + e.showException(); + } + m_locked = false; +} + +void PropertyEditorView::removePropertyFromModel(const PropertyName &propertyName) +{ + m_locked = true; + try { + RewriterTransaction transaction = beginRewriterTransaction("PropertyEditorView::removePropertyFromModel"); + + for (const ModelNode &node : m_selectedNode.view()->selectedModelNodes()) { + if (QmlObjectNode::isValidQmlObjectNode(node)) + QmlObjectNode(node).removeProperty(propertyName); + } + + transaction.commit(); + } + catch (const RewritingException &e) { + e.showException(); + } + m_locked = false; +} + void PropertyEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList, const QList<ModelNode> &lastSelectedNodeList) { Q_UNUSED(lastSelectedNodeList); - if (selectedNodeList.isEmpty() || selectedNodeList.count() > 1) + if (selectedNodeList.isEmpty()) select(ModelNode()); - else if (m_selectedNode != selectedNodeList.constFirst()) + else select(selectedNodeList.constFirst()); } @@ -542,10 +553,11 @@ void PropertyEditorView::modelAttached(Model *model) m_locked = true; if (!m_setupCompleted) { - m_singleShotTimer->setSingleShot(true); - m_singleShotTimer->setInterval(100); - connect(m_singleShotTimer, &QTimer::timeout, this, &PropertyEditorView::setupPanes); - m_singleShotTimer->start(); + QTimer::singleShot(50, this, [this]{ + PropertyEditorView::setupPanes(); + /* workaround for QTBUG-75847 */ + reloadQml(); + }); } m_locked = false; @@ -648,6 +660,9 @@ void PropertyEditorView::instanceInformationsChanged(const QMultiHash<ModelNode, if (!m_selectedNode.isValid()) return; + if (!m_qmlBackEndForCurrentType) + return; + m_locked = true; QList<InformationName> informationNameList = informationChangedHash.values(m_selectedNode); if (informationNameList.contains(Anchor) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 85bd8286f5..e7f57cf186 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -110,6 +110,9 @@ private: //functions void delayedResetView(); void setupQmlBackend(); + void commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value); + void removePropertyFromModel(const PropertyName &propertyName); + private: //variables ModelNode m_selectedNode; QWidget *m_parent; diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp index bc6b4376b6..7a38f74f34 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp @@ -292,9 +292,9 @@ void QmlAnchorBindingProxy::setDefaultRelativeRightTarget() } } -RewriterTransaction QmlAnchorBindingProxy::beginRewriterTransaction(const QByteArray &identifier) +bool QmlAnchorBindingProxy::executeInTransaction(const QByteArray &identifier, const AbstractView::OperationBlock &lambda) { - return m_qmlItemNode.modelNode().view()->beginRewriterTransaction(identifier); + return m_qmlItemNode.modelNode().view()->executeInTransaction(identifier, lambda); } bool QmlAnchorBindingProxy::hasParent() const @@ -361,20 +361,11 @@ void QmlAnchorBindingProxy::setTopTarget(const QString &target) if (!newTarget.isValid()) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setTopTarget")); - + executeInTransaction("QmlAnchorBindingProxy::setTopTarget", [this, newTarget](){ m_topTarget = newTarget; - setDefaultRelativeTopTarget(); - anchorTop(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit topTargetChanged(); } @@ -393,18 +384,12 @@ void QmlAnchorBindingProxy::setBottomTarget(const QString &target) if (!newTarget.isValid()) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setBottomTarget")); - + executeInTransaction("QmlAnchorBindingProxy::setBottomTarget", [this, newTarget](){ m_bottomTarget = newTarget; setDefaultRelativeBottomTarget(); anchorBottom(); - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit bottomTargetChanged(); } @@ -422,18 +407,11 @@ void QmlAnchorBindingProxy::setLeftTarget(const QString &target) if (!newTarget.isValid()) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setLeftTarget")); - + executeInTransaction("QmlAnchorBindingProxy::setLeftTarget", [this, newTarget](){ m_leftTarget = newTarget; setDefaultRelativeLeftTarget(); anchorLeft(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit leftTargetChanged(); } @@ -451,18 +429,11 @@ void QmlAnchorBindingProxy::setRightTarget(const QString &target) if (!newTarget.isValid()) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRightTarget")); - + executeInTransaction("QmlAnchorBindingProxy::setRightTarget", [this, newTarget](){ m_rightTarget = newTarget; setDefaultRelativeRightTarget(); anchorRight(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit rightTargetChanged(); } @@ -480,17 +451,10 @@ void QmlAnchorBindingProxy::setVerticalTarget(const QString &target) if (!newTarget.isValid()) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setVerticalTarget")); - + executeInTransaction("QmlAnchorBindingProxy::setVerticalTarget", [this, newTarget](){ m_verticalTarget = newTarget; anchorVertical(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit verticalTargetChanged(); } @@ -508,17 +472,10 @@ void QmlAnchorBindingProxy::setHorizontalTarget(const QString &target) if (!newTarget.isValid()) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setHorizontalTarget")); - + executeInTransaction("QmlAnchorBindingProxy::setHorizontalTarget", [this, newTarget](){ m_horizontalTarget = newTarget; - anchorHorizontal();\ - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + anchorHorizontal(); + }); emit horizontalTargetChanged(); } @@ -531,18 +488,10 @@ void QmlAnchorBindingProxy::setRelativeAnchorTargetTop(QmlAnchorBindingProxy::Re if (target == m_relativeTopTarget) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRelativeAnchorTargetTop")); - + executeInTransaction("QmlAnchorBindingProxy::setRelativeAnchorTargetTop", [this, target](){ m_relativeTopTarget = target; - anchorTop(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetTopChanged(); } @@ -555,19 +504,10 @@ void QmlAnchorBindingProxy::setRelativeAnchorTargetBottom(QmlAnchorBindingProxy: if (target == m_relativeBottomTarget) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRelativeAnchorTargetBottom")); - + executeInTransaction("QmlAnchorBindingProxy::setRelativeAnchorTargetBottom", [this, target](){ m_relativeBottomTarget = target; - - anchorBottom(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetBottomChanged(); } @@ -580,18 +520,11 @@ void QmlAnchorBindingProxy::setRelativeAnchorTargetLeft(QmlAnchorBindingProxy::R if (target == m_relativeLeftTarget) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRelativeAnchorTargetLeft")); - + executeInTransaction("QmlAnchorBindingProxy::setRelativeAnchorTargetLeft", [this, target](){ m_relativeLeftTarget = target; - anchorLeft(); - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetLeftChanged(); } @@ -604,18 +537,10 @@ void QmlAnchorBindingProxy::setRelativeAnchorTargetRight(QmlAnchorBindingProxy:: if (target == m_relativeRightTarget) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRelativeAnchorTargetRight")); - + executeInTransaction("QmlAnchorBindingProxy::setRelativeAnchorTargetRight", [this, target](){ m_relativeRightTarget = target; - anchorRight(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetRightChanged(); @@ -629,18 +554,11 @@ void QmlAnchorBindingProxy::setRelativeAnchorTargetVertical(QmlAnchorBindingProx if (target == m_relativeVerticalTarget) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRelativeAnchorTargetVertical")); + executeInTransaction("QmlAnchorBindingProxy::setRelativeAnchorTargetVertical", [this, target](){ m_relativeVerticalTarget = target; - anchorVertical(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetVerticalChanged(); } @@ -653,18 +571,10 @@ void QmlAnchorBindingProxy::setRelativeAnchorTargetHorizontal(QmlAnchorBindingPr if (target == m_relativeHorizontalTarget) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRelativeAnchorTargetHorizontal")); - + executeInTransaction("QmlAnchorBindingProxy::setRelativeAnchorTargetHorizontal", [this, target](){ m_relativeHorizontalTarget = target; - anchorHorizontal(); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetHorizontalChanged(); } @@ -709,12 +619,10 @@ int QmlAnchorBindingProxy::indexOfPossibleTargetItem(const QString &targetName) return possibleTargetItems().indexOf(targetName); } -void QmlAnchorBindingProxy::resetLayout() { - - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::resetLayout")); +void QmlAnchorBindingProxy::resetLayout() +{ + executeInTransaction("QmlAnchorBindingProxy::resetLayout", [this](){ m_qmlItemNode.anchors().removeAnchors(); m_qmlItemNode.anchors().removeMargins(); @@ -722,11 +630,7 @@ void QmlAnchorBindingProxy::resetLayout() { restoreProperty(modelNode(), "y"); restoreProperty(modelNode(), "width"); restoreProperty(modelNode(), "height"); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit topAnchorChanged(); emit bottomAnchorChanged(); @@ -743,10 +647,7 @@ void QmlAnchorBindingProxy::setBottomAnchor(bool anchor) if (bottomAnchored() == anchor) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setBottomAnchor")); - + executeInTransaction("QmlAnchorBindingProxy::setBottomAnchor", [this, anchor](){ if (!anchor) { removeBottomAnchor(); } else { @@ -756,10 +657,7 @@ void QmlAnchorBindingProxy::setBottomAnchor(bool anchor) backupPropertyAndRemove(modelNode(), "height"); } - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetBottomChanged(); emit bottomAnchorChanged(); @@ -776,10 +674,8 @@ void QmlAnchorBindingProxy::setLeftAnchor(bool anchor) if (leftAnchored() == anchor) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setLeftAnchor")); + executeInTransaction("QmlAnchorBindingProxy::setLeftAnchor", [this, anchor](){ if (!anchor) { removeLeftAnchor(); } else { @@ -791,10 +687,7 @@ void QmlAnchorBindingProxy::setLeftAnchor(bool anchor) backupPropertyAndRemove(modelNode(), "width"); } - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetLeftChanged(); emit leftAnchorChanged(); @@ -810,10 +703,7 @@ void QmlAnchorBindingProxy::setRightAnchor(bool anchor) if (rightAnchored() == anchor) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setRightAnchor")); - + executeInTransaction("QmlAnchorBindingProxy::setRightAnchor", [this, anchor](){ if (!anchor) { removeRightAnchor(); } else { @@ -824,10 +714,7 @@ void QmlAnchorBindingProxy::setRightAnchor(bool anchor) backupPropertyAndRemove(modelNode(), "width"); } - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetRightChanged(); emit rightAnchorChanged(); @@ -1026,10 +913,7 @@ void QmlAnchorBindingProxy::setTopAnchor(bool anchor) if (topAnchored() == anchor) return; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setTopAnchor")); - + executeInTransaction("QmlAnchorBindingProxy::setTopAnchor", [this, anchor](){ if (!anchor) { removeTopAnchor(); } else { @@ -1040,10 +924,7 @@ void QmlAnchorBindingProxy::setTopAnchor(bool anchor) if (bottomAnchored()) backupPropertyAndRemove(modelNode(), "height"); } - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit relativeAnchorTargetTopChanged(); emit topAnchorChanged(); @@ -1052,70 +933,44 @@ void QmlAnchorBindingProxy::setTopAnchor(bool anchor) } void QmlAnchorBindingProxy::removeTopAnchor() { - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::removeTopAnchor")); - + executeInTransaction("QmlAnchorBindingProxy::removeTopAnchor", [this](){ m_qmlItemNode.anchors().removeAnchor(AnchorLineTop); m_qmlItemNode.anchors().removeMargin(AnchorLineTop); restoreProperty(modelNode(), "y"); restoreProperty(modelNode(), "height"); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); } -void QmlAnchorBindingProxy::removeBottomAnchor() { - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::removeBottomAnchor")); - +void QmlAnchorBindingProxy::removeBottomAnchor() +{ + executeInTransaction("QmlAnchorBindingProxy::removeBottomAnchor", [this](){ m_qmlItemNode.anchors().removeAnchor(AnchorLineBottom); m_qmlItemNode.anchors().removeMargin(AnchorLineBottom); - restoreProperty(modelNode(), "height"); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); } -void QmlAnchorBindingProxy::removeLeftAnchor() { - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::removeLeftAnchor")); - +void QmlAnchorBindingProxy::removeLeftAnchor() +{ + executeInTransaction("QmlAnchorBindingProxy::removeLeftAnchor", [this](){ m_qmlItemNode.anchors().removeAnchor(AnchorLineLeft); m_qmlItemNode.anchors().removeMargin(AnchorLineLeft); restoreProperty(modelNode(), "x"); restoreProperty(modelNode(), "width"); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); } -void QmlAnchorBindingProxy::removeRightAnchor() { - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::removeRightAnchor")); - +void QmlAnchorBindingProxy::removeRightAnchor() +{ + executeInTransaction("QmlAnchorBindingProxy::removeRightAnchor", [this](){ m_qmlItemNode.anchors().removeAnchor(AnchorLineRight); m_qmlItemNode.anchors().removeMargin(AnchorLineRight); restoreProperty(modelNode(), "width"); - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); } void QmlAnchorBindingProxy::setVerticalCentered(bool centered) @@ -1128,10 +983,7 @@ void QmlAnchorBindingProxy::setVerticalCentered(bool centered) m_locked = true; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setVerticalCentered")); - + executeInTransaction("QmlAnchorBindingProxy::setVerticalCentered", [this, centered](){ if (!centered) { m_qmlItemNode.anchors().removeAnchor(AnchorLineVerticalCenter); m_qmlItemNode.anchors().removeMargin(AnchorLineVerticalCenter); @@ -1141,10 +993,7 @@ void QmlAnchorBindingProxy::setVerticalCentered(bool centered) anchorVertical(); } - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); m_locked = false; emit relativeAnchorTargetVerticalChanged(); @@ -1161,10 +1010,7 @@ void QmlAnchorBindingProxy::setHorizontalCentered(bool centered) m_locked = true; - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::setHorizontalCentered")); - + executeInTransaction("QmlAnchorBindingProxy::setHorizontalCentered", [this, centered](){ if (!centered) { m_qmlItemNode.anchors().removeAnchor(AnchorLineHorizontalCenter); m_qmlItemNode.anchors().removeMargin(AnchorLineHorizontalCenter); @@ -1173,11 +1019,7 @@ void QmlAnchorBindingProxy::setHorizontalCentered(bool centered) anchorHorizontal(); } - - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); m_locked = false; emit relativeAnchorTargetHorizontalChanged(); @@ -1256,12 +1098,7 @@ bool QmlAnchorBindingProxy::horizontalCentered() void QmlAnchorBindingProxy::fill() { - - try { - RewriterTransaction transaction = beginRewriterTransaction( - QByteArrayLiteral("QmlAnchorBindingProxy::fill")); - - + executeInTransaction("QmlAnchorBindingProxy::fill", [this](){ backupPropertyAndRemove(modelNode(), "x"); backupPropertyAndRemove(modelNode(), "y"); backupPropertyAndRemove(modelNode(), "width"); @@ -1277,10 +1114,7 @@ void QmlAnchorBindingProxy::fill() m_qmlItemNode.anchors().removeMargin(AnchorLineTop); m_qmlItemNode.anchors().removeMargin(AnchorLineBottom); - transaction.commit(); - } catch (const Exception &e) { - e.showException(); - } + }); emit topAnchorChanged(); emit bottomAnchorChanged(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.h b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.h index cf42ea055a..0bd562add2 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.h +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.h @@ -210,7 +210,7 @@ private: void setDefaultRelativeLeftTarget(); void setDefaultRelativeRightTarget(); - RewriterTransaction beginRewriterTransaction(const QByteArray &identifier); + bool executeInTransaction(const QByteArray &identifier, const AbstractView::OperationBlock &lambda); QmlItemNode targetIdToNode(const QString &id) const; QString idForNode(const QmlItemNode &qmlItemNode) const; diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp index 6f56b055c8..934c284691 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "abstractview.h" #include "qmlmodelnodeproxy.h" #include <QtQml> @@ -66,4 +67,34 @@ ModelNode QmlModelNodeProxy::modelNode() const return m_qmlItemNode.modelNode(); } +bool QmlModelNodeProxy::multiSelection() const +{ + if (!m_qmlItemNode.isValid()) + return false; + + return m_qmlItemNode.view()->selectedModelNodes().count() > 1; +} + +QString QmlModelNodeProxy::nodeId() const +{ + if (!m_qmlItemNode.isValid()) + return {}; + + if (multiSelection()) + return tr("multiselection"); + + return m_qmlItemNode.id(); +} + +QString QmlModelNodeProxy::simplifiedTypeName() const +{ + if (!m_qmlItemNode.isValid()) + return {}; + + if (multiSelection()) + return tr("multiselection"); + + return m_qmlItemNode.simplifiedTypeName(); +} + } diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h index 0a73583355..6037f32752 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h @@ -35,7 +35,8 @@ class QmlModelNodeProxy : public QObject { Q_OBJECT - Q_PROPERTY(QmlDesigner::ModelNode modelNode READ modelNode NOTIFY modelNodeChanged) + Q_PROPERTY(QmlDesigner::ModelNode modelNode READ modelNode NOTIFY modelNodeChanged) + Q_PROPERTY(bool multiSelection READ multiSelection NOTIFY modelNodeChanged) public: explicit QmlModelNodeProxy(QObject *parent = nullptr); @@ -51,6 +52,12 @@ public: ModelNode modelNode() const; + bool multiSelection() const; + + QString nodeId() const; + + QString simplifiedTypeName() const; + signals: void modelNodeChanged(); void selectionToBeChanged(); diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp index 4e58374759..862d16ba22 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp @@ -28,6 +28,9 @@ #include "propertyeditorvalue.h" #include "fileresourcesmodel.h" #include "gradientmodel.h" +#include "gradientpresetdefaultlistmodel.h" +#include "gradientpresetcustomlistmodel.h" +#include "simplecolorpalettemodel.h" #include "qmlanchorbindingproxy.h" #include "theme.h" @@ -48,6 +51,9 @@ void Quick2PropertyEditorView::registerQmlTypes() PropertyEditorValue::registerDeclarativeTypes(); FileResourcesModel::registerDeclarativeType(); GradientModel::registerDeclarativeType(); + GradientPresetDefaultListModel::registerDeclarativeType(); + GradientPresetCustomListModel::registerDeclarativeType(); + SimpleColorPaletteModel::registerDeclarativeType(); Internal::QmlAnchorBindingProxy::registerDeclarativeType(); } } diff --git a/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalette.cpp b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalette.cpp new file mode 100644 index 0000000000..c88d83aa0a --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalette.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 "simplecolorpalette.h" + +#include "designersettings.h" + +#include <QDebug> + +namespace QmlDesigner { + +PaletteColor::PaletteColor() + : m_color(QColor()) + , m_colorCode(QColor().name()) + , m_isFavorite(false) +{} + +PaletteColor::PaletteColor(const QString &colorCode) + : m_color(colorCode) + , m_colorCode(colorCode) + , m_isFavorite(false) +{} + +PaletteColor::PaletteColor(const QColor &color) + : m_color(color) + , m_colorCode(color.name(QColor::HexArgb)) + , m_isFavorite(false) +{} + +QVariant PaletteColor::getProperty(Property id) const +{ + QVariant out; + + switch (id) { + case objectNameRole: + out.setValue(QString()); + break; + case colorRole: + out.setValue(color()); + break; + case colorCodeRole: + out.setValue(colorCode()); + break; + case isFavoriteRole: + out.setValue(isFavorite()); + break; + default: + qWarning() << "PaletteColor Property switch default case"; + break; //replace with assert before switch? + } + + return out; +} + +QColor PaletteColor::color() const +{ + return m_color; +} + +void PaletteColor::setColor(const QColor &value) +{ + m_color = value; + m_colorCode = m_color.name(QColor::HexArgb); +} + +QString PaletteColor::colorCode() const +{ + return m_colorCode; +} + +bool PaletteColor::isFavorite() const +{ + return m_isFavorite; +} + +void PaletteColor::setFavorite(bool favorite) +{ + m_isFavorite = favorite; +} + +bool PaletteColor::toggleFavorite() +{ + return m_isFavorite = !m_isFavorite; +} + +bool PaletteColor::operator==(const PaletteColor &other) const +{ + return (m_color == other.m_color); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalette.h b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalette.h new file mode 100644 index 0000000000..342c9832e7 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalette.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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. +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QtQml/qqml.h> +#include <QColor> + +namespace QmlDesigner { + +class PaletteColor +{ + Q_GADGET + + Q_PROPERTY(QColor color READ color FINAL) + Q_PROPERTY(QString colorCode READ colorCode FINAL) + Q_PROPERTY(bool isFavorite READ isFavorite FINAL) +public: + PaletteColor(); + PaletteColor(const QString &colorCode); + PaletteColor(const QColor &value); + ~PaletteColor() = default; + + enum Property { + objectNameRole = 0, + colorRole = 1, + colorCodeRole = 2, + isFavoriteRole = 3 + }; + + QVariant getProperty(Property id) const; + + QColor color() const; + void setColor(const QColor &value); + + QString colorCode() const; + + bool isFavorite() const; + void setFavorite(bool favorite); + bool toggleFavorite(); + + bool operator==(const PaletteColor &other) const; + +private: + QColor m_color; + QString m_colorCode; + bool m_isFavorite; +}; + +} // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::PaletteColor) diff --git a/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettemodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettemodel.cpp new file mode 100644 index 0000000000..b3207f0006 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettemodel.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 "simplecolorpalettemodel.h" +#include "simplecolorpalette.h" +#include "simplecolorpalettesingleton.h" + +#include "designersettings.h" + +#include <QHash> +#include <QByteArray> +#include <QDebug> +#include <QSettings> + +namespace QmlDesigner { + +SimpleColorPaletteModel::SimpleColorPaletteModel(QObject *parent) + : QAbstractListModel(parent) +{ + connect(&SimpleColorPaletteSingleton::getInstance(), + &SimpleColorPaletteSingleton::paletteChanged, + this, + &SimpleColorPaletteModel::setPalette); + m_roleNames = {{static_cast<int>(PaletteColor::Property::objectNameRole), "objectName"}, + {static_cast<int>(PaletteColor::Property::colorRole), "color"}, + {static_cast<int>(PaletteColor::Property::colorCodeRole), "colorCode"}, + {static_cast<int>(PaletteColor::Property::isFavoriteRole), "isFavorite"}}; + + setPalette(); +} + +SimpleColorPaletteModel::~SimpleColorPaletteModel() +{ + clearItems(); +} + +int SimpleColorPaletteModel::rowCount(const QModelIndex & /*parent*/) const +{ + return m_items.count(); +} + +QVariant SimpleColorPaletteModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && (index.row() >= 0) && (index.row() < m_items.count())) { + if (m_roleNames.contains(role)) { + QVariant value = m_items.at(index.row()) + .getProperty(static_cast<PaletteColor::Property>(role)); + if (auto model = qobject_cast<SimpleColorPaletteModel *>(value.value<QObject *>())) + return QVariant::fromValue(model); + + return value; + } + + qWarning() << Q_FUNC_INFO << "invalid role requested"; + return QVariant(); + } + + qWarning() << Q_FUNC_INFO << "invalid index requested"; + return QVariant(); +} + +QHash<int, QByteArray> SimpleColorPaletteModel::roleNames() const +{ + return m_roleNames; +} + +void SimpleColorPaletteModel::clearItems() +{ + beginResetModel(); + m_items.clear(); + endResetModel(); +} + +void SimpleColorPaletteModel::addItem(const QString &item) +{ + PaletteColor palette(item); + addItem(palette); +} + +void SimpleColorPaletteModel::addItem(const PaletteColor &item) +{ + SimpleColorPaletteSingleton::getInstance().addItem(item); +} + +const QList<PaletteColor> &SimpleColorPaletteModel::items() const +{ + return m_items; +} + +void SimpleColorPaletteModel::sortItems() +{ + SimpleColorPaletteSingleton::getInstance().sortItems(); +} + +void SimpleColorPaletteModel::registerDeclarativeType() +{ + qmlRegisterType<SimpleColorPaletteModel>("HelperWidgets", 2, 0, "SimpleColorPaletteModel"); +} + +void SimpleColorPaletteModel::toggleFavorite(int id) +{ + SimpleColorPaletteSingleton::getInstance().toggleFavorite(id); +} + +void SimpleColorPaletteModel::setPalette() +{ + beginResetModel(); + m_items = SimpleColorPaletteSingleton::getInstance().getItems(); + m_favoriteOffset = SimpleColorPaletteSingleton::getInstance().getFavoriteOffset(); + m_paletteSize = SimpleColorPaletteSingleton::getInstance().getPaletteSize(); + endResetModel(); +} + +bool SimpleColorPaletteModel::read() +{ + return SimpleColorPaletteSingleton::getInstance().readPalette(); +} + +void SimpleColorPaletteModel::write() +{ + SimpleColorPaletteSingleton::getInstance().writePalette(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettemodel.h b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettemodel.h new file mode 100644 index 0000000000..3ed2cc8a31 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettemodel.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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. +** +****************************************************************************/ + +#pragma once + +#include <QAbstractListModel> +#include <QtQml/qqml.h> +#include <QList> + +namespace QmlDesigner { + +class PaletteColor; + +class SimpleColorPaletteModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit SimpleColorPaletteModel(QObject *parent = nullptr); + ~SimpleColorPaletteModel() override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash<int, QByteArray> roleNames() const override; + + void clearItems(); + Q_INVOKABLE void addItem(const QString &item); + void addItem(const PaletteColor &item); + + const QList<PaletteColor> &items() const; + + void sortItems(); + + static void registerDeclarativeType(); + + Q_INVOKABLE void toggleFavorite(int id); + + bool read(); + void write(); + +private slots: + void setPalette(); + +private: + void enqueue(const PaletteColor &item); + +private: + int m_paletteSize; + int m_favoriteOffset; + QList<PaletteColor> m_items; + QHash<int, QByteArray> m_roleNames; +}; + +} // namespace QmlDesigner + +QML_DECLARE_TYPE(QmlDesigner::SimpleColorPaletteModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettesingleton.cpp b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettesingleton.cpp new file mode 100644 index 0000000000..ccea50bbf2 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettesingleton.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 "simplecolorpalettesingleton.h" +#include "simplecolorpalette.h" + +#include "designersettings.h" + +#include <QDebug> +#include <QSettings> + +namespace QmlDesigner { + +SimpleColorPaletteSingleton::SimpleColorPaletteSingleton() + : m_items() + , m_favoriteOffset(0) +{ + if (!readPalette()) { + for (int i = 0; i < m_paletteSize; i++) + m_items.append(PaletteColor()); + } +} + +SimpleColorPaletteSingleton &SimpleColorPaletteSingleton::getInstance() +{ + static SimpleColorPaletteSingleton singleton; + + return singleton; +} + +void SimpleColorPaletteSingleton::addItem(const PaletteColor &item) +{ + if (m_favoriteOffset >= m_paletteSize) + return; + + if (item.isFavorite()) { + int contains = m_items.indexOf(item); + if (contains != -1) { + if (m_items.at(contains).isFavorite()) + return; + else + m_items.removeAt(contains); + } + m_items.insert(0, item); + m_favoriteOffset++; + } else if (m_items.contains(item)) + return; + else + m_items.insert(m_favoriteOffset, item); + + while (m_items.size() > m_paletteSize) { + m_items.removeLast(); + } + + writePalette(); + + emit paletteChanged(); +} + +QList<PaletteColor> SimpleColorPaletteSingleton::getItems() const +{ + return m_items; +} + +int SimpleColorPaletteSingleton::getPaletteSize() const +{ + return m_paletteSize; +} + +int SimpleColorPaletteSingleton::getFavoriteOffset() const +{ + return m_favoriteOffset; +} + +void SimpleColorPaletteSingleton::sortItems() +{ + auto itemSort = [](const PaletteColor &first, const PaletteColor &second) { + return (static_cast<int>(first.isFavorite()) < static_cast<int>(second.isFavorite())); + }; + + std::sort(m_items.begin(), m_items.end(), itemSort); + + emit paletteChanged(); +} + +void SimpleColorPaletteSingleton::toggleFavorite(int id) +{ + bool toggleResult = m_items[id].toggleFavorite(); + + if (toggleResult) { + m_favoriteOffset++; + m_items.move(id, 0); + } else { + m_favoriteOffset--; + m_items.move(id, m_favoriteOffset); + } + + if (m_favoriteOffset < 0) + m_favoriteOffset = 0; + else if (m_favoriteOffset > m_paletteSize) + m_favoriteOffset = m_paletteSize; + + emit paletteChanged(); +} + +bool SimpleColorPaletteSingleton::readPalette() +{ + QList<PaletteColor> proxy; + const QStringList stringData = QmlDesigner::DesignerSettings::getValue( + QmlDesigner::DesignerSettingsKey::SIMPLE_COLOR_PALETTE_CONTENT) + .toStringList(); + + int favCounter = 0; + + for (int i = 0; i < stringData.size(); i++) { + const QStringList strsep = stringData.at(i).split(";"); + if (strsep.size() != 2) { + continue; + } + PaletteColor colorItem(strsep.at(0)); + bool isFav = static_cast<bool>(strsep.at(1).toInt()); + colorItem.setFavorite(isFav); + if (isFav) + favCounter++; + proxy.append(colorItem); + } + + if (proxy.size() == 0) { + return false; + } + + while (proxy.size() > m_paletteSize) { + proxy.removeLast(); + } + while (proxy.size() < m_paletteSize) { + proxy.append(PaletteColor()); + } + + m_items.clear(); + m_items = proxy; + m_favoriteOffset = favCounter; + + return true; +} + +void SimpleColorPaletteSingleton::writePalette() +{ + QStringList output; + QString subres; + + for (int i = 0; i < m_items.size(); i++) { + subres = m_items.at(i).color().name(QColor::HexArgb); + subres += ";"; + subres += QString::number(static_cast<int>(m_items.at(i).isFavorite())); + output.push_back(subres); + subres.clear(); + } + + QmlDesigner::DesignerSettings::setValue( + QmlDesigner::DesignerSettingsKey::SIMPLE_COLOR_PALETTE_CONTENT, output); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettesingleton.h b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettesingleton.h new file mode 100644 index 0000000000..77ad2b0732 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/simplecolorpalettesingleton.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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. +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QAbstractListModel> +#include <QtQml/qqml.h> +#include <QList> +#include <QColor> +#include <simplecolorpalette.h> + +namespace QmlDesigner { + +class SimpleColorPaletteSingleton : public QObject +{ + Q_OBJECT +public: + static SimpleColorPaletteSingleton &getInstance(); + + bool readPalette(); + void writePalette(); + + void addItem(const PaletteColor &item); + QList<PaletteColor> getItems() const; + + int getPaletteSize() const; + int getFavoriteOffset() const; + + void sortItems(); + + void toggleFavorite(int id); + + SimpleColorPaletteSingleton(const SimpleColorPaletteSingleton &) = delete; + void operator=(const SimpleColorPaletteSingleton &) = delete; + +signals: + void paletteChanged(); + +private: + SimpleColorPaletteSingleton(); + +private: + QList<PaletteColor> m_items; + const int m_paletteSize = 6; + int m_favoriteOffset; +}; + +} // namespace QmlDesigner |