stateseditorview.cpp 12.2 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
**
** 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"
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
enum {
48
    debug = false
49 50 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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
        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();
        }
96 97 98
    }  catch (RewritingException &e) {
        QMessageBox::warning(0, "Error", e.description());
    }
99 100
}

101
void StatesEditorView::synchonizeCurrentStateFromWidget()
102
{
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 117 118 119 120 121 122
void StatesEditorView::createNewState()
{
    if (currentState().isBaseState()) {
        addState();
    } else {
        duplicateCurrentState();
    }
}
123

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

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

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

140 141 142 143 144
    try {
        if (rootStateGroup().allStates().count() < 1)
            model()->addImport(Import::createLibraryImport("QtQuick", "1.0"));
        ModelNode newState = rootStateGroup().addState(newStateName);
        setCurrentState(newState);
145 146 147
    }  catch (RewritingException &e) {
        QMessageBox::warning(0, "Error", e.description());
    }
148 149
}

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

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

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

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

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

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

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

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
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)
{
219 220 221 222 223
    if (model == QmlModelView::model())
        return;

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

225
    resetModel();
226 227 228 229 230
}

void StatesEditorView::modelAboutToBeDetached(Model *model)
{
    QmlModelView::modelAboutToBeDetached(model);
231
    resetModel();
232 233
}

234
void StatesEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList)
235 236
{
    foreach (const AbstractProperty &property, propertyList) {
237 238
        if (property.name() == "states" && property.parentModelNode().isRootNode())
            m_statesEditorModel->reset();
239 240 241 242
    }
}


243
void StatesEditorView::variantPropertiesChanged(const QList<VariantProperty> &propertyList, PropertyChangeFlags propertyChange)
244 245
{
    foreach (const VariantProperty &property, propertyList) {
246 247 248 249 250
        if (property.name() == "name" && property.parentModelNode().hasParentProperty()) {
            NodeAbstractProperty parentProperty = property.parentModelNode().parentProperty();
            if (parentProperty.name() == "states" && parentProperty.parentModelNode().isRootNode()) {
                m_statesEditorModel->updateState(parentProperty.indexOf(property.parentModelNode()));
            }
251 252 253 254
        }
    }
}

255

256 257
void StatesEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{
258 259 260 261 262 263
    if (removedNode.hasParentProperty()) {
        const NodeAbstractProperty propertyParent = removedNode.parentProperty();
        if (propertyParent.parentModelNode().isRootNode() && propertyParent.name() == "states") {
            m_lastIndex = propertyParent.indexOf(removedNode);
        }
    }
264 265
}

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

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

280

281 282 283 284
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);
285

286
    m_lastIndex = -1;
287

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

294
void StatesEditorView::nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex)
295
{
296 297
    if (listProperty.isValid() && listProperty.parentModelNode().isRootNode() && listProperty.name() == "states")
        resetModel();
298 299
}

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

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

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

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

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


332
void StatesEditorView::customNotification(const AbstractView * view, const QString & identifier, const QList<ModelNode> & nodeList, const QList<QVariant> &imageList)
333
{
334 335 336
    if (debug)
        qDebug() << __FUNCTION__;

337 338 339 340 341 342 343 344 345 346
    if (identifier == "__state preview updated__")   {
        if (nodeList.size() != imageList.size())
            return;

//        if (++m_updateCounter == INT_MAX)
//            m_updateCounter = 0;

        for (int i = 0; i < nodeList.size(); i++) {
            QmlModelState modelState(nodeList.at(i));            
        }
347

348 349 350 351 352
     //   emit dataChanged(createIndex(i, 0), createIndex(i, 0));

    } else {
        QmlModelView::customNotification(view, identifier, nodeList, imageList);
    }
353 354
}

Marco Bubke's avatar
Marco Bubke committed
355 356 357 358 359 360 361 362
void StatesEditorView::scriptFunctionsChanged(const ModelNode &node, const QStringList &scriptFunctionList)
{
    if (debug)
        qDebug() << __FUNCTION__;

    QmlModelView::scriptFunctionsChanged(node, scriptFunctionList);
}

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

}

378
} // namespace QmlDesigner