stateseditorview.cpp 11.8 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8
9
10
11
12
13
14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29
30

#include "stateseditorview.h"
31
#include "stateseditorwidget.h"
32
33
#include "stateseditormodel.h"
#include <customnotifications.h>
34
#include <rewritingexception.h>
35
36
37

#include <QPainter>
#include <QTimerEvent>
38
#include <QMessageBox>
39
#include <QDebug>
40
#include <math.h>
41

42
43
#include <nodemetainfo.h>

44
45
46
#include <variantproperty.h>
#include <nodelistproperty.h>

47
48
49
50
51
52
namespace QmlDesigner {

/**
  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.
  */
53
StatesEditorView::StatesEditorView(QObject *parent) :
54
        QmlModelView(parent),
55
        m_statesEditorModel(new StatesEditorModel(this)),
Marco Bubke's avatar
Marco Bubke committed
56
        m_statesEditorWidget(new StatesEditorWidget(this, m_statesEditorModel.data())),
57
        m_lastIndex(-1)
58
{
59
    Q_ASSERT(m_statesEditorModel);
60
    // base state
61
62
}

Marco Bubke's avatar
Marco Bubke committed
63
QWidget *StatesEditorView::widget()
64
{
65
    return m_statesEditorWidget.data();
66
67
}

68
69
70
71
72
WidgetInfo StatesEditorView::widgetInfo()
{
    return createWidgetInfo(m_statesEditorWidget.data(), "StatesEditor", WidgetInfo::TopPane, 0, tr("States Editor"));
}

73
void StatesEditorView::removeState(int nodeId)
74
{
75
    try {
76
77
        if (nodeId > 0 && hasModelNodeForInternalId(nodeId)) {
            ModelNode stateNode(modelNodeForInternalId(nodeId));
78
            Q_ASSERT(stateNode.metaInfo().isSubclassOf("QtQuick.State", -1, -1));
79
80
81
82
83
84
            NodeListProperty parentProperty = stateNode.parentProperty().toNodeListProperty();

            if (parentProperty.count() <= 1) {
                setCurrentState(baseState());
            } else if (parentProperty.isValid()){
                int index = parentProperty.indexOf(stateNode);
85
                if (index == 0)
86
                    setCurrentState(parentProperty.at(1));
87
                else
88
89
90
91
92
93
                    setCurrentState(parentProperty.at(index - 1));
            }


            stateNode.destroy();
        }
94
95
96
    }  catch (RewritingException &e) {
        QMessageBox::warning(0, "Error", e.description());
    }
97
98
}

99
void StatesEditorView::synchonizeCurrentStateFromWidget()
100
{
101
102
    if (!model())
        return;
103
104
105
106
107
108
109
110
111
112
113
    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());
    }
}
114

115
116
void StatesEditorView::createNewState()
{
117
    if (currentState().isBaseState())
118
        addState();
119
    else
120
121
        duplicateCurrentState();
}
122

123
124
125
126
127
void StatesEditorView::addState()
{
    // can happen when root node is e.g. a ListModel
    if (!rootQmlItemNode().isValid())
        return;
128

129
    QStringList modelStateNames = rootStateGroup().names();
130

131
132
133
    QString newStateName;
    int index = 1;
    while (true) {
134
        newStateName = QString("State%1").arg(index++);
135
136
137
        if (!modelStateNames.contains(newStateName))
            break;
    }
138

139
    try {
140
        if ((rootStateGroup().allStates().count() < 1) && //QtQuick import might be missing
141
142
143
            (!model()->hasImport(Import::createLibraryImport("QtQuick", "1.0"), true)
             && !model()->hasImport(Import::createLibraryImport("QtQuick", "1.1"), true)
             && !model()->hasImport(Import::createLibraryImport("QtQuick", "2.0"), true)))
144
            model()->changeImports(QList<Import>() << Import::createLibraryImport("QtQuick", "1.0"), QList<Import>());
145
146
        ModelNode newState = rootStateGroup().addState(newStateName);
        setCurrentState(newState);
147
148
149
    }  catch (RewritingException &e) {
        QMessageBox::warning(0, "Error", e.description());
    }
150
151
}

152
void StatesEditorView::resetModel()
153
{
154
155
156
157
    if (m_statesEditorModel)
        m_statesEditorModel->reset();

    if (m_statesEditorWidget) {
158
        if (currentState().isBaseState())
159
            m_statesEditorWidget->setCurrentStateInternalId(currentState().modelNode().internalId());
160
        else
161
            m_statesEditorWidget->setCurrentStateInternalId(0);
162
163
164
    }
}

165
void StatesEditorView::duplicateCurrentState()
166
{
167
    QmlModelState state = currentState();
168

169
    Q_ASSERT(!state.isBaseState());
170

171
172
173
174
175
176
177
178
179
    QString newName = state.name();

    // Strip out numbers at the end of the string
    QRegExp regEx(QString("[0-9]+$"));
    int numberIndex = newName.indexOf(regEx);
    if ((numberIndex != -1) && (numberIndex+regEx.matchedLength()==newName.length()))
        newName = newName.left(numberIndex);

    int i = 1;
180
    QStringList stateNames = rootStateGroup().names();
181
182
    while (stateNames.contains(newName + QString::number(i)))
        i++;
183
184
185

    QmlModelState newState = state.duplicate(newName + QString::number(i));
    setCurrentState(newState);
186
187
}

188
bool StatesEditorView::validStateName(const QString &name) const
189
{
190
191
192
193
194
195
196
197
198
    if (name == tr("base state"))
        return false;
    QList<QmlModelState> modelStates = rootStateGroup().allStates();
    foreach (const QmlModelState &state, modelStates) {
        if (state.name() == name)
            return false;
    }
    return true;
}
199

200
201
202
203
204
QString StatesEditorView::currentStateName() const
{
    return currentState().isValid() ? currentState().name() : QString();
}

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
void StatesEditorView::renameState(int nodeId, const QString &newName)
{
    if (hasModelNodeForInternalId(nodeId)) {
        QmlModelState state(modelNodeForInternalId(nodeId));
        try {
            if (state.isValid() && state.name() != newName) {
                // Jump to base state for the change
                QmlModelState oldState = currentState();
                setCurrentState(baseState());
                state.setName(newName);
                setCurrentState(oldState);
            }
        }  catch (RewritingException &e) {
            QMessageBox::warning(0, "Error", e.description());
        }
    }
}

void StatesEditorView::modelAttached(Model *model)
{
225
226
227
228
229
    if (model == QmlModelView::model())
        return;

    Q_ASSERT(model);
    QmlModelView::modelAttached(model);
230

231
232
233
    if (m_statesEditorWidget)
        m_statesEditorWidget->setNodeInstanceView(nodeInstanceView());

234
    resetModel();
235
236
237
238
239
}

void StatesEditorView::modelAboutToBeDetached(Model *model)
{
    QmlModelView::modelAboutToBeDetached(model);
240
    resetModel();
241
242
}

243
void StatesEditorView::propertiesRemoved(const QList<AbstractProperty>& propertyList)
244
245
{
    foreach (const AbstractProperty &property, propertyList) {
246
        if (property.name() == "states" && property.parentModelNode().isRootNode())
247
            resetModel();
248
249
250
251
    }
}


Marco Bubke's avatar
Marco Bubke committed
252
void StatesEditorView::variantPropertiesChanged(const QList<VariantProperty> &/*propertyList*/, PropertyChangeFlags /*propertyChange*/)
253
254
255
{
}

256

257
258
void StatesEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{
259
260
    if (removedNode.hasParentProperty()) {
        const NodeAbstractProperty propertyParent = removedNode.parentProperty();
261
        if (propertyParent.parentModelNode().isRootNode() && propertyParent.name() == "states")
262
263
            m_lastIndex = propertyParent.indexOf(removedNode);
    }
Thomas Hartmann's avatar
Thomas Hartmann committed
264
    if (currentState().isValid() && removedNode == currentState())
265
        setCurrentState(baseState());
266
267
}

Thomas Hartmann's avatar
Thomas Hartmann committed
268
void StatesEditorView::nodeRemoved(const ModelNode & /*removedNode*/, const NodeAbstractProperty &parentProperty, PropertyChangeFlags /*propertyChange*/)
269
270
271
272
273
274
{
    if (parentProperty.isValid() && parentProperty.parentModelNode().isRootNode() && parentProperty.name() == "states") {
        m_statesEditorModel->removeState(m_lastIndex);
        m_lastIndex = -1;
    }
}
275

276
void StatesEditorView::nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags /*propertyChange*/)
277
{
278
279
280
    if (oldPropertyParent.isValid() && oldPropertyParent.parentModelNode().isRootNode() && oldPropertyParent.name() == "states")
        m_lastIndex = oldPropertyParent.indexOf(node);
}
281

282

283
284
285
286
void StatesEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags /*propertyChange*/)
{
    if (oldPropertyParent.isValid() && oldPropertyParent.parentModelNode().isRootNode() && oldPropertyParent.name() == "states")
        m_statesEditorModel->removeState(m_lastIndex);
287

288
    m_lastIndex = -1;
289

290
291
292
    if (newPropertyParent.isValid() && newPropertyParent.parentModelNode().isRootNode() && newPropertyParent.name() == "states") {
        int index = newPropertyParent.indexOf(node);
        m_statesEditorModel->insertState(index);
293
294
295
    }
}

Thomas Hartmann's avatar
Thomas Hartmann committed
296
void StatesEditorView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode & /*movedNode*/, int /*oldIndex*/)
297
{
298
299
    if (listProperty.isValid() && listProperty.parentModelNode().isRootNode() && listProperty.name() == "states")
        resetModel();
300
301
}

Thomas Hartmann's avatar
Thomas Hartmann committed
302
void StatesEditorView::actualStateChanged(const ModelNode &node)
303
{
Thomas Hartmann's avatar
Thomas Hartmann committed
304
305
    QmlModelState newQmlModelState(node);

306
    if (newQmlModelState.isBaseState())
307
        m_statesEditorWidget->setCurrentStateInternalId(0);
308
    else
309
        m_statesEditorWidget->setCurrentStateInternalId(newQmlModelState.modelNode().internalId());
Thomas Hartmann's avatar
Thomas Hartmann committed
310
    QmlModelView::actualStateChanged(node);
311
312
}

313
void StatesEditorView::instancesPreviewImageChanged(const QVector<ModelNode> &nodeList)
314
{
315
316
    int minimumIndex = 10000;
    int maximumIndex = -1;
317
    foreach (const ModelNode &node, nodeList) {
318
319
320
321
322
323
324
325
        if (node.isRootNode()) {
            minimumIndex = qMin(minimumIndex, 0);
            maximumIndex = qMax(maximumIndex, 0);
        } else {
            int index = rootStateGroup().allStates().indexOf(QmlModelState(node)) + 1;
            if (index > 0) {
                minimumIndex = qMin(minimumIndex, index);
                maximumIndex = qMax(maximumIndex, index);
326
            }
327
328
        }
    }
329
330
331

    if (maximumIndex >= 0)
        m_statesEditorModel->updateState(minimumIndex, maximumIndex);
332
333
}

Marco Bubke's avatar
Marco Bubke committed
334
335
336
337
338
339
void StatesEditorView::scriptFunctionsChanged(const ModelNode &node, const QStringList &scriptFunctionList)
{

    QmlModelView::scriptFunctionsChanged(node, scriptFunctionList);
}

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
void StatesEditorView::nodeIdChanged(const ModelNode &/*node*/, const QString &/*newId*/, const QString &/*oldId*/)
{

}

void StatesEditorView::bindingPropertiesChanged(const QList<BindingProperty> &/*propertyList*/, PropertyChangeFlags /*propertyChange*/)
{

}

void StatesEditorView::selectedNodesChanged(const QList<ModelNode> &/*selectedNodeList*/, const QList<ModelNode> &/*lastSelectedNodeList*/)
{

}

355
} // namespace QmlDesigner