Commit 562d0c5f authored by Marco Bubke's avatar Marco Bubke
Browse files

QmlDesigner: Refactor states editor

Reviewed-By: Thomas Hartmann
parent fabf76d2
......@@ -151,7 +151,7 @@ void ComponentView::nodeRemoved(const ModelNode & /*removedNode*/, const NodeAbs
// }
// }
//}
void ComponentView::nodeAboutToBeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) {}
void ComponentView::nodeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) {}
void ComponentView::nodeIdChanged(const ModelNode& /*node*/, const QString& /*newId*/, const QString& /*oldId*/) {}
void ComponentView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& /*propertyList*/) {}
......
......@@ -59,6 +59,7 @@ public:
void nodeCreated(const ModelNode &createdNode);
void nodeAboutToBeRemoved(const ModelNode &removedNode);
void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty, PropertyChangeFlags propertyChange);
void nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId);
void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList);
......
......@@ -37,7 +37,7 @@
#include <allpropertiesbox.h>
#include <itemlibrary.h>
#include <navigatorview.h>
#include <stateseditorwidget.h>
#include <stateseditorview.h>
#include <formeditorview.h>
#include <formeditorwidget.h>
#include <basetexteditmodifier.h>
......@@ -87,7 +87,7 @@ public:
QWeakPointer<ItemLibrary> itemLibrary;
QWeakPointer<NavigatorView> navigator;
QWeakPointer<AllPropertiesBox> allPropertiesBox;
QWeakPointer<StatesEditorWidget> statesEditorWidget;
QWeakPointer<StatesEditorView> statesEditorView;
QWeakPointer<QStackedWidget> stackedWidget;
QWeakPointer<NodeInstanceView> nodeInstanceView;
......@@ -205,9 +205,9 @@ void DesignDocumentController::setAllPropertiesBox(AllPropertiesBox* allProperti
m_d->allPropertiesBox = allPropertiesBox;
}
void DesignDocumentController::setStatesEditorWidget(StatesEditorWidget* statesEditorWidget)
void DesignDocumentController::setStatesEditorView(StatesEditorView* statesEditorView)
{
m_d->statesEditorWidget = statesEditorWidget;
m_d->statesEditorView = statesEditorView;
}
void DesignDocumentController::setFormEditorView(FormEditorView *formEditorView)
......@@ -375,7 +375,7 @@ void DesignDocumentController::loadCurrentModel()
m_d->stackedWidget->addWidget(m_d->textEdit.data());
// Will call setCurrentState (formEditorView etc has to be constructed first)
m_d->statesEditorWidget->setup(m_d->model.data());
m_d->model->attachView(m_d->statesEditorView.data());
m_d->allPropertiesBox->setModel(m_d->model.data());
......
......@@ -54,7 +54,7 @@ class RewriterView;
class ItemLibrary;
class NavigatorView;
class AllPropertiesBox;
class StatesEditorWidget;
class StatesEditorView;
class FormEditorView;
class DesignDocumentController: public QObject
......@@ -92,7 +92,7 @@ public:
void setItemLibrary(ItemLibrary* itemLibrary);
void setNavigator(NavigatorView* navigatorView);
void setAllPropertiesBox(AllPropertiesBox* allPropertiesBox);
void setStatesEditorWidget(StatesEditorWidget* statesEditorWidget);
void setStatesEditorView(StatesEditorView* statesEditorView);
void setFormEditorView(FormEditorView *formEditorView);
void setNodeInstanceView(NodeInstanceView *nodeInstanceView);
......
......@@ -43,6 +43,7 @@ namespace QmlDesigner {
void DesignDocumentControllerView::nodeCreated(const ModelNode & /*createdNode*/) {};
void DesignDocumentControllerView::nodeAboutToBeRemoved(const ModelNode & /*removedNode*/) {};
void DesignDocumentControllerView::nodeRemoved(const ModelNode & /*removedNode*/, const NodeAbstractProperty & /*parentProperty*/, AbstractView::PropertyChangeFlags /*propertyChange*/) {};
void DesignDocumentControllerView::nodeAboutToBeReparented(const ModelNode & /*node*/, const NodeAbstractProperty & /*newPropertyParent*/, const NodeAbstractProperty & /*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) {};
void DesignDocumentControllerView::nodeReparented(const ModelNode & /*node*/, const NodeAbstractProperty & /*newPropertyParent*/, const NodeAbstractProperty & /*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) {};
void DesignDocumentControllerView::nodeIdChanged(const ModelNode& /*node*/, const QString& /*newId*/, const QString& /*oldId*/) {};
void DesignDocumentControllerView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& /*propertyList*/) {};
......
......@@ -45,6 +45,7 @@ public:
virtual void nodeCreated(const ModelNode &createdNode);
virtual void nodeAboutToBeRemoved(const ModelNode &removedNode);
virtual void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty, PropertyChangeFlags propertyChange);
virtual void nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
virtual void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
virtual void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId);
virtual void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList);
......
......@@ -130,6 +130,10 @@ void NavigatorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
m_treeModel->removeSubTree(removedNode);
}
void NavigatorView::nodeAboutToBeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
{
}
void NavigatorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty & /*newPropertyParent*/, const NodeAbstractProperty & /*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
{
bool blocked = blockSelectionChangedSignal(true);
......
......@@ -69,9 +69,9 @@ public:
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags propertyChange);
void nodeAboutToBeRemoved(const ModelNode &removedNode);
void nodeReparented(const ModelNode &node, const ModelNode &oldParent, const ModelNode &newParent);
void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex);
void nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion);
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId);
......
......@@ -33,107 +33,143 @@
#include <QtCore/QDebug>
#include <QMessageBox>
#include <nodelistproperty.h>
#include <modelnode.h>
#include <variantproperty.h>
enum {
debug = false
};
namespace QmlDesigner {
namespace Internal {
StatesEditorModel::StatesEditorModel(QObject *parent) :
QAbstractListModel(parent),
m_updateCounter(0)
StatesEditorModel::StatesEditorModel(StatesEditorView *view)
: QAbstractListModel(view),
m_statesEditorView(view),
m_updateCounter(0)
{
QHash<int, QByteArray> roleNames;
roleNames.insert(StateNameRole, "stateName");
roleNames.insert(StateImageSourceRole, "stateImageSource");
roleNames.insert(NodeId, "nodeId");
setRoleNames(roleNames);
}
int StatesEditorModel::count() const
{
return m_stateNames.count();
return rowCount();
}
QModelIndex StatesEditorModel::index(int row, int column, const QModelIndex &parent) const
{
if (m_statesEditorView.isNull())
return QModelIndex();
int internalId = 0;
if (row > 0)
internalId = m_statesEditorView->rootModelNode().nodeListProperty("states").at(row - 1).internalId();
return hasIndex(row, column, parent) ? createIndex(row, column, internalId) : QModelIndex();
}
int StatesEditorModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
if (parent.isValid() || m_statesEditorView.isNull() || !m_statesEditorView->model())
return 0;
return m_stateNames.count();
if (!m_statesEditorView->rootModelNode().hasNodeListProperty("states"))
return 1;
return m_statesEditorView->rootModelNode().nodeListProperty("states").count() + 1;
}
void StatesEditorModel::reset()
{
QAbstractListModel::reset();
}
QVariant StatesEditorModel::data(const QModelIndex &index, int role) const
{
if (index.parent().isValid() || index.column() != 0)
if (index.parent().isValid() || index.column() != 0 || m_statesEditorView.isNull() || !m_statesEditorView->hasModelNodeForInternalId(index.internalId()))
return QVariant();
QVariant result;
ModelNode stateNode;
if (index.internalId() > 0)
stateNode = m_statesEditorView->modelNodeForInternalId(index.internalId());
switch (role) {
case StateNameRole: {
if (index.row()==0)
result = QString(tr("base state", "Implicit default state"));
else
result = m_stateNames.at(index.row());
break;
}
case StateImageSourceRole: {
if (!m_statesView.isNull())
return QString("image://qmldesigner_stateseditor/%1-%2").arg(index.row()).arg(m_updateCounter);
break;
if (index.row() == 0) {
return QString(tr("base state", "Implicit default state"));
} else {
if (stateNode.hasVariantProperty("name")) {
return stateNode.variantProperty("name").value();
} else {
return QVariant();
}
}
}
case StateImageSourceRole: return QString("image://qmldesigner_stateseditor/%1").arg(index.internalId());
case NodeId : return index.internalId();
}
return result;
return QVariant();
}
void StatesEditorModel::insertState(int i, const QString &name)
void StatesEditorModel::insertState(int stateIndex)
{
beginInsertRows(QModelIndex(), i, i);
if (stateIndex >= 0) {
m_stateNames.insert(i, name);
const int index = stateIndex + 1;
beginInsertRows(QModelIndex(), index, index);
endInsertRows();
endInsertRows();
emit dataChanged(createIndex(i, 0), createIndex(i, 0));
emit countChanged();
emit dataChanged(createIndex(index, 0), createIndex(index, 0));
emit countChanged();
}
}
void StatesEditorModel::removeState(int i)
void StatesEditorModel::updateState(int stateIndex)
{
beginRemoveRows(QModelIndex(), i, i);
if (stateIndex >= 0) {
const int index = stateIndex + 1;
m_stateNames.removeAt(i);
endRemoveRows();
emit dataChanged(createIndex(i, 0), createIndex(i, 0));
emit countChanged();
emit dataChanged(createIndex(index, 0), createIndex(index, 0));
}
}
void StatesEditorModel::renameState(int i, const QString &newName)
void StatesEditorModel::removeState(int stateIndex)
{
Q_ASSERT(i > 0 && i < m_stateNames.count());
if (m_stateNames[i] != newName) {
if (m_stateNames.contains(newName) || newName.isEmpty()) {
QMessageBox::warning(0, tr("Invalid state name"),
newName.isEmpty() ?
tr("The empty string as a name is reserved for the base state.") :
tr("Name already used in another state"));
} else {
m_stateNames.replace(i, newName);
m_statesView->renameState(i,newName);
emit dataChanged(createIndex(i, 0), createIndex(i, 0));
}
if (stateIndex >= 0) {
const int index = stateIndex + 1;
beginRemoveRows(QModelIndex(), index, index);
endRemoveRows();
emit dataChanged(createIndex(index, 0), createIndex(index, 0));
emit countChanged();
}
}
void StatesEditorModel::setStatesEditorView(StatesEditorView *statesView)
{
m_statesView = statesView;
void StatesEditorModel::renameState(int nodeId, const QString &newName)
{
if (newName.isEmpty() ||! m_statesEditorView->validStateName(newName)) {
QMessageBox::warning(0, tr("Invalid state name"),
newName.isEmpty() ?
tr("The empty string as a name is reserved for the base state.") :
tr("Name already used in another state"));
} else {
m_statesEditorView->renameState(nodeId, newName);
}
}
void StatesEditorModel::emitChangedToState(int n)
......@@ -141,5 +177,4 @@ void StatesEditorModel::emitChangedToState(int n)
emit changedToState(n);
}
} // namespace Internal
} // namespace QmlDesigner
......@@ -33,11 +33,10 @@
#include <QAbstractListModel>
#include <QWeakPointer>
#include <stateseditorview.h>
namespace QmlDesigner {
namespace Internal {
class StatesEditorView;
class StatesEditorModel : public QAbstractListModel
{
......@@ -48,32 +47,34 @@ class StatesEditorModel : public QAbstractListModel
enum {
StateNameRole = Qt::DisplayRole,
StateImageSourceRole = Qt::UserRole,
NodeId
};
public:
StatesEditorModel(QObject *parent);
StatesEditorModel(StatesEditorView *view);
int count() const;
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
void insertState(int i, const QString &name);
void removeState(int i);
Q_INVOKABLE void renameState(int i, const QString &newName);
void setStatesEditorView(StatesEditorView *statesView);
void insertState(int stateIndex);
void removeState(int stateIndex);
void updateState(int stateIndex);
Q_INVOKABLE void renameState(int nodeId, const QString &newName);
void emitChangedToState(int n);
void reset();
signals:
void countChanged();
void changedToState(int n);
private:
QList<QString> m_stateNames;
QWeakPointer<StatesEditorView> m_statesView;
QWeakPointer<StatesEditorView> m_statesEditorView;
int m_updateCounter;
};
} // namespace Itnernal
} // namespace QmlDesigner
#endif // STATESEDITORMODEL_H
......@@ -28,6 +28,7 @@
**************************************************************************/
#include "stateseditorview.h"
#include "stateseditorwidget.h"
#include "stateseditormodel.h"
#include <customnotifications.h>
#include <rewritingexception.h>
......@@ -38,6 +39,8 @@
#include <QDebug>
#include <math.h>
#include <nodemetainfo.h>
#include <variantproperty.h>
#include <nodelistproperty.h>
......@@ -46,108 +49,124 @@ enum {
};
namespace QmlDesigner {
namespace Internal {
/**
We always have 'one' current state, where we get updates from (see sceneChanged()). In case
the current state is the base state, we render the base state + all other states.
*/
StatesEditorView::StatesEditorView(StatesEditorModel *editorModel, QObject *parent) :
StatesEditorView::StatesEditorView(QObject *parent) :
QmlModelView(parent),
m_editorModel(editorModel)
m_statesEditorModel(new StatesEditorModel(this)),
m_lastIndex(-1)
{
Q_ASSERT(m_editorModel);
Q_ASSERT(m_statesEditorModel);
// base state
}
void StatesEditorView::setCurrentState(int index)
StatesEditorWidget *StatesEditorView::widget()
{
if (debug)
qDebug() << __FUNCTION__ << index;
if (m_statesEditorWidget.isNull())
m_statesEditorWidget = new StatesEditorWidget(this, m_statesEditorModel.data());
// happens to be the case for an invalid document / no base state
if (m_modelStates.isEmpty())
return;
Q_ASSERT(index < m_modelStates.count());
if (index == -1)
return;
if (m_modelStates.indexOf(currentState()) == index)
return;
QmlModelState state(m_modelStates.at(index));
Q_ASSERT(state.isValid());
QmlModelView::setCurrentState(state);
return m_statesEditorWidget.data();
}
void StatesEditorView::createState(const QString &name)
void StatesEditorView::removeState(int nodeId)
{
if (debug)
qDebug() << __FUNCTION__ << name;
try {
model()->addImport(Import::createLibraryImport("QtQuick", "1.0"));
stateRootNode().states().addState(name);
if (nodeId > 0 && hasModelNodeForInternalId(nodeId)) {
ModelNode stateNode(modelNodeForInternalId(nodeId));
Q_ASSERT(stateNode.metaInfo().isSubclassOf("QtQuick/State", 4, 7));
NodeListProperty parentProperty = stateNode.parentProperty().toNodeListProperty();
if (parentProperty.count() <= 1) {
setCurrentState(baseState());
} else if (parentProperty.isValid()){
int index = parentProperty.indexOf(stateNode);
if (index == 0) {
setCurrentState(parentProperty.at(1));
} else {
setCurrentState(parentProperty.at(index - 1));
}
}
stateNode.destroy();
}
} catch (RewritingException &e) {
QMessageBox::warning(0, "Error", e.description());
}
}
void StatesEditorView::removeState(int index)
void StatesEditorView::synchonizeCurrentStateFromWidget()
{
if (debug)
qDebug() << __FUNCTION__ << index;
int internalId = m_statesEditorWidget->currentStateInternalId();
if (internalId > 0 && hasModelNodeForInternalId(internalId)) {
ModelNode node = modelNodeForInternalId(internalId);
QmlModelState modelState(node);
if (modelState.isValid() && modelState != currentState())
setCurrentState(modelState);
} else {
setCurrentState(baseState());
}
}
Q_ASSERT(index > 0 && index < m_modelStates.size());
QmlModelState state = m_modelStates.at(index);
Q_ASSERT(state.isValid());
void StatesEditorView::createNewState()
{
if (currentState().isBaseState()) {
addState();
} else {
duplicateCurrentState();
}
}
setCurrentState(0);
void StatesEditorView::addState()
{
// can happen when root node is e.g. a ListModel
if (!rootQmlItemNode().isValid())
return;
try {
m_modelStates.removeAll(state);
state.destroy();
QStringList modelStateNames = rootStateGroup().names();
m_editorModel->removeState(index);
QString newStateName;
int index = 1;
while (true) {
newStateName = tr("State%1", "Default name for newly created states").arg(index++);
if (!modelStateNames.contains(newStateName))
break;
}
int newIndex = (index < m_modelStates.count()) ? index : m_modelStates.count() - 1;
setCurrentState(newIndex);
try {
if (rootStateGroup().allStates().count() < 1)
model()->addImport(Import::createLibraryImport("QtQuick", "1.0"));
ModelNode newState = rootStateGroup().addState(newStateName);
setCurrentState(newState);
} catch (RewritingException &e) {
QMessageBox::warning(0, "Error", e.description());
}
}
void StatesEditorView::renameState(int index, const QString &newName)
void StatesEditorView::resetModel()
{
if (debug)
qDebug() << __FUNCTION__ << index << newName;
Q_ASSERT(index > 0 && index < m_modelStates.size());
QmlModelState state = m_modelStates.at(index);
Q_ASSERT(state.isValid());
try {
if (state.name() != newName) {
// Jump to base state for the change
QmlModelState oldState = currentState();
state.setName(newName);
setCurrentState(m_modelStates.indexOf(oldState));
if (m_statesEditorModel)
m_statesEditorModel->reset();
if (m_statesEditorWidget) {
if (currentState().isBaseState()) {
m_statesEditorWidget->setCurrentStateInternalId(currentState().modelNode().internalId());
} else {
m_statesEditorWidget->setCurrentStateInternalId(0);
}
} catch (RewritingException &e) {
QMessageBox::warning(0, "Error", e.description());
}
}
void StatesEditorView::duplicateCurrentState(int index