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

    QStringList modelStateNames = rootStateGroup().names();

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

    try {
        if ((rootStateGroup().allStates().count() < 1) && //QtQuick import might be missing
            (!model()->hasImport(Import::createLibraryImport("QtQuick", "1.0"), true) &&
             !model()->hasImport(Import::createLibraryImport("QtQuick", "1.1"), true)))
            model()->changeImports(QList<Import>() << Import::createLibraryImport("QtQuick", "1.0"), QList<Import>());
        ModelNode newState = rootStateGroup().addState(newStateName);
        setCurrentState(newState);
    }  catch (RewritingException &e) {
        QMessageBox::warning(0, "Error", e.description());
    }
}
QmlItemNode QmlModelView::createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry, const QPointF &position, QmlItemNode parentNode)
{
    if (!parentNode.isValid())
        parentNode = rootQmlItemNode();

    Q_ASSERT(parentNode.isValid());


    QmlItemNode newNode;
    RewriterTransaction transaction = beginRewriterTransaction();
    {
        QList<QPair<QString, QVariant> > propertyPairList;
        propertyPairList.append(qMakePair(QString("x"), QVariant(round(position.x(), 4))));
        propertyPairList.append(qMakePair(QString("y"), QVariant(round(position.y(), 4))));

        foreach (const PropertyContainer &property, itemLibraryEntry.properties())
            propertyPairList.append(qMakePair(property.name(), property.value()));

        newNode = createQmlItemNode(itemLibraryEntry.typeName(), itemLibraryEntry.majorVersion(), itemLibraryEntry.minorVersion(), propertyPairList);
        parentNode.nodeAbstractProperty("data").reparentHere(newNode);

        Q_ASSERT(newNode.isValid());

        QString id;
        int i = 1;
        QString name(itemLibraryEntry.name().toLower());
        //remove forbidden characters
        name.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_"));
        do {
            id = name + QString::number(i);
            i++;
        } while (hasId(id)); //If the name already exists count upwards

        try {
            newNode.setId(id);
        } catch (InvalidIdException &e) {
            // should never happen
            QMessageBox::warning(0, tr("Invalid Id"), e.description());
        }

        if (!currentState().isBaseState()) {
            newNode.modelNode().variantProperty("opacity") = 0;
            newNode.setVariantProperty("opacity", 1);
        }

        Q_ASSERT(newNode.isValid());
    }

    Q_ASSERT(newNode.isValid());

    return newNode;
}
QmlItemNode QmlModelView::createQmlItemNodeFromImage(const QString &imageName, const QPointF &position, QmlItemNode parentNode)
{
    if (!parentNode.isValid())
        parentNode = rootQmlItemNode();

    if (!parentNode.isValid())
        return QmlItemNode();

    QmlItemNode newNode;
    RewriterTransaction transaction = beginRewriterTransaction();
    {
        QList<QPair<QString, QVariant> > propertyPairList;
        propertyPairList.append(qMakePair(QString("x"), QVariant( round(position.x(), 4))));
        propertyPairList.append(qMakePair(QString("y"), QVariant( round(position.y(), 4))));

        QString relativeImageName = imageName;

        //use relative path
        if (QFileInfo(model()->fileUrl().toLocalFile()).exists()) {
            QDir fileDir(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath());
            relativeImageName = fileDir.relativeFilePath(imageName);
        }

        propertyPairList.append(qMakePair(QString("source"), QVariant(relativeImageName)));
        newNode = createQmlItemNode("Qt/Image",4, 7, propertyPairList);
        parentNode.nodeAbstractProperty("data").reparentHere(newNode);

        Q_ASSERT(newNode.isValid());

        QString id;
        int i = 1;
        QString name("image");
        name.remove(QLatin1Char(' '));
        do {
            id = name + QString::number(i);
            i++;
        } while (hasId(id)); //If the name already exists count upwards

        newNode.setId(id);
        if (!currentState().isBaseState()) {
            newNode.modelNode().variantProperty("opacity") = 0;
            newNode.setVariantProperty("opacity", 1);
        }

        Q_ASSERT(newNode.isValid());
    }

    Q_ASSERT(newNode.isValid());

    return newNode;
}
QmlItemNode QmlModelView::createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry, const QPointF &position, QmlItemNode parentNode)
{
    if (!parentNode.isValid())
        parentNode = rootQmlItemNode();

    Q_ASSERT(parentNode.isValid());

    QmlItemNode newNode;

    try {
        RewriterTransaction transaction = beginRewriterTransaction();
        if (itemLibraryEntry.typeName().contains('.')) {

            const QString newImportUrl = itemLibraryEntry.requiredImport();

            if (!itemLibraryEntry.requiredImport().isEmpty()) {
                const QString newImportVersion = QString("%1.%2").arg(QString::number(itemLibraryEntry.majorVersion()), QString::number(itemLibraryEntry.minorVersion()));
                Import newImport = Import::createLibraryImport(newImportUrl, newImportVersion);

                foreach (const Import &import, model()->imports()) {
                    if (import.isLibraryImport()
                            && import.url() == newImport.url()
                            && import.version() == newImport.version()) {
                        // reuse this import
                        newImport = import;
                        break;
                    }
                }

                if (!model()->hasImport(newImport, true, true)) {
                    model()->changeImports(QList<Import>() << newImport, QList<Import>());
                }
            }
        }

        QList<QPair<QString, QVariant> > propertyPairList;
        propertyPairList.append(qMakePair(QString("x"), QVariant(round(position.x(), 4))));
        propertyPairList.append(qMakePair(QString("y"), QVariant(round(position.y(), 4))));

        if (itemLibraryEntry.qml().isEmpty()) {
            foreach (const PropertyContainer &property, itemLibraryEntry.properties())
                propertyPairList.append(qMakePair(property.name(), property.value()));

            newNode = createQmlItemNode(itemLibraryEntry.typeName(), itemLibraryEntry.majorVersion(), itemLibraryEntry.minorVersion(), propertyPairList);
        } else {
            QScopedPointer<Model> inputModel(Model::create("QtQuick.Rectangle", 1, 0, model()));
            inputModel->setFileUrl(model()->fileUrl());
            QPlainTextEdit textEdit;


            textEdit.setPlainText(Utils::FileReader::fetchQrc(itemLibraryEntry.qml()));
            NotIndentingTextEditModifier modifier(&textEdit);

            QScopedPointer<RewriterView> rewriterView(new RewriterView(RewriterView::Amend, 0));
            rewriterView->setCheckSemanticErrors(false);
            rewriterView->setTextModifier(&modifier);
            inputModel->attachView(rewriterView.data());

            if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) {
                ModelNode rootModelNode = rewriterView->rootModelNode();
                inputModel->detachView(rewriterView.data());

                rootModelNode.variantProperty("x") = propertyPairList.first().second;
                rootModelNode.variantProperty("y") = propertyPairList.at(1).second;

                ModelMerger merger(this);
                newNode = merger.insertModel(rootModelNode);               
            }
        }

        if (parentNode.hasDefaultProperty()) {
            parentNode.nodeAbstractProperty(parentNode.defaultProperty()).reparentHere(newNode);
        }

        if (!newNode.isValid())
            return newNode;

        QString id;
        int i = 1;
        QString name(itemLibraryEntry.name().toLower());
        //remove forbidden characters
        name.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_"));
        do {
            id = name + QString::number(i);
            i++;
        } while (hasId(id)); //If the name already exists count upwards

        newNode.setId(id);

        if (!currentState().isBaseState()) {
            newNode.modelNode().variantProperty("opacity") = 0;
            newNode.setVariantProperty("opacity", 1);
        }

        Q_ASSERT(newNode.isValid());
    }
QmlItemNode QmlModelView::createQmlItemNodeFromImage(const QString &imageName, const QPointF &position, QmlItemNode parentNode)
{
    if (!parentNode.isValid())
        parentNode = rootQmlItemNode();

    if (!parentNode.isValid())
        return QmlItemNode();

    QmlItemNode newNode;
    RewriterTransaction transaction = beginRewriterTransaction();
    {
        const QString newImportUrl = QLatin1String("QtQuick");
        const QString newImportVersion = QLatin1String("1.0");
        Import newImport = Import::createLibraryImport(newImportUrl, newImportVersion);

        foreach (const Import &import, model()->imports()) {
            if (import.isLibraryImport()
                && import.url() == newImport.url()
                && import.version() == newImport.version()) {
                // reuse this import
                newImport = import;
                break;
            }
        }

        if (!model()->imports().contains(newImport)) {
            model()->changeImports(QList<Import>() << newImport, QList<Import>());
        }

        QList<QPair<QString, QVariant> > propertyPairList;
        propertyPairList.append(qMakePair(QString("x"), QVariant( round(position.x(), 4))));
        propertyPairList.append(qMakePair(QString("y"), QVariant( round(position.y(), 4))));

        QString relativeImageName = imageName;

        //use relative path
        if (QFileInfo(model()->fileUrl().toLocalFile()).exists()) {
            QDir fileDir(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath());
            relativeImageName = fileDir.relativeFilePath(imageName);
        }

        propertyPairList.append(qMakePair(QString("source"), QVariant(relativeImageName)));
        newNode = createQmlItemNode("QtQuick.Image", 1, 0, propertyPairList);
        parentNode.nodeAbstractProperty("data").reparentHere(newNode);

        Q_ASSERT(newNode.isValid());

        QString id;
        int i = 1;
        QString name("image");
        name.remove(QLatin1Char(' '));
        do {
            id = name + QString::number(i);
            i++;
        } while (hasId(id)); //If the name already exists count upwards

        newNode.setId(id);
        if (!currentState().isBaseState()) {
            newNode.modelNode().variantProperty("opacity") = 0;
            newNode.setVariantProperty("opacity", 1);
        }

        Q_ASSERT(newNode.isValid());
    }

    Q_ASSERT(newNode.isValid());

    return newNode;
}