stateseditorview.cpp 16.7 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "stateseditorview.h"
#include "stateseditormodel.h"
#include <customnotifications.h>

#include <QPainter>
#include <QTimerEvent>
#include <QDebug>
37
#include <math.h>
38
39

enum {
40
    debug = false
41
42
43
44
45
46
47
48
49
50
51
};

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) :
        QmlModelView(parent),
52
        m_editorModel(editorModel),
53
        m_attachedToModel(false), m_settingSilentState(false)
54
55
56
57
58
59
{
    Q_ASSERT(m_editorModel);
}

void StatesEditorView::setCurrentStateSilent(int index)
{
60
    m_settingSilentState = true;
61
62
63
    if (debug)
        qDebug() << __FUNCTION__ << index;

64
    Q_ASSERT(index >= 0 && index < m_modelStates.count());
65

66
67
    // TODO
    QmlModelState state(m_modelStates.at(index));
68
69
    if (!state.isValid()) {
        m_settingSilentState = false;
70
        return;
71
72
73
    }
    if (state == currentState()) {
        m_settingSilentState = false;
74
        return;
75
    }
76
    QmlModelView::activateState(state);
77
78

    m_settingSilentState = false;
79
80
81
82
}

void StatesEditorView::setCurrentState(int index)
{
83
84
    if (debug)
        qDebug() << __FUNCTION__ << index;
85

86
87
88
89
    // happens to be the case for an invalid document / no base state
    if (m_modelStates.isEmpty())
        return;

90
91
92
    Q_ASSERT(index < m_modelStates.count());
    if (index == -1)
        return;
93
94

    if (m_modelStates.indexOf(currentState()) == index)
95
96
97
98
99
100
101
102
103
        return;

    QmlModelState state(m_modelStates.at(index));
    Q_ASSERT(state.isValid());
    QmlModelView::setCurrentState(state);
}

void StatesEditorView::createState(const QString &name)
{
104
105
106
    if (debug)
        qDebug() << __FUNCTION__ << name;

107
108
109
110
111
    stateRootNode().states().addState(name);
}

void StatesEditorView::removeState(int index)
{
112
113
114
    if (debug)
        qDebug() << __FUNCTION__ << index;

115
116
117
    Q_ASSERT(index > 0 && index < m_modelStates.size());
    QmlModelState state = m_modelStates.at(index);
    Q_ASSERT(state.isValid());
118
119
120

    setCurrentState(0);

121
122
    m_modelStates.removeAll(state);
    state.destroy();
123
124
125
126
    m_editorModel->removeState(index);

    int newIndex = (index < m_modelStates.count()) ? index : m_modelStates.count() - 1;
    setCurrentState(newIndex);
127
128
}

129
void StatesEditorView::renameState(int index, const QString &newName)
130
{
131
132
133
    if (debug)
        qDebug() << __FUNCTION__ << index << newName;

134
135
136
137
138
139
140
141
    Q_ASSERT(index > 0 && index < m_modelStates.size());
    QmlModelState state = m_modelStates.at(index);
    Q_ASSERT(state.isValid());
    if (state.name() != newName) {
        // Jump to base state for the change
        QmlModelState oldState = currentState();
        setCurrentStateSilent(0);
        state.setName(newName);
142
        setCurrentState(m_modelStates.indexOf(oldState));
143
144
145
146
147
    }
}

void StatesEditorView::duplicateCurrentState(int index)
{
148
149
150
    if (debug)
        qDebug() << __FUNCTION__ << index;

151
    Q_ASSERT(index > 0 && index < m_modelStates.size());
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    QmlModelState state = m_modelStates.at(index);
    Q_ASSERT(state.isValid());
    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;
    QStringList stateNames = state.stateGroup().names();
    while (stateNames.contains(newName + QString::number(i)))
        i++;
    state.duplicate(newName + QString::number(i));
}

void StatesEditorView::modelAttached(Model *model)
{
172
173
174
    if (debug)
        qDebug() << __FUNCTION__;

175
176
177
178
179
180
181
182
    if (model == QmlModelView::model())
        return;

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

    // Add base state
183
184
185
    if (!baseState().isValid())
        return;

186
    m_modelStates.insert(0, baseState());
187
    m_attachedToModel = true;
188
189
    m_editorModel->insertState(0, baseState().name());

190
    // Add custom states
191
192
    m_stateRootNode = QmlItemNode(rootModelNode());
    if (!m_stateRootNode.isValid())
193
        return;    
194

195
196
197
198
    for (int i = 0; i < m_stateRootNode.states().allStates().size(); ++i) {
        QmlModelState state = QmlItemNode(rootModelNode()).states().allStates().at(i);
        insertModelState(i, state);
    }
199

200
201
202
203
204
205
206
}

void StatesEditorView::modelAboutToBeDetached(Model *model)
{
    if (debug)
        qDebug() << __FUNCTION__;

207
208
    m_attachedToModel = false;

209
210
211
212
213
    clearModelStates();

    QmlModelView::modelAboutToBeDetached(model);
}

214
void StatesEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList)
215
{
216
217
218
    if (debug)
        qDebug() << __FUNCTION__;

219
220
221
222
223
224
225
    foreach (const AbstractProperty &property, propertyList) {
        // remove all states except base state
        if ((property.name()=="states") && (property.parentModelNode().isRootNode())) {
            foreach (const QmlModelState &state, m_modelStates) {
                if (!state.isBaseState())
                    removeModelState(state);
            }
226
227
228
229
        } else {
            ModelNode node (property.parentModelNode().parentProperty().parentModelNode());
            if (QmlModelState(node).isValid()) {
                startUpdateTimer(modelStateIndex(node) + 1, 0);
230
231
232
            } else { //a change to the base state update all
                for (int i = 0; i < m_modelStates.count(); ++i)
                    startUpdateTimer(i, 0);
233
            }
234
235
        }
    }
236
    QmlModelView::propertiesAboutToBeRemoved(propertyList);
237
238
}

239
void StatesEditorView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
240
{
241
242
243
    if (debug)
        qDebug() << __FUNCTION__;

244
245
246
    QmlModelView::propertiesRemoved(propertyList);
}

247
void StatesEditorView::variantPropertiesChanged(const QList<VariantProperty> &propertyList, PropertyChangeFlags propertyChange)
248
{
249
250
251
    if (debug)
        qDebug() << __FUNCTION__;

252
253
254
255
256
257
258
259
260
261
262
263
264
    QmlModelView::variantPropertiesChanged(propertyList, propertyChange);
    foreach (const VariantProperty &property, propertyList) {
        ModelNode node (property.parentModelNode());
        if (QmlModelState(node).isValid() && (property.name() == QLatin1String("name"))) {
            int index = m_modelStates.indexOf(node);
            if (index != -1)
                m_editorModel->renameState(index, property.value().toString());
        }
    }
}

void StatesEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{
265
266
267
    if (debug)
        qDebug() << __FUNCTION__;

268
269
270
271
    if (removedNode.parentProperty().parentModelNode() == m_stateRootNode
          && QmlModelState(removedNode).isValid()) {
        removeModelState(removedNode);
    }
272

273
    QmlModelView::nodeAboutToBeRemoved(removedNode);
274
275
276
277
278
279
280

    if (QmlModelState(removedNode).isValid()) {
        startUpdateTimer(modelStateIndex(removedNode) + 1, 0);
    } else { //a change to the base state update all
        for (int i = 0; i < m_modelStates.count(); ++i)
            startUpdateTimer(i, 0);
    }
281
282
283
284
285
}


void StatesEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange)
{
286
287
288
    if (debug)
        qDebug() << __FUNCTION__;

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
    QmlModelView::nodeReparented(node, newPropertyParent, oldPropertyParent, propertyChange);

    // this would be sliding
    Q_ASSERT(newPropertyParent != oldPropertyParent);

    if (QmlModelState(node).isValid()) {
        if (oldPropertyParent.parentModelNode() == m_stateRootNode) {
            if (oldPropertyParent.isNodeListProperty()
                && oldPropertyParent.name() == "states") {
                removeModelState(node);
            } else {
                qWarning() << "States Editor: Reparented model state was not in states property list";
            }
        }

        if (newPropertyParent.parentModelNode() == m_stateRootNode) {
            if (newPropertyParent.isNodeListProperty()
                && newPropertyParent.name() == "states") {
                NodeListProperty statesProperty = newPropertyParent.toNodeListProperty();
                int index = statesProperty.toModelNodeList().indexOf(node);
                Q_ASSERT(index >= 0);
                insertModelState(index, node);
            } else {
                qWarning() << "States Editor: Reparented model state is not in the states property list";
            }
        }
    }
}

318
void StatesEditorView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex)
319
{
320
321
322
    if (debug)
        qDebug() << __FUNCTION__;

323
    QmlModelView::nodeOrderChanged(listProperty, movedNode, oldIndex);
324
325
    if (listProperty.parentModelNode() == m_stateRootNode
        && listProperty.name() == "states") {
326
327
328
329
330

        int newIndex = listProperty.toModelNodeList().indexOf(movedNode);
        Q_ASSERT(newIndex >= 0);

        QmlModelState state = QmlModelState(movedNode);
331
332
333
334
335
336
337
338
339
        if (state.isValid()) {
            Q_ASSERT(oldIndex == modelStateIndex(state));
            removeModelState(state);
            insertModelState(newIndex, state);
            Q_ASSERT(newIndex == modelStateIndex(state));
        }
    }
}

340
341
void StatesEditorView::nodeInstancePropertyChanged(const ModelNode &node, const QString &propertyName)
{
342
343
344
345
346
347
348
    if (!m_settingSilentState) {
        if (QmlModelState(node).isValid()) {
            startUpdateTimer(modelStateIndex(node) + 1, 0);
        } else { //a change to the base state update all
            for (int i = 0; i < m_modelStates.count(); ++i)
                startUpdateTimer(i, 0);
        }
349
350
351
352
353
    }

    QmlModelView::nodeInstancePropertyChanged(node, propertyName);
}

354
355
void StatesEditorView::stateChanged(const QmlModelState &newQmlModelState, const QmlModelState &oldQmlModelState)
{
356
357
358
    if (debug)
        qDebug() << __FUNCTION__;

359
360
    QmlModelView::stateChanged(newQmlModelState, oldQmlModelState);

361
362
363
364
365
366
    if (!m_settingSilentState) {
        if (newQmlModelState.isBaseState())
            m_editorModel->emitChangedToState(0);
        else
            m_editorModel->emitChangedToState(m_modelStates.indexOf(newQmlModelState));
    }
367
368
}

369
void StatesEditorView::transformChanged(const QmlObjectNode &qmlObjectNode, const QString &propertyName)
370
{
371
372
373
    if (debug)
        qDebug() << __FUNCTION__;

374
    QmlModelView::transformChanged(qmlObjectNode, propertyName);
375
376
377
378
}

void StatesEditorView::parentChanged(const QmlObjectNode &qmlObjectNode)
{
379
380
381
    if (debug)
        qDebug() << __FUNCTION__;

382
383
384
    QmlModelView::parentChanged(qmlObjectNode);
}

385
void StatesEditorView::otherPropertyChanged(const QmlObjectNode &qmlObjectNode, const QString &propertyName)
386
{
387
388
389
    if (debug)
        qDebug() << __FUNCTION__;

390
    QmlModelView::otherPropertyChanged(qmlObjectNode, propertyName);
391
392
393
}


Kai Koehne's avatar
Kai Koehne committed
394
void StatesEditorView::customNotification(const AbstractView * /*view*/, const QString & /*identifier*/, const QList<ModelNode> & /*nodeList*/, const QList<QVariant> & /*data*/)
395
{
396
397
398
    if (debug)
        qDebug() << __FUNCTION__;

399
400
401
402
}

QPixmap StatesEditorView::renderState(int i)
{
403
404
405
    if (debug)
        qDebug() << __FUNCTION__ << i;

406
407
408
    if (!m_attachedToModel)
        return QPixmap();

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
    Q_ASSERT(i >= 0 && i < m_modelStates.size());
    QmlModelState oldState = currentState();
    setCurrentStateSilent(i);

    Q_ASSERT(nodeInstanceView());

    const int checkerbordSize= 10;
    QPixmap tilePixmap(checkerbordSize * 2, checkerbordSize * 2);
    tilePixmap.fill(Qt::white);
    QPainter tilePainter(&tilePixmap);
    QColor color(220, 220, 220);
    tilePainter.fillRect(0, 0, checkerbordSize, checkerbordSize, color);
    tilePainter.fillRect(checkerbordSize, checkerbordSize, checkerbordSize, checkerbordSize, color);
    tilePainter.end();


425
426
427
428
429
430
431
    QSizeF pixmapSize(nodeInstanceView()->sceneRect().size());
    if (pixmapSize.width() > 100 || pixmapSize.height() > 100) // sensible maximum size
        pixmapSize.scale(QSize(100, 100), Qt::KeepAspectRatio);
    QSize cutSize(floor(pixmapSize.width()),floor(pixmapSize.height()));
    pixmapSize.setWidth(ceil(pixmapSize.width()));
    pixmapSize.setHeight(ceil(pixmapSize.height()));
    QPixmap pixmap(pixmapSize.toSize());
432
433
434
435
436

    QPainter painter(&pixmap);
    painter.drawTiledPixmap(pixmap.rect(), tilePixmap);
    nodeInstanceView()->render(&painter, pixmap.rect(), nodeInstanceView()->sceneRect());

437
    setCurrentStateSilent(m_modelStates.indexOf(oldState));
438

439
440
    Q_ASSERT(oldState == currentState());

441
    return pixmap.copy(0,0,cutSize.width(),cutSize.height());
442
443
444
445
}

void StatesEditorView::sceneChanged()
{
446
447
448
    if (debug)
        qDebug() << __FUNCTION__;

449
450
451
452
453
454
455
456
457
458
459
460
461
462
    // If we are in base state we have to update the pixmaps of all states
    // otherwise only the pixmpap for the current state

    if (currentState().isValid()) { //during setup we might get sceneChanged signals with an invalid currentState()
        if (currentState().isBaseState()) {
            for (int i = 0; i < m_modelStates.count(); ++i)
                startUpdateTimer(i, i * 80);
        } else {
            startUpdateTimer(modelStateIndex(currentState()) + 1, 0);
        }
    }
}

void StatesEditorView::startUpdateTimer(int i, int offset) {
463
464
465
    if (i < 0 || i >  m_modelStates.count())
        return;

466
467
468
    if (i < m_updateTimerIdList.size() && m_updateTimerIdList.at(i) != 0)
        return;
    // TODO: Add an offset so not all states are rendered at once
469
470


471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
    if (i < m_updateTimerIdList.size() && i > 0)
        if (m_updateTimerIdList.at(i))
            killTimer(m_updateTimerIdList.at(i));
    int j = i;

    while (m_updateTimerIdList.size() <= i) {
        m_updateTimerIdList.insert(j, 0);
        j++;
    }
    m_updateTimerIdList[i] =  startTimer(100 + offset);
}

// index without base state
void StatesEditorView::insertModelState(int i, const QmlModelState &state)
{
486
487
488
    if (debug)
        qDebug() << __FUNCTION__ << i << state.name();

489
490
491
492
493
494
495
496
497
    Q_ASSERT(state.isValid());
    Q_ASSERT(!state.isBaseState());
    // For m_modelStates / m_editorModel, i=0 is base state
    m_modelStates.insert(i+1, state);
    m_editorModel->insertState(i+1, state.name());
}

void StatesEditorView::removeModelState(const QmlModelState &state)
{
498
499
500
    if (debug)
        qDebug() << __FUNCTION__ << state.name();

501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
    Q_ASSERT(state.isValid());
    Q_ASSERT(!state.isBaseState());
    int index = m_modelStates.indexOf(state);
    if (index != -1) {
        m_modelStates.removeOne(state);

        if (m_updateTimerIdList.contains(index)) {
            killTimer(m_updateTimerIdList[index]);
            m_updateTimerIdList[index] = 0;
        }
        m_editorModel->removeState(index);
    }
}

void StatesEditorView::clearModelStates()
{
517
518
519
    if (debug)
        qDebug() << __FUNCTION__;

520
521
522

    // Remove all states
    const int modelStateCount = m_modelStates.size();
523
    for (int i=modelStateCount-1; i>=0; --i) {
524
525
        m_modelStates.removeAt(i);
        m_editorModel->removeState(i);
526
527
528
529
530
531
532
533
534
535
536
    }
}

// index without base state
int StatesEditorView::modelStateIndex(const QmlModelState &state)
{
    return m_modelStates.indexOf(state) - 1;
}

void StatesEditorView::timerEvent(QTimerEvent *event)
{
537
538
539
    if (debug)
        qDebug() << __FUNCTION__;

540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
    int index = m_updateTimerIdList.indexOf(event->timerId());
    if (index > -1) {
        event->accept();
        Q_ASSERT(index >= 0);
        if (index < m_modelStates.count()) //there might be updates for a state already deleted 100ms are long
            m_editorModel->updateState(index);
        killTimer(m_updateTimerIdList[index]);
       m_updateTimerIdList[index] = 0;
    } else {
        QmlModelView::timerEvent(event);
    }
}

} // namespace Internal
} // namespace QmlDesigner