forked from qt-creator/qt-creator
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>
This commit is contained in:
committed by
Henning Gründl
parent
15f39cf37c
commit
2860e57112
@@ -98,33 +98,37 @@ QtObject {
|
||||
readonly property string idAliasOff: "\u005B"
|
||||
readonly property string idAliasOn: "\u005C"
|
||||
readonly property string listView: "\u005D"
|
||||
readonly property string mergeCells: "\u005E"
|
||||
readonly property string minus: "\u005F"
|
||||
readonly property string plus: "\u0060"
|
||||
readonly property string redo: "\u0061"
|
||||
readonly property string splitColumns: "\u0062"
|
||||
readonly property string splitRows: "\u0063"
|
||||
readonly property string startNode: "\u0064"
|
||||
readonly property string testIcon: "\u0065"
|
||||
readonly property string textAlignBottom: "\u0066"
|
||||
readonly property string textAlignCenter: "\u0067"
|
||||
readonly property string textAlignLeft: "\u0068"
|
||||
readonly property string textAlignMiddle: "\u0069"
|
||||
readonly property string textAlignRight: "\u006A"
|
||||
readonly property string textAlignTop: "\u006B"
|
||||
readonly property string textBulletList: "\u006C"
|
||||
readonly property string textFullJustification: "\u006D"
|
||||
readonly property string textNumberedList: "\u006E"
|
||||
readonly property string tickIcon: "\u006F"
|
||||
readonly property string triState: "\u0070"
|
||||
readonly property string undo: "\u0071"
|
||||
readonly property string upDownIcon: "\u0072"
|
||||
readonly property string upDownSquare2: "\u0073"
|
||||
readonly property string wildcard: "\u0074"
|
||||
readonly property string zoomAll: "\u0075"
|
||||
readonly property string zoomIn: "\u0076"
|
||||
readonly property string zoomOut: "\u0077"
|
||||
readonly property string zoomSelection: "\u0078"
|
||||
readonly property string lockOff: "\u005E"
|
||||
readonly property string lockOn: "\u005F"
|
||||
readonly property string mergeCells: "\u0060"
|
||||
readonly property string minus: "\u0061"
|
||||
readonly property string plus: "\u0062"
|
||||
readonly property string redo: "\u0063"
|
||||
readonly property string splitColumns: "\u0064"
|
||||
readonly property string splitRows: "\u0065"
|
||||
readonly property string startNode: "\u0066"
|
||||
readonly property string testIcon: "\u0067"
|
||||
readonly property string textAlignBottom: "\u0068"
|
||||
readonly property string textAlignCenter: "\u0069"
|
||||
readonly property string textAlignLeft: "\u006A"
|
||||
readonly property string textAlignMiddle: "\u006B"
|
||||
readonly property string textAlignRight: "\u006C"
|
||||
readonly property string textAlignTop: "\u006D"
|
||||
readonly property string textBulletList: "\u006E"
|
||||
readonly property string textFullJustification: "\u006F"
|
||||
readonly property string textNumberedList: "\u0070"
|
||||
readonly property string tickIcon: "\u0071"
|
||||
readonly property string triState: "\u0072"
|
||||
readonly property string undo: "\u0073"
|
||||
readonly property string upDownIcon: "\u0074"
|
||||
readonly property string upDownSquare2: "\u0075"
|
||||
readonly property string visibilityOff: "\u0076"
|
||||
readonly property string visibilityOn: "\u0077"
|
||||
readonly property string wildcard: "\u0078"
|
||||
readonly property string zoomAll: "\u0079"
|
||||
readonly property string zoomIn: "\u007A"
|
||||
readonly property string zoomOut: "\u007B"
|
||||
readonly property string zoomSelection: "\u007C"
|
||||
|
||||
readonly property font iconFont: Qt.font({
|
||||
"family": controlIcons.name,
|
||||
|
Binary file not shown.
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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))
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
IconCheckboxItemDelegate *aliasDelegate =
|
||||
new IconCheckboxItemDelegate(this, aliasOnIcon, aliasOffIcon);
|
||||
|
||||
#ifdef _LOCK_ITEMS_
|
||||
IconCheckboxItemDelegate *lockDelegate =
|
||||
new IconCheckboxItemDelegate(this,
|
||||
Utils::Icons::LOCKED_TOOLBAR.icon(),
|
||||
Utils::Icons::UNLOCKED_TOOLBAR.icon());
|
||||
#endif
|
||||
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
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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) {
|
||||
|
@@ -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(
|
||||
|
@@ -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;
|
||||
|
@@ -156,4 +156,9 @@ TimelineFrameHandle *TimelineMovableAbstractItem::asTimelineFrameHandle()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool TimelineMovableAbstractItem::isLocked() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -69,6 +69,8 @@ public:
|
||||
virtual TimelineKeyframeItem *asTimelineKeyframeItem();
|
||||
virtual TimelineFrameHandle *asTimelineFrameHandle();
|
||||
|
||||
virtual bool isLocked() const;
|
||||
|
||||
protected:
|
||||
int scrollOffset() const;
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
|
@@ -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())
|
||||
|
@@ -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"));
|
||||
|
||||
|
@@ -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();
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -93,6 +93,7 @@ public:
|
||||
void setRulerScaling(int scaling);
|
||||
|
||||
void invalidateSectionForTarget(const ModelNode &modelNode);
|
||||
void invalidateHeightForTarget(const ModelNode &modelNode);
|
||||
|
||||
void invalidateScene();
|
||||
void invalidateCurrentValues();
|
||||
|
@@ -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));
|
||||
|
@@ -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;
|
||||
|
@@ -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())
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
|
@@ -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 {
|
||||
|
@@ -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});
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user