aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner
diff options
context:
space:
mode:
authorHenning Gruendl <henning.gruendl@qt.io>2020-10-06 12:29:09 +0200
committerHenning Gründl <henning.gruendl@qt.io>2020-10-12 15:24:55 +0000
commit2860e57112e147a5d639c773836f5e43a82524f7 (patch)
tree7a8f0a1993c983af685295c4a47b7fcb4b0fee0b /src/plugins/qmldesigner
parent15f39cf37c490a1cad6a67919e0a3734dcbdaf26 (diff)
QmlDesigner: Add lock functionality to navigator
* Update icon font and change related theme and constants files * Add locked column to Navigator * Add auxiliary property "locked" * Integrate locked feature into the following components: * Transition Editor * Connection Editor * Form Editor * Text Editor * Timeline * Navigator * State Editor Task-number: QDS-826 Change-Id: Ibf3ae96e0d5daeb1ab00279b94df5aaabe75e0bb Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Diffstat (limited to 'src/plugins/qmldesigner')
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp27
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.h4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp27
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h7
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp29
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionview.h1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp5
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.cpp1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp6
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocument.cpp36
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp37
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.h8
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.cpp89
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.h2
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp40
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp12
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h1
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp5
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h2
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp6
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp38
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h4
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp12
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineview.h3
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp14
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h1
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.cpp39
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.h4
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp14
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.h3
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractview.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelnode.h11
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractview.cpp20
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelnode.cpp47
36 files changed, 472 insertions, 92 deletions
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 96d08e5baef..ea34b091cd4 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -347,25 +347,27 @@ public:
&& !selectionContext().currentSingleSelectedNode().isRootNode()
&& selectionContext().currentSingleSelectedNode().hasParentProperty()) {
- ActionTemplate *selectionAction = new ActionTemplate(QString(), &ModelNodeOperations::select);
- selectionAction->setParent(menu());
-
parentNode = selectionContext().currentSingleSelectedNode().parentProperty().parentModelNode();
- selectionAction->setText(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1")).arg(
- captionForModelNode(parentNode)));
+ if (!ModelNode::isThisOrAncestorLocked(parentNode)) {
+ ActionTemplate *selectionAction = new ActionTemplate(QString(), &ModelNodeOperations::select);
+ selectionAction->setParent(menu());
+ selectionAction->setText(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1")).arg(
+ captionForModelNode(parentNode)));
- SelectionContext nodeSelectionContext = selectionContext();
- nodeSelectionContext.setTargetNode(parentNode);
- selectionAction->setSelectionContext(nodeSelectionContext);
+ SelectionContext nodeSelectionContext = selectionContext();
+ nodeSelectionContext.setTargetNode(parentNode);
+ selectionAction->setSelectionContext(nodeSelectionContext);
- menu()->addAction(selectionAction);
+ menu()->addAction(selectionAction);
+ }
}
- foreach (const ModelNode &node, selectionContext().view()->allModelNodes()) {
+ for (const ModelNode &node : selectionContext().view()->allModelNodes()) {
if (node != selectionContext().currentSingleSelectedNode()
&& node != parentNode
&& contains(node, selectionContext().scenePosition())
- && !node.isRootNode()) {
+ && !node.isRootNode()
+ && !ModelNode::isThisOrAncestorLocked(node)) {
selectionContext().setTargetNode(node);
QString what = QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select: %1")).arg(captionForModelNode(node));
ActionTemplate *selectionAction = new ActionTemplate(what, &ModelNodeOperations::select);
@@ -377,6 +379,9 @@ public:
menu()->addAction(selectionAction);
}
}
+
+ if (menu()->isEmpty())
+ action()->setEnabled(false);
}
}
};
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h
index f6a1df97cc1..513965b18f4 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.h
+++ b/src/plugins/qmldesigner/components/componentcore/theme.h
@@ -107,6 +107,8 @@ public:
idAliasOff,
idAliasOn,
listView,
+ lockOff,
+ lockOn,
mergeCells,
minus,
plus,
@@ -129,6 +131,8 @@ public:
undo,
upDownIcon,
upDownSquare2,
+ visibilityOff,
+ visibilityOn,
wildcard,
zoomAll,
zoomIn,
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
index 69e0e202f40..e325b020346 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
@@ -75,6 +75,23 @@ ConnectionModel::ConnectionModel(ConnectionView *parent)
connect(this, &QStandardItemModel::dataChanged, this, &ConnectionModel::handleDataChanged);
}
+Qt::ItemFlags ConnectionModel::flags(const QModelIndex &modelIndex) const
+{
+ if (!modelIndex.isValid())
+ return Qt::ItemIsEnabled;
+
+ if (!m_connectionView || !m_connectionView->model())
+ return Qt::ItemIsEnabled;
+
+ const int internalId = data(index(modelIndex.row(), TargetModelNodeRow), UserRoles::InternalIdRole).toInt();
+ ModelNode modelNode = m_connectionView->modelNodeForInternalId(internalId);
+
+ if (modelNode.isValid() && ModelNode::isThisOrAncestorLocked(modelNode))
+ return Qt::ItemIsEnabled;
+
+ return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
+}
+
void ConnectionModel::resetModel()
{
beginResetModel();
@@ -82,7 +99,7 @@ void ConnectionModel::resetModel()
setHorizontalHeaderLabels(QStringList({ tr("Target"), tr("Signal Handler"), tr("Action") }));
if (connectionView()->isAttached()) {
- for (const ModelNode modelNode : connectionView()->allModelNodes())
+ for (const ModelNode &modelNode : connectionView()->allModelNodes())
addModelNode(modelNode);
}
@@ -94,8 +111,8 @@ void ConnectionModel::resetModel()
SignalHandlerProperty ConnectionModel::signalHandlerPropertyForRow(int rowNumber) const
{
- const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
- const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString();
+ const int internalId = data(index(rowNumber, TargetModelNodeRow), UserRoles::InternalIdRole).toInt();
+ const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), UserRoles::TargetPropertyNameRole).toString();
ModelNode modelNode = connectionView()->modelNodeForInternalId(internalId);
if (modelNode.isValid())
@@ -256,8 +273,8 @@ void ConnectionModel::updateTargetNode(int rowNumber)
void ConnectionModel::updateCustomData(QStandardItem *item, const SignalHandlerProperty &signalHandlerProperty)
{
- item->setData(signalHandlerProperty.parentModelNode().internalId(), Qt::UserRole + 1);
- item->setData(signalHandlerProperty.name(), Qt::UserRole + 2);
+ item->setData(signalHandlerProperty.parentModelNode().internalId(), UserRoles::InternalIdRole);
+ item->setData(signalHandlerProperty.name(), UserRoles::TargetPropertyNameRole);
}
ModelNode ConnectionModel::getTargetNodeForConnection(const ModelNode &connection) const
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h
index b7d24db7190..5acf4f6402c 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h
@@ -48,7 +48,14 @@ public:
TargetPropertyNameRow = 1,
SourceRow = 2
};
+ enum UserRoles {
+ InternalIdRole = Qt::UserRole + 1,
+ TargetPropertyNameRole
+ };
ConnectionModel(ConnectionView *parent = nullptr);
+
+ Qt::ItemFlags flags(const QModelIndex &modelIndex) const override;
+
void resetModel();
SignalHandlerProperty signalHandlerPropertyForRow(int rowNumber) const;
ConnectionView *connectionView() const;
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
index 0410ccf9089..88dd6a971db 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
@@ -36,6 +36,8 @@
#include <variantproperty.h>
#include <signalhandlerproperty.h>
+#include <QTableView>
+
namespace QmlDesigner {
namespace Internal {
@@ -162,6 +164,33 @@ void ConnectionView::selectedNodesChanged(const QList<ModelNode> & selectedNodeL
emit connectionViewWidget()->setEnabledAddButton(selectedNodeList.count() == 1);
}
+void ConnectionView::auxiliaryDataChanged(const ModelNode &node,
+ const PropertyName &name,
+ const QVariant &data)
+{
+ Q_UNUSED(node)
+
+ // Check if the auxiliary data is actually the locked property or if it is unlocked
+ if (name != QmlDesigner::lockedProperty || !data.toBool())
+ return;
+
+ QItemSelectionModel *selectionModel = connectionTableView()->selectionModel();
+ if (!selectionModel->hasSelection())
+ return;
+
+ QModelIndex modelIndex = selectionModel->currentIndex();
+ if (!modelIndex.isValid() || !model())
+ return;
+
+ const int internalId = connectionModel()->data(connectionModel()->index(modelIndex.row(),
+ ConnectionModel::TargetModelNodeRow),
+ ConnectionModel::UserRoles::InternalIdRole).toInt();
+ ModelNode modelNode = modelNodeForInternalId(internalId);
+
+ if (modelNode.isValid() && ModelNode::isThisOrAncestorLocked(modelNode))
+ selectionModel->clearSelection();
+}
+
void ConnectionView::importsChanged(const QList<Import> & /*addedImports*/, const QList<Import> & /*removedImports*/)
{
backendModel()->resetModel();
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
index 905fa02a587..dda496263d7 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
@@ -69,6 +69,7 @@ public:
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
+ void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp
index 0ed7abaefe3..fc7e8b97c7b 100644
--- a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp
@@ -189,7 +189,7 @@ FormEditorItem *AbstractFormEditorTool::topMovableFormEditorItem(const QList<QGr
FormEditorItem* AbstractFormEditorTool::nearestFormEditorItem(const QPointF &point, const QList<QGraphicsItem*> &itemList)
{
FormEditorItem* nearestItem = nullptr;
- foreach (QGraphicsItem *item, itemList) {
+ for (QGraphicsItem *item : itemList) {
FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
if (formEditorItem && formEditorItem->flowHitTest(point))
@@ -201,6 +201,9 @@ FormEditorItem* AbstractFormEditorTool::nearestFormEditorItem(const QPointF &poi
if (formEditorItem->parentItem() && !formEditorItem->parentItem()->isContentVisible())
continue;
+ if (formEditorItem && ModelNode::isThisOrAncestorLocked(formEditorItem->qmlItemNode().modelNode()))
+ continue;
+
if (!nearestItem)
nearestItem = formEditorItem;
else if (formEditorItem->selectionWeigth(point, 1) < nearestItem->selectionWeigth(point, 0))
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
index 9a643edef8e..8bd2d827f5e 100644
--- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
@@ -250,7 +250,6 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSc
if (m_dragNode.isValid())
view()->setSelectedModelNode(m_dragNode);
-
m_dragNode = QmlItemNode();
view()->changeToSelectionTool();
diff --git a/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp
index 242b5649d27..fa399f8860a 100644
--- a/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp
@@ -90,10 +90,10 @@ void RubberBandSelectionManipulator::select(SelectionType selectionType)
if (!m_beginFormEditorItem)
return;
- QList<QGraphicsItem*> itemList = m_editorView->scene()->items(m_selectionRectangleElement.rect(), Qt::IntersectsItemBoundingRect);
+ QList<QGraphicsItem *> itemList = m_editorView->scene()->items(m_selectionRectangleElement.rect(), Qt::IntersectsItemBoundingRect);
QList<QmlItemNode> newNodeList;
- foreach (QGraphicsItem* item, itemList)
+ for (QGraphicsItem *item : itemList)
{
FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
@@ -137,7 +137,7 @@ void RubberBandSelectionManipulator::select(SelectionType selectionType)
}
-void RubberBandSelectionManipulator::setItems(const QList<FormEditorItem*> &itemList)
+void RubberBandSelectionManipulator::setItems(const QList<FormEditorItem *> &itemList)
{
m_itemList = itemList;
}
diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp
index 05929fbd0ef..ae5c2fbcc2f 100644
--- a/src/plugins/qmldesigner/components/integration/designdocument.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp
@@ -49,6 +49,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/editormanager.h>
+#include <utils/algorithm.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -57,6 +58,7 @@
#include <QDebug>
#include <QApplication>
+#include <QMessageBox>
#include <QPlainTextEdit>
#include <QRandomGenerator>
@@ -375,9 +377,41 @@ void DesignDocument::deleteSelected()
if (!currentModel())
return;
+ QStringList lockedNodes;
+ for (const ModelNode &modelNode : view()->selectedModelNodes()) {
+ for (const ModelNode &node : modelNode.allSubModelNodesAndThisNode()) {
+ if (node.isValid() && !node.isRootNode() && node.locked())
+ lockedNodes.push_back(node.id());
+ }
+ }
+
+ if (!lockedNodes.empty()) {
+ Utils::sort(lockedNodes);
+ QString detailedText = QString("<b>" + tr("Locked items:") + "</b><br>");
+
+ for (const auto &id : qAsConst(lockedNodes))
+ detailedText.append("- " + id + "<br>");
+
+ detailedText.chop(QString("<br>").size());
+
+ QMessageBox msgBox;
+ msgBox.setTextFormat(Qt::RichText);
+ msgBox.setIcon(QMessageBox::Question);
+ msgBox.setWindowTitle(tr("Delete/Cut Item"));
+ msgBox.setText(QString(tr("Deleting or cutting this item will modify locked items.") + "<br><br>%1")
+ .arg(detailedText));
+ msgBox.setInformativeText(tr("Do you want to continue by removing the item (Delete) or removing it and copying it to the clipboard (Cut)?"));
+ msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
+ msgBox.setDefaultButton(QMessageBox::Ok);
+
+ if (msgBox.exec() == QMessageBox::Cancel)
+ return;
+ }
+
rewriterView()->executeInTransaction("DesignDocument::deleteSelected", [this](){
QList<ModelNode> toDelete = view()->selectedModelNodes();
- foreach (ModelNode node, toDelete) {
+
+ for (ModelNode node : toDelete) {
if (node.isValid() && !node.isRootNode() && QmlObjectNode::isValidQmlObjectNode(node))
QmlObjectNode(node).destroy();
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index 5538a9cb8d2..78d38c082d7 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
@@ -200,10 +200,10 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
if (!modelNode.isValid())
return QVariant();
- if (role == ItemIsVisibleRole) //independent of column
+ if (role == ItemIsVisibleRole) // independent of column
return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked;
- if (index.column() == 0) {
+ if (index.column() == ColumnType::Name) {
if (role == Qt::DisplayRole) {
return modelNode.displayName();
} else if (role == Qt::DecorationRole) {
@@ -240,18 +240,24 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
} else if (role == ModelNodeRole) {
return QVariant::fromValue<ModelNode>(modelNode);
}
- } else if (index.column() == 1) { //export
+ } else if (index.column() == ColumnType::Alias) { // export
if (role == Qt::CheckStateRole)
- return currentQmlObjectNode.isAliasExported() ? Qt::Checked : Qt::Unchecked;
+ return currentQmlObjectNode.isAliasExported() ? Qt::Checked : Qt::Unchecked;
else if (role == Qt::ToolTipRole)
return tr("Toggles whether this item is exported as an "
"alias property of the root item.");
- } else if (index.column() == 2) { //visible
+ } else if (index.column() == ColumnType::Visibility) { // visible
if (role == Qt::CheckStateRole)
return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked;
else if (role == Qt::ToolTipRole)
return tr("Toggles the visibility of this item in the form editor.\n"
"This is independent of the visibility property in QML.");
+ } else if (index.column() == ColumnType::Lock) { // lock
+ if (role == Qt::CheckStateRole)
+ return modelNode.locked() ? Qt::Checked : Qt::Unchecked;
+ else if (role == Qt::ToolTipRole)
+ return tr("Toggles whether this item is locked.\n"
+ "Locked items can't be modified or selected.");
}
return QVariant();
@@ -259,7 +265,16 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
Qt::ItemFlags NavigatorTreeModel::flags(const QModelIndex &index) const
{
- if (index.column() == 0)
+ if (index.column() == ColumnType::Alias
+ || index.column() == ColumnType::Visibility
+ || index.column() == ColumnType::Lock)
+ return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren;
+
+ const ModelNode modelNode = modelNodeForIndex(index);
+ if (ModelNode::isThisOrAncestorLocked(modelNode))
+ return Qt::NoItemFlags;
+
+ if (index.column() == ColumnType::Name)
return Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable
@@ -378,7 +393,7 @@ int NavigatorTreeModel::columnCount(const QModelIndex &parent) const
if (parent.column() > 0)
return 0;
- return 3;
+ return ColumnType::Count;
}
ModelNode NavigatorTreeModel::modelNodeForIndex(const QModelIndex &index) const
@@ -792,11 +807,13 @@ Qt::DropActions NavigatorTreeModel::supportedDragActions() const
bool NavigatorTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
ModelNode modelNode = modelNodeForIndex(index);
- if (index.column() == 1 && role == Qt::CheckStateRole) {
+ if (index.column() == ColumnType::Alias && role == Qt::CheckStateRole) {
QTC_ASSERT(m_view, return false);
m_view->handleChangedExport(modelNode, value.toInt() != 0);
- } else if (index.column() == 2 && role == Qt::CheckStateRole) {
+ } else if (index.column() == ColumnType::Visibility && role == Qt::CheckStateRole) {
QmlVisualNode(modelNode).setVisibilityOverride(value.toInt() == 0);
+ } else if (index.column() == ColumnType::Lock && role == Qt::CheckStateRole) {
+ modelNode.setLocked(value.toInt() != 0);
}
return true;
@@ -806,7 +823,7 @@ void NavigatorTreeModel::notifyDataChanged(const ModelNode &modelNode)
{
const QModelIndex index = indexForModelNode(modelNode);
const QAbstractItemModel *model = index.model();
- const QModelIndex sibling = model ? model->sibling(index.row(), 2, index) : QModelIndex();
+ const QModelIndex sibling = model ? model->sibling(index.row(), ColumnType::Count - 1, index) : QModelIndex();
emit dataChanged(index, sibling);
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
index d474ee98b9c..bb2712148df 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
@@ -49,6 +49,14 @@ class NavigatorTreeModel : public QAbstractItemModel, public NavigatorModelInter
public:
+ enum ColumnType {
+ Name = 0,
+ Alias,
+ Visibility,
+ Lock,
+ Count
+ };
+
explicit NavigatorTreeModel(QObject *parent = nullptr);
~NavigatorTreeModel() override;
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
index 87952613b1c..e1702bdac46 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
@@ -41,6 +41,7 @@
#include <qmlitemnode.h>
#include <rewritingexception.h>
#include <nodeinstanceview.h>
+#include <theme.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
@@ -48,6 +49,7 @@
#include <utils/algorithm.h>
#include <utils/icon.h>
#include <utils/utilsicons.h>
+#include <utils/stylehelper.h>
#include <QHeaderView>
#include <QTimer>
@@ -138,13 +140,14 @@ void NavigatorView::modelAttached(Model *model)
QTreeView *treeView = treeWidget();
- treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
- treeView->header()->resizeSection(1,26);
+ treeView->header()->setSectionResizeMode(NavigatorTreeModel::ColumnType::Name, QHeaderView::Stretch);
+ treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Alias, 26);
+ treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Visibility, 26);
+ treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Lock, 26);
treeView->setIndentation(20);
m_currentModelInterface->setFilter(false);
-
QTimer::singleShot(0, this, [this, treeView]() {
m_currentModelInterface->setFilter(
DesignerSettings::getValue(DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS).toBool());
@@ -166,10 +169,6 @@ void NavigatorView::modelAttached(Model *model)
}
}
});
-
-#ifdef _LOCK_ITEMS_
- treeView->header()->resizeSection(2,20);
-#endif
}
void NavigatorView::modelAboutToBeDetached(Model *model)
@@ -304,7 +303,7 @@ void NavigatorView::nodeIdChanged(const ModelNode& modelNode, const QString & /*
m_currentModelInterface->notifyDataChanged(modelNode);
}
-void NavigatorView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& /*propertyList*/)
+void NavigatorView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &/*propertyList*/)
{
}
@@ -321,7 +320,7 @@ void NavigatorView::propertiesRemoved(const QList<AbstractProperty> &propertyLis
m_currentModelInterface->notifyModelNodesRemoved(modelNodes);
}
-void NavigatorView::rootNodeTypeChanged(const QString & /*type*/, int /*majorVersion*/, int /*minorVersion*/)
+void NavigatorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/)
{
m_currentModelInterface->notifyDataChanged(rootModelNode());
}
@@ -332,9 +331,12 @@ void NavigatorView::nodeTypeChanged(const ModelNode &modelNode, const TypeName &
}
void NavigatorView::auxiliaryDataChanged(const ModelNode &modelNode,
- const PropertyName & /*name*/,
- const QVariant & /*data*/)
+ const PropertyName &name,
+ const QVariant &data)
{
+ Q_UNUSED(name)
+ Q_UNUSED(data)
+
m_currentModelInterface->notifyDataChanged(modelNode);
}
@@ -344,8 +346,8 @@ void NavigatorView::instanceErrorChanged(const QVector<ModelNode> &errorNodeList
m_currentModelInterface->notifyDataChanged(modelNode);
}
-void NavigatorView::nodeOrderChanged(const NodeListProperty & listProperty,
- const ModelNode & /*node*/,
+void NavigatorView::nodeOrderChanged(const NodeListProperty &listProperty,
+ const ModelNode &/*node*/,
int /*oldIndex*/)
{
m_currentModelInterface->notifyModelNodesMoved(listProperty.directSubNodes());
@@ -613,33 +615,50 @@ void NavigatorView::setupWidget()
connect(m_widget.data(), &NavigatorWidget::reverseOrderToggled, this, &NavigatorView::reverseOrderToggled);
#ifndef QMLDESIGNER_TEST
+ const QString fontName = "qtds_propertyIconFont.ttf";
+
+ const QIcon visibilityOnIcon =
+ Utils::StyleHelper::getIconFromIconFont(fontName,
+ Theme::getIconUnicode(Theme::Icon::visibilityOn),
+ 28, 28, QColor(Qt::white));
+ const QIcon visibilityOffIcon =
+ Utils::StyleHelper::getIconFromIconFont(fontName,
+ Theme::getIconUnicode(Theme::Icon::visibilityOff),
+ 28, 28, QColor(Qt::white));
+
+ const QIcon aliasOnIcon =
+ Utils::StyleHelper::getIconFromIconFont(fontName,
+ Theme::getIconUnicode(Theme::Icon::idAliasOn),
+ 28, 28, QColor(Qt::red));
+ const QIcon aliasOffIcon =
+ Utils::StyleHelper::getIconFromIconFont(fontName,
+ Theme::getIconUnicode(Theme::Icon::idAliasOff),
+ 28, 28, QColor(Qt::white));
+
+ const QIcon lockOnIcon =
+ Utils::StyleHelper::getIconFromIconFont(fontName,
+ Theme::getIconUnicode(Theme::Icon::lockOn),
+ 28, 28, QColor(Qt::white));
+ const QIcon lockOffIcon =
+ Utils::StyleHelper::getIconFromIconFont(fontName,
+ Theme::getIconUnicode(Theme::Icon::lockOff),
+ 28, 28, QColor(Qt::white));
+
auto idDelegate = new NameItemDelegate(this);
- IconCheckboxItemDelegate *showDelegate =
- new IconCheckboxItemDelegate(this,
- Utils::Icons::EYE_OPEN_TOOLBAR.icon(),
- Utils::Icons::EYE_CLOSED_TOOLBAR.icon());
- IconCheckboxItemDelegate *exportDelegate =
- new IconCheckboxItemDelegate(this,
- Icons::EXPORT_CHECKED.icon(),
- Icons::EXPORT_UNCHECKED.icon());
+ IconCheckboxItemDelegate *visibilityDelegate =
+ new IconCheckboxItemDelegate(this, visibilityOnIcon, visibilityOffIcon);
-#ifdef _LOCK_ITEMS_
- IconCheckboxItemDelegate *lockDelegate =
- new IconCheckboxItemDelegate(this,
- Utils::Icons::LOCKED_TOOLBAR.icon(),
- Utils::Icons::UNLOCKED_TOOLBAR.icon());
-#endif
+ IconCheckboxItemDelegate *aliasDelegate =
+ new IconCheckboxItemDelegate(this, aliasOnIcon, aliasOffIcon);
+ IconCheckboxItemDelegate *lockDelegate =
+ new IconCheckboxItemDelegate(this, lockOnIcon, lockOffIcon);
- treeWidget()->setItemDelegateForColumn(0, idDelegate);
-#ifdef _LOCK_ITEMS_
- treeWidget()->setItemDelegateForColumn(1,lockDelegate);
- treeWidget()->setItemDelegateForColumn(2,showDelegate);
-#else
- treeWidget()->setItemDelegateForColumn(1, exportDelegate);
- treeWidget()->setItemDelegateForColumn(2, showDelegate);
-#endif
+ treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Name, idDelegate);
+ treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Alias, aliasDelegate);
+ treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Visibility, visibilityDelegate);
+ treeWidget()->setItemDelegateForColumn(NavigatorTreeModel::ColumnType::Lock, lockDelegate);
#endif //QMLDESIGNER_TEST
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h
index 67042634e90..6189b24559a 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h
@@ -82,7 +82,7 @@ public:
void propertiesRemoved(const QList<AbstractProperty>& propertyList) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList ,
- const QList<ModelNode> &lastSelectedNodeList) override;
+ const QList<ModelNode> &lastSelectedNodeList) override;
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
void instanceErrorChanged(const QVector<ModelNode> &errorNodeList) override;
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp
index 3813881f550..649b53b5ffa 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp
@@ -78,7 +78,7 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view)
#endif
}
-void NavigatorWidget::setTreeModel(QAbstractItemModel* model)
+void NavigatorWidget::setTreeModel(QAbstractItemModel *model)
{
m_treeView->setModel(model);
}
@@ -92,7 +92,6 @@ QList<QToolButton *> NavigatorWidget::createToolBarWidgets()
{
QList<QToolButton *> buttons;
-
auto button = new QToolButton();
button->setIcon(Icons::ARROW_LEFT.icon());
button->setToolTip(tr("Become last sibling of parent (CTRL + Left)."));
@@ -180,7 +179,6 @@ void NavigatorWidget::enableNavigator()
m_treeView->setEnabled(true);
}
-
NavigatorView *NavigatorWidget::navigatorView() const
{
return m_navigatorView.data();
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
index 3a152836633..a8792ef2041 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
@@ -30,6 +30,7 @@
#include <QDebug>
#include <QRegularExpression>
+#include <QMessageBox>
#include <cmath>
#include <memory>
@@ -42,6 +43,7 @@
#include <qmlitemnode.h>
#include <qmlstate.h>
#include <annotationeditor/annotationeditor.h>
+#include <utils/algorithm.h>
namespace QmlDesigner {
@@ -92,11 +94,46 @@ void StatesEditorView::removeState(int nodeId)
if (nodeId > 0 && hasModelNodeForInternalId(nodeId)) {
ModelNode stateNode(modelNodeForInternalId(nodeId));
Q_ASSERT(stateNode.metaInfo().isSubclassOf("QtQuick.State"));
+
+ QmlModelState modelState(stateNode);
+ if (modelState.isValid()) {
+ QStringList lockedTargets;
+ const auto propertyChanges = modelState.propertyChanges();
+ for (const QmlPropertyChanges &change : propertyChanges) {
+ const ModelNode target = change.target();
+ if (target.locked())
+ lockedTargets.push_back(target.id());
+ }
+
+ if (!lockedTargets.empty()) {
+ Utils::sort(lockedTargets);
+ QString detailedText = QString("<b>" + tr("Locked items:") + "</b><br>");
+
+ for (const auto &id : qAsConst(lockedTargets))
+ detailedText.append("- " + id + "<br>");
+
+ detailedText.chop(QString("<br>").size());
+
+ QMessageBox msgBox;
+ msgBox.setTextFormat(Qt::RichText);
+ msgBox.setIcon(QMessageBox::Question);
+ msgBox.setWindowTitle(tr("Remove State"));
+ msgBox.setText(QString(tr("Removing this state will modify locked items.") + "<br><br>%1")
+ .arg(detailedText));
+ msgBox.setInformativeText(tr("Do you want to continue by removing the state?"));
+ msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
+ msgBox.setDefaultButton(QMessageBox::Ok);
+
+ if (msgBox.exec() == QMessageBox::Cancel)
+ return;
+ }
+ }
+
NodeListProperty parentProperty = stateNode.parentProperty().toNodeListProperty();
if (parentProperty.count() <= 1) {
setCurrentState(baseState());
- } else if (parentProperty.isValid()){
+ } else if (parentProperty.isValid()) {
int index = parentProperty.indexOf(stateNode);
if (index == 0)
setCurrentState(parentProperty.at(1));
@@ -104,7 +141,6 @@ void StatesEditorView::removeState(int nodeId)
setCurrentState(parentProperty.at(index - 1));
}
-
stateNode.destroy();
}
} catch (const RewritingException &e) {
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp
index 3b87f22c517..0f87032519c 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp
@@ -428,6 +428,18 @@ void TimelineGraphicsScene::invalidateKeyframesForTarget(const ModelNode &target
TimelineSectionItem::updateFramesForTarget(child, target);
}
+void TimelineGraphicsScene::invalidateHeightForTarget(const ModelNode &target)
+{
+ if (!target.isValid())
+ return;
+
+ const auto children = m_layout->childItems();
+ for (auto child : children)
+ TimelineSectionItem::updateHeightForTarget(child, target);
+
+ invalidateLayout();
+}
+
void TimelineGraphicsScene::invalidateScene()
{
ModelNode node = timelineView()->modelNodeForId(
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h
index 7413cb1dbb2..8ef1c13092e 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h
@@ -158,6 +158,7 @@ public:
void invalidateSectionForTarget(const ModelNode &modelNode);
void invalidateKeyframesForTarget(const ModelNode &modelNode);
+ void invalidateHeightForTarget(const ModelNode &modelNode);
void invalidateScene();
void invalidateScrollbar() override;
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp
index 12345a404e4..1b0b2cb7e53 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.cpp
@@ -156,4 +156,9 @@ TimelineFrameHandle *TimelineMovableAbstractItem::asTimelineFrameHandle()
return nullptr;
}
+bool TimelineMovableAbstractItem::isLocked() const
+{
+ return false;
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h
index 199a78ad997..d79101b4d9d 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinemovableabstractitem.h
@@ -69,6 +69,8 @@ public:
virtual TimelineKeyframeItem *asTimelineKeyframeItem();
virtual TimelineFrameHandle *asTimelineFrameHandle();
+ virtual bool isLocked() const;
+
protected:
int scrollOffset() const;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp
index 5dc52bbc9b8..0508606c11f 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinemovetool.cpp
@@ -70,6 +70,9 @@ void TimelineMoveTool::mousePressEvent(TimelineMovableAbstractItem *item,
{
Q_UNUSED(item)
+ if (currentItem() && currentItem()->isLocked())
+ return;
+
if (auto *current = currentItem()->asTimelineKeyframeItem()) {
const qreal sourceFrame = qRound(current->mapFromSceneToFrame(current->rect().center().x()));
const qreal targetFrame = qRound(current->mapFromSceneToFrame(event->scenePos().x()));
@@ -85,6 +88,9 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
if (!currentItem())
return;
+ if (currentItem()->isLocked())
+ return;
+
if (auto *current = currentItem()->asTimelineKeyframeItem()) {
// prevent dragging if deselecting a keyframe (Ctrl+click and drag a selected keyframe)
if (!current->highlighted())
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp
index c77d466585f..4580240c5fb 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp
@@ -171,6 +171,17 @@ void TimelineSectionItem::updateFramesForTarget(QGraphicsItem *item, const Model
}
}
+void TimelineSectionItem::updateHeightForTarget(QGraphicsItem *item, const ModelNode &target)
+{
+ if (!target.isValid())
+ return;
+
+ if (auto sectionItem = qgraphicsitem_cast<TimelineSectionItem *>(item)) {
+ if (sectionItem->targetNode() == target)
+ sectionItem->updateHeight();
+ }
+}
+
void TimelineSectionItem::moveAllFrames(qreal offset)
{
if (m_timeline.isValid())
@@ -313,7 +324,8 @@ void TimelineSectionItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
if (event->button() == Qt::LeftButton) {
event->accept();
- toggleCollapsed();
+ if (!ModelNode::isThisOrAncestorLocked(m_targetNode))
+ toggleCollapsed();
}
}
@@ -345,7 +357,8 @@ void TimelineSectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (m_targetNode.isValid())
m_targetNode.view()->setSelectedModelNode(m_targetNode);
} else {
- toggleCollapsed();
+ if (!ModelNode::isThisOrAncestorLocked(m_targetNode))
+ toggleCollapsed();
}
update();
}
@@ -414,6 +427,12 @@ void TimelineSectionItem::updateFrames()
update();
}
+void TimelineSectionItem::updateHeight()
+{
+ invalidateHeight();
+ update();
+}
+
void TimelineSectionItem::invalidateHeight()
{
int height = 0;
@@ -464,7 +483,8 @@ void TimelineSectionItem::invalidateFrames()
bool TimelineSectionItem::collapsed() const
{
- return m_targetNode.isValid() && !m_targetNode.hasAuxiliaryData("timeline_expanded");
+ return m_targetNode.isValid()
+ && (!m_targetNode.hasAuxiliaryData("timeline_expanded") || m_targetNode.locked());
}
void TimelineSectionItem::createPropertyItems()
@@ -845,6 +865,11 @@ void TimelineBarItem::commitPosition(const QPointF & /*point*/)
m_oldRect = QRectF();
}
+bool TimelineBarItem::isLocked() const
+{
+ return sectionItem()->targetNode().isValid() && sectionItem()->targetNode().locked();
+}
+
void TimelineBarItem::scrollOffsetChanged()
{
sectionItem()->invalidateBar();
@@ -904,7 +929,9 @@ void TimelineBarItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
const auto p = event->pos();
QRectF left, right;
- if (handleRects(rect(), left, right)) {
+ if (isLocked() && rect().contains(p)) {
+ setCursor(QCursor(Qt::ForbiddenCursor));
+ } else if (handleRects(rect(), left, right)) {
if (left.contains(p) || right.contains(p)) {
if (cursor().shape() != Qt::SizeHorCursor)
setCursor(QCursor(Qt::SizeHorCursor));
@@ -920,6 +947,9 @@ void TimelineBarItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
void TimelineBarItem::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
{
+ if (isLocked())
+ return;
+
QMenu menu;
QAction* overrideColor = menu.addAction(tr("Override Color"));
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h
index e5403bcb74f..a31930b709b 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h
@@ -50,6 +50,8 @@ public:
void itemMoved(const QPointF &start, const QPointF &end) override;
void commitPosition(const QPointF &point) override;
+ bool isLocked() const override;
+
protected:
void scrollOffsetChanged() override;
void paint(QPainter *painter,
@@ -100,6 +102,7 @@ public:
static void updateData(QGraphicsItem *item);
static void updateDataForTarget(QGraphicsItem *item, const ModelNode &target, bool *b);
static void updateFramesForTarget(QGraphicsItem *item, const ModelNode &target);
+ static void updateHeightForTarget(QGraphicsItem *item, const ModelNode &target);
void moveAllFrames(qreal offset);
void scaleAllFrames(qreal scale);
@@ -121,6 +124,7 @@ protected:
private:
void updateData();
void updateFrames();
+ void updateHeight();
void invalidateHeight();
void invalidateProperties();
void invalidateFrames();
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
index d0679c80bb6..dab580a1469 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
@@ -236,6 +236,18 @@ void TimelineView::selectedNodesChanged(const QList<ModelNode> & /*selectedNodeL
m_timelineWidget->graphicsScene()->update();
}
+void TimelineView::auxiliaryDataChanged(const ModelNode &modelNode,
+ const PropertyName &name,
+ const QVariant &data)
+{
+ if (name == QmlDesigner::lockedProperty && data.toBool() && modelNode.isValid()) {
+ for (const auto &node : modelNode.allSubModelNodesAndThisNode()) {
+ if (node.hasAuxiliaryData("timeline_expanded"))
+ m_timelineWidget->graphicsScene()->invalidateHeightForTarget(node);
+ }
+ }
+}
+
void TimelineView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList)
{
for (const auto &property : propertyList) {
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineview.h b/src/plugins/qmldesigner/components/timelineeditor/timelineview.h
index fe3f5903ff3..f1f39b6a35f 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineview.h
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineview.h
@@ -62,6 +62,9 @@ public:
PropertyChangeFlags propertyChange) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
+ void auxiliaryDataChanged(const ModelNode &node,
+ const PropertyName &name,
+ const QVariant &data) override;
void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) override;
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp
index 036fe173f5c..3b14a9986cd 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp
@@ -218,7 +218,7 @@ void TransitionEditorGraphicsScene::invalidateSectionForTarget(const ModelNode &
const QList<QGraphicsItem *> items = m_layout->childItems();
for (auto child : items)
- TimelineSectionItem::updateDataForTarget(child, target, &found);
+ TransitionEditorSectionItem::updateDataForTarget(child, target, &found);
if (!found)
invalidateScene();
@@ -227,6 +227,18 @@ void TransitionEditorGraphicsScene::invalidateSectionForTarget(const ModelNode &
invalidateLayout();
}
+void TransitionEditorGraphicsScene::invalidateHeightForTarget(const ModelNode &target)
+{
+ if (!target.isValid())
+ return;
+
+ const auto children = m_layout->childItems();
+ for (auto child : children)
+ TransitionEditorSectionItem::updateHeightForTarget(child, target);
+
+ invalidateLayout();
+}
+
void TransitionEditorGraphicsScene::invalidateScene()
{
invalidateScrollbar();
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h
index 2f04c5b7298..d7174df55a6 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h
@@ -93,6 +93,7 @@ public:
void setRulerScaling(int scaling);
void invalidateSectionForTarget(const ModelNode &modelNode);
+ void invalidateHeightForTarget(const ModelNode &modelNode);
void invalidateScene();
void invalidateCurrentValues();
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.cpp
index 86442059d9c..7172465e0d5 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.cpp
@@ -196,6 +196,17 @@ void TransitionEditorSectionItem::updateData(QGraphicsItem *item)
sectionItem->updateData();
}
+void TransitionEditorSectionItem::updateHeightForTarget(QGraphicsItem *item, const ModelNode &target)
+{
+ if (!target.isValid())
+ return;
+
+ if (auto sectionItem = qgraphicsitem_cast<TransitionEditorSectionItem *>(item)) {
+ if (sectionItem->targetNode() == target)
+ sectionItem->updateHeight();
+ }
+}
+
void TransitionEditorSectionItem::invalidateBar(QGraphicsItem *item)
{
if (auto sectionItem = qgraphicsitem_cast<TransitionEditorSectionItem *>(item))
@@ -360,7 +371,8 @@ void TransitionEditorSectionItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent
if (event->button() == Qt::LeftButton) {
event->accept();
- toggleCollapsed();
+ if (!ModelNode::isThisOrAncestorLocked(m_targetNode))
+ toggleCollapsed();
}
}
@@ -392,7 +404,8 @@ void TransitionEditorSectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *ev
if (m_targetNode.isValid())
m_targetNode.view()->setSelectedModelNode(m_targetNode);
} else {
- toggleCollapsed();
+ if (!ModelNode::isThisOrAncestorLocked(m_targetNode))
+ toggleCollapsed();
}
update();
}
@@ -417,6 +430,12 @@ void TransitionEditorSectionItem::updateData()
update();
}
+void TransitionEditorSectionItem::updateHeight()
+{
+ invalidateHeight();
+ update();
+}
+
const QList<QGraphicsItem *> TransitionEditorSectionItem::propertyItems() const
{
QList<QGraphicsItem *> list;
@@ -488,7 +507,8 @@ void TransitionEditorSectionItem::invalidateProperties()
bool TransitionEditorSectionItem::collapsed() const
{
- return m_targetNode.isValid() && !m_targetNode.hasAuxiliaryData("timeline_expanded");
+ return m_targetNode.isValid()
+ && (!m_targetNode.hasAuxiliaryData("transition_expanded") || m_targetNode.locked());
}
qreal TransitionEditorSectionItem::rulerWidth() const
@@ -501,9 +521,9 @@ void TransitionEditorSectionItem::toggleCollapsed()
QTC_ASSERT(m_targetNode.isValid(), return );
if (collapsed())
- m_targetNode.setAuxiliaryData("timeline_expanded", true);
+ m_targetNode.setAuxiliaryData("transition_expanded", true);
else
- m_targetNode.removeAuxiliaryData("timeline_expanded");
+ m_targetNode.removeAuxiliaryData("transition_expanded");
invalidateHeight();
}
@@ -592,6 +612,11 @@ void TransitionEditorBarItem::commitPosition(const QPointF & /*point*/)
scrollOffsetChanged();
}
+bool TransitionEditorBarItem::isLocked() const
+{
+ return sectionItem() && sectionItem()->targetNode().isValid() && sectionItem()->targetNode().locked();
+}
+
void TransitionEditorBarItem::scrollOffsetChanged()
{
if (sectionItem())
@@ -637,7 +662,9 @@ void TransitionEditorBarItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
const auto p = event->pos();
QRectF left, right;
- if (handleRects(rect(), left, right)) {
+ if (isLocked() && rect().contains(p)) {
+ setCursor(QCursor(Qt::ForbiddenCursor));
+ } else if (handleRects(rect(), left, right)) {
if (left.contains(p) || right.contains(p)) {
if (cursor().shape() != Qt::SizeHorCursor)
setCursor(QCursor(Qt::SizeHorCursor));
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.h b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.h
index d7ce78f56c2..63828b52f54 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.h
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsectionitem.h
@@ -54,6 +54,8 @@ public:
void itemMoved(const QPointF &start, const QPointF &end) override;
void commitPosition(const QPointF &point) override;
+ bool isLocked() const override;
+
protected:
void scrollOffsetChanged() override;
void paint(QPainter *painter,
@@ -106,6 +108,7 @@ public:
static void updateData(QGraphicsItem *item);
static void invalidateBar(QGraphicsItem *item);
static void updateDataForTarget(QGraphicsItem *item, const ModelNode &target, bool *b);
+ static void updateHeightForTarget(QGraphicsItem *item, const ModelNode &target);
void moveAllDurations(qreal offset);
void scaleAllDurations(qreal scale);
@@ -125,6 +128,7 @@ protected:
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
private:
+ void updateHeight();
void invalidateHeight();
void invalidateProperties();
bool collapsed() const;
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
index ef83b17d90a..e9cfb3fd729 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
@@ -142,6 +142,18 @@ void TransitionEditorView::selectedNodesChanged(const QList<ModelNode> & /*selec
}
+void TransitionEditorView::auxiliaryDataChanged(const ModelNode &modelNode,
+ const PropertyName &name,
+ const QVariant &data)
+{
+ if (name == QmlDesigner::lockedProperty && data.toBool() && modelNode.isValid()) {
+ for (const auto &node : modelNode.allSubModelNodesAndThisNode()) {
+ if (node.hasAuxiliaryData("transition_expanded"))
+ m_transitionEditorWidget->graphicsScene()->invalidateHeightForTarget(node);
+ }
+ }
+}
+
void TransitionEditorView::propertiesAboutToBeRemoved(
const QList<AbstractProperty> & /*propertyList */)
{
@@ -217,7 +229,7 @@ ModelNode TransitionEditorView::addNewTransition()
QStringList newlist = idPropertyList.value(targetId);
for (const QString &str :locList)
if (!newlist.contains(str))
- newlist.append(str);
+ newlist.append(str);
idPropertyList.insert(targetId, newlist);
} else {
if (!locList.isEmpty())
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.h b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.h
index 1476a07353d..857467e3cd9 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.h
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.h
@@ -60,6 +60,9 @@ public:
PropertyChangeFlags propertyChange) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
+ void auxiliaryDataChanged(const ModelNode &node,
+ const PropertyName &name,
+ const QVariant &data) override;
void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) override;
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h
index 12cb4575717..6b0276c8b15 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractview.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractview.h
@@ -147,6 +147,7 @@ public:
void setSelectedModelNodes(const QList<ModelNode> &selectedNodeList);
void setSelectedModelNode(const ModelNode &modelNode);
+
void selectModelNode(const ModelNode &node);
void deselectModelNode(const ModelNode &node);
void clearSelectedModelNodes();
diff --git a/src/plugins/qmldesigner/designercore/include/modelnode.h b/src/plugins/qmldesigner/designercore/include/modelnode.h
index 3197e746ab5..19bed05a255 100644
--- a/src/plugins/qmldesigner/designercore/include/modelnode.h
+++ b/src/plugins/qmldesigner/designercore/include/modelnode.h
@@ -65,7 +65,9 @@ QMLDESIGNERCORE_EXPORT QList<Internal::InternalNodePointer> toInternalNodeList(c
using PropertyListType = QList<QPair<PropertyName, QVariant> >;
-class QMLDESIGNERCORE_EXPORT ModelNode
+static const PropertyName lockedProperty = {("locked")};
+
+class QMLDESIGNERCORE_EXPORT ModelNode
{
friend QMLDESIGNERCORE_EXPORT bool operator ==(const ModelNode &firstNode, const ModelNode &secondNode);
friend QMLDESIGNERCORE_EXPORT bool operator !=(const ModelNode &firstNode, const ModelNode &secondNode);
@@ -216,6 +218,11 @@ public:
void setGlobalStatus(const GlobalAnnotationStatus &status);
void removeGlobalStatus();
+ bool locked() const;
+ void setLocked(bool value);
+
+ static bool isThisOrAncestorLocked(const ModelNode &node);
+
qint32 internalId() const;
void setNodeSource(const QString&);
@@ -241,6 +248,8 @@ public:
private: // functions
Internal::InternalNodePointer internalNode() const;
+ void removeLocked();
+ bool hasLocked() const;
private: // variables
Internal::InternalNodePointer m_internalNode;
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index 492d6c62b6b..c4779543e84 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -534,11 +534,11 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
const PropertyName &name,
const QVariant &value)
{
- if (((node.isRootNode() && (name == "width" || name == "height")) || name == "invisible")
+ if (((node.isRootNode() && (name == "width" || name == "height")) || name == "invisible" || name == "locked")
|| name.endsWith(PropertyName("@NodeInstance"))) {
if (hasInstanceForModelNode(node)) {
NodeInstance instance = instanceForModelNode(node);
- if (value.isValid() || name == "invisible") {
+ if (value.isValid() || name == "invisible" || name == "locked") {
PropertyValueContainer container{instance.instanceId(), name, value, TypeName()};
m_nodeInstanceServer->changeAuxiliaryValues({{container}});
} else {
diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index d7d512334d9..6a1a8d4897b 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -35,6 +35,7 @@
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
#include <viewmanager.h>
+#include <nodeabstractproperty.h>
#endif
#include <coreplugin/helpmanager.h>
@@ -397,7 +398,7 @@ QList<ModelNode> AbstractView::toModelNodeList(const QList<Internal::InternalNod
QList<ModelNode> toModelNodeList(const QList<Internal::InternalNode::Pointer> &nodeList, AbstractView *view)
{
QList<ModelNode> newNodeList;
- foreach (const Internal::InternalNode::Pointer &node, nodeList)
+ for (const Internal::InternalNode::Pointer &node : nodeList)
newNodeList.append(ModelNode(node, view->model(), view));
return newNodeList;
@@ -406,7 +407,7 @@ QList<ModelNode> toModelNodeList(const QList<Internal::InternalNode::Pointer> &n
QList<Internal::InternalNode::Pointer> toInternalNodeList(const QList<ModelNode> &nodeList)
{
QList<Internal::InternalNode::Pointer> newNodeList;
- foreach (const ModelNode &node, nodeList)
+ for (const ModelNode &node : nodeList)
newNodeList.append(node.internalNode());
return newNodeList;
@@ -414,15 +415,26 @@ QList<Internal::InternalNode::Pointer> toInternalNodeList(const QList<ModelNode>
/*!
Sets the list of nodes to the actual selected nodes specified by
- \a selectedNodeList.
+ \a selectedNodeList if the node or its ancestors are not locked.
*/
void AbstractView::setSelectedModelNodes(const QList<ModelNode> &selectedNodeList)
{
- model()->d->setSelectedNodes(toInternalNodeList(selectedNodeList));
+ QList<ModelNode> unlockedNodes;
+
+ for (const auto &modelNode : selectedNodeList) {
+ if (!ModelNode::isThisOrAncestorLocked(modelNode))
+ unlockedNodes.push_back(modelNode);
+ }
+
+ model()->d->setSelectedNodes(toInternalNodeList(unlockedNodes));
}
void AbstractView::setSelectedModelNode(const ModelNode &modelNode)
{
+ if (ModelNode::isThisOrAncestorLocked(modelNode)) {
+ clearSelectedModelNodes();
+ return;
+ }
setSelectedModelNodes({modelNode});
}
diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
index 5c1ffce639a..688dae2d074 100644
--- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
@@ -1228,6 +1228,53 @@ void ModelNode::removeGlobalStatus()
}
}
+bool ModelNode::locked() const
+{
+ if (hasLocked())
+ return auxiliaryData(lockedProperty).toBool();
+
+ return false;
+}
+
+bool ModelNode::hasLocked() const
+{
+ return hasAuxiliaryData(lockedProperty);
+}
+
+void ModelNode::setLocked(bool value)
+{
+ setAuxiliaryData(lockedProperty, value);
+
+ if (value) {
+ // Remove newly locked node and all its descendants from potential selection
+ for (ModelNode node : allSubModelNodesAndThisNode()) {
+ node.deselectNode();
+ node.removeAuxiliaryData("timeline_expanded");
+ node.removeAuxiliaryData("transition_expanded");
+ }
+ }
+}
+
+void ModelNode::removeLocked()
+{
+ if (hasLocked())
+ removeAuxiliaryData(lockedProperty);
+}
+
+bool ModelNode::isThisOrAncestorLocked(const ModelNode &node)
+{
+ if (!node.isValid())
+ return false;
+
+ if (node.locked())
+ return true;
+
+ if (node.isRootNode() || !node.hasParentProperty())
+ return false;
+
+ return isThisOrAncestorLocked(node.parentProperty().parentModelNode());
+}
+
void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList)
{
model()->d->setScriptFunctions(internalNode(), scriptFunctionList);