stateseditorview.cpp 12.1 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6
7
8
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11
12
13
14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
15
16
17
18
19
20
21
22
23
24
**
** GNU Lesser General Public License Usage
**
** 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.
**
con's avatar
con committed
25
26
27
28
29
30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
31
32
33
34
**
**************************************************************************/

#include "stateseditorview.h"
35
#include "stateseditorwidget.h"
36
37
#include "stateseditormodel.h"
#include <customnotifications.h>
38
#include <rewritingexception.h>
39
40
41

#include <QPainter>
#include <QTimerEvent>
42
#include <QMessageBox>
43
#include <QDebug>
44
#include <math.h>
45

46
47
#include <nodemetainfo.h>

48
49
50
#include <variantproperty.h>
#include <nodelistproperty.h>

51
52
53
54
55
56
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.
  */
57
StatesEditorView::StatesEditorView(QObject *parent) :
58
        QmlModelView(parent),
59
60
        m_statesEditorModel(new StatesEditorModel(this)),
        m_lastIndex(-1)
61
{
62
    Q_ASSERT(m_statesEditorModel);
63
    // base state
64
65
}

66
StatesEditorWidget *StatesEditorView::widget()
67
{
68
69
    if (m_statesEditorWidget.isNull())
        m_statesEditorWidget = new StatesEditorWidget(this, m_statesEditorModel.data());
70

71
    return m_statesEditorWidget.data();
72
73
}

74
void StatesEditorView::removeState(int nodeId)
75
{
76
    try {
77
78
        if (nodeId > 0 && hasModelNodeForInternalId(nodeId)) {
            ModelNode stateNode(modelNodeForInternalId(nodeId));
79
            Q_ASSERT(stateNode.metaInfo().isSubclassOf("QtQuick.State", -1, -1));
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
            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();
        }
96
97
98
    }  catch (RewritingException &e) {
        QMessageBox::warning(0, "Error", e.description());
    }
99
100
}

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

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

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

132
    QStringList modelStateNames = rootStateGroup().names();
133

134
135
136
137
138
139
140
    QString newStateName;
    int index = 1;
    while (true) {
        newStateName = tr("State%1", "Default name for newly created states").arg(index++);
        if (!modelStateNames.contains(newStateName))
            break;
    }
141

142
143
    try {
        if (rootStateGroup().allStates().count() < 1)
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
158
159
160
161
    if (m_statesEditorModel)
        m_statesEditorModel->reset();

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

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

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

172
173
174
175
176
177
178
179
180
    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;
181
    QStringList stateNames = rootStateGroup().names();
182
183
    while (stateNames.contains(newName + QString::number(i)))
        i++;
184
185
186

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

189
bool StatesEditorView::validStateName(const QString &name) const
190
{
191
192
193
194
195
196
197
198
199
    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;
}
200

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

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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)
{
226
227
228
229
230
    if (model == QmlModelView::model())
        return;

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

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

235
    resetModel();
236
237
238
239
240
}

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

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


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

257

258
259
void StatesEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{
260
261
262
263
264
265
    if (removedNode.hasParentProperty()) {
        const NodeAbstractProperty propertyParent = removedNode.parentProperty();
        if (propertyParent.parentModelNode().isRootNode() && propertyParent.name() == "states") {
            m_lastIndex = propertyParent.indexOf(removedNode);
        }
    }
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
}

302
303
void StatesEditorView::nodeInstancePropertyChanged(const ModelNode &node, const QString &propertyName)
{
304
    // sets currentState() used in sceneChanged
305
306
307
    QmlModelView::nodeInstancePropertyChanged(node, propertyName);
}

308
309
void StatesEditorView::stateChanged(const QmlModelState &newQmlModelState, const QmlModelState &oldQmlModelState)
{
310
311
312
313
    if (newQmlModelState.isBaseState()) {
        m_statesEditorWidget->setCurrentStateInternalId(0);
    } else {
        m_statesEditorWidget->setCurrentStateInternalId(newQmlModelState.modelNode().internalId());
314
    }
315
    QmlModelView::stateChanged(newQmlModelState, oldQmlModelState);
316
317
}

318
void StatesEditorView::transformChanged(const QmlObjectNode &qmlObjectNode, const QString &propertyName)
319
{
320
    QmlModelView::transformChanged(qmlObjectNode, propertyName);
321
322
323
324
325
326
327
}

void StatesEditorView::parentChanged(const QmlObjectNode &qmlObjectNode)
{
    QmlModelView::parentChanged(qmlObjectNode);
}

328
void StatesEditorView::otherPropertyChanged(const QmlObjectNode &qmlObjectNode, const QString &propertyName)
329
{
330
    QmlModelView::otherPropertyChanged(qmlObjectNode, propertyName);
331
332
}

333
void StatesEditorView::instancesPreviewImageChanged(const QVector<ModelNode> &nodeList)
334
{
335
336
337
338
339
340
341
342
343
344
345
    int minimumIndex = 10000;
    int maximumIndex = -1;
    foreach(const ModelNode &node, nodeList) {
        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);
346
            }
347
348
        }
    }
349
350
351

    if (maximumIndex >= 0)
        m_statesEditorModel->updateState(minimumIndex, maximumIndex);
352
353
}

Marco Bubke's avatar
Marco Bubke committed
354
355
356
357
358
359
void StatesEditorView::scriptFunctionsChanged(const ModelNode &node, const QStringList &scriptFunctionList)
{

    QmlModelView::scriptFunctionsChanged(node, scriptFunctionList);
}

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
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*/)
{

}

375
} // namespace QmlDesigner