/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. ** ** 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. ** ** 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. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "abstractview.h" #include "model.h" #include "model_p.h" #include "internalnode_p.h" #include "nodeinstanceview.h" #include namespace QmlDesigner { /*! \class QmlDesigner::AbstractView \ingroup CoreModel \brief The AbstractView class provides an abstract interface that views and editors can implement to be notified about model changes. \sa QmlDesigner::WidgetQueryView(), QmlDesigner::NodeInstanceView() */ AbstractView::~AbstractView() { if (m_model) m_model.data()->detachView(this, Model::DoNotNotifyView); } /*! Sets the view of a new \a model. This is handled automatically by AbstractView::modelAttached(). \sa AbstractView::modelAttached() */ void AbstractView::setModel(Model *model) { Q_ASSERT(model != 0); if (model == m_model.data()) return; if (m_model) m_model.data()->detachView(this); m_model = model; } RewriterTransaction AbstractView::beginRewriterTransaction() { return RewriterTransaction(this); } ModelNode AbstractView::createModelNode(const TypeName &typeName, int majorVersion, int minorVersion, const QList > &propertyList, const QList > &auxPropertyList, const QString &nodeSource, ModelNode::NodeSourceType nodeSourceType) { return ModelNode(model()->d->createNode(typeName, majorVersion, minorVersion, propertyList, auxPropertyList, nodeSource, nodeSourceType), model(), this); } /*! Returns the constant root model node. */ const ModelNode AbstractView::rootModelNode() const { Q_ASSERT(model()); return ModelNode(model()->d->rootNode(), model(), const_cast(this)); } /*! Returns the root model node. */ ModelNode AbstractView::rootModelNode() { Q_ASSERT(model()); return ModelNode(model()->d->rootNode(), model(), this); } /*! Sets the reference to a model to a null pointer. */ void AbstractView::removeModel() { m_model.clear(); } WidgetInfo AbstractView::createWidgetInfo(QWidget *widget, WidgetInfo::ToolBarWidgetFactoryInterface *toolBarWidgetFactory, const QString &uniqueId, WidgetInfo::PlacementHint placementHint, int placementPriority, const QString &tabName) { WidgetInfo widgetInfo; widgetInfo.widget = widget; widgetInfo.toolBarWidgetFactory = toolBarWidgetFactory; widgetInfo.uniqueId = uniqueId; widgetInfo.placementHint = placementHint; widgetInfo.placementPriority = placementPriority; widgetInfo.tabName = tabName; return widgetInfo; } /*! Returns the model of the view. */ Model* AbstractView::model() const { return m_model.data(); } bool AbstractView::isAttached() const { return model(); } /*! Called if a view is being attached to \a model. The default implementation is setting the reference of the model to the view. \sa Model::attachView() */ void AbstractView::modelAttached(Model *model) { setModel(model); } /*! Called before a view is detached from \a model. This function is not called if Model::detachViewWithOutNotification is used. The default implementation is removing the reference to the model from the view. \sa Model::detachView() */ void AbstractView::modelAboutToBeDetached(Model *) { removeModel(); } /*! \enum QmlDesigner::AbstractView::PropertyChangeFlag Notifies about changes in the abstract properties of a node: \value NoAdditionalChanges No changes were made. \value PropertiesAdded Some properties were added. \value EmptyPropertiesRemoved Empty properties were removed. */ // Node related functions /*! \fn void AbstractView::nodeCreated(const ModelNode &createdNode) Called when the new node \a createdNode is created. */ /*! Called when the file URL (that is needed to resolve relative paths against, for example) is changed form \a oldUrl to \a newUrl. */ void AbstractView::fileUrlChanged(const QUrl &/*oldUrl*/, const QUrl &/*newUrl*/) { } /*! \fn void AbstractView::nodeAboutToBeRemoved(const ModelNode &removedNode) Called when the node specified by \a removedNode will be removed. */ /*! Called when the properties specified by \a propertyList are removed. */ void AbstractView::propertiesRemoved(const QList& /*propertyList*/) { } /*! \fn void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) Called when the parent of \a node will be changed from \a oldPropertyParent to \a newPropertyParent. */ /*! \fn void QmlDesigner::AbstractView::selectedNodesChanged(const QList &selectedNodeList, const QList &lastSelectedNodeList) Called when the selection is changed from \a lastSelectedNodeList to \a selectedNodeList. */ void AbstractView::auxiliaryDataChanged(const ModelNode &/*node*/, const PropertyName &/*name*/, const QVariant &/*data*/) { } void AbstractView::customNotification(const AbstractView * /*view*/, const QString & /*identifier*/, const QList & /*nodeList*/, const QList & /*data*/) { } QList AbstractView::toModelNodeList(const QList &nodeList) const { return QmlDesigner::toModelNodeList(nodeList, const_cast(this)); } QList toModelNodeList(const QList &nodeList, AbstractView *view) { QList newNodeList; foreach (const Internal::InternalNode::Pointer &node, nodeList) newNodeList.append(ModelNode(node, view->model(), view)); return newNodeList; } QList toInternalNodeList(const QList &nodeList) { QList newNodeList; foreach (const ModelNode &node, nodeList) newNodeList.append(node.internalNode()); return newNodeList; } /*! Sets the list of nodes to the actual selected nodes specified by \a selectedNodeList. */ void AbstractView::setSelectedModelNodes(const QList &selectedNodeList) { model()->d->setSelectedNodes(toInternalNodeList(selectedNodeList)); } void AbstractView::setSelectedModelNode(const ModelNode &modelNode) { setSelectedModelNodes(QList() << modelNode); } /*! Clears the selection. */ void AbstractView::clearSelectedModelNodes() { model()->d->clearSelectedNodes(); } bool AbstractView::hasSelectedModelNodes() const { return !model()->d->selectedNodes().isEmpty(); } bool AbstractView::hasSingleSelectedModelNode() const { return model()->d->selectedNodes().count() == 1; } bool AbstractView::isSelectedModelNode(const ModelNode &modelNode) const { return model()->d->selectedNodes().contains(modelNode.internalNode()); } /*! Sets the list of nodes to the actual selected nodes. Returns a list of the selected nodes. */ QList AbstractView::selectedModelNodes() const { return toModelNodeList(model()->d->selectedNodes()); } ModelNode AbstractView::firstSelectedModelNode() const { if (hasSelectedModelNodes()) return ModelNode(model()->d->selectedNodes().first(), model(), this); return ModelNode(); } ModelNode AbstractView::singleSelectedModelNode() const { if (hasSingleSelectedModelNode()) return ModelNode(model()->d->selectedNodes().first(), model(), this); return ModelNode(); } /*! Adds \a node to the selection list. */ void AbstractView::selectModelNode(const ModelNode &node) { model()->d->selectNode(node.internalNode()); } /*! Removes \a node from the selection list. */ void AbstractView::deselectModelNode(const ModelNode &node) { model()->d->deselectNode(node.internalNode()); } ModelNode AbstractView::modelNodeForId(const QString &id) { return ModelNode(model()->d->nodeForId(id), model(), this); } bool AbstractView::hasId(const QString &id) const { return model()->d->hasId(id); } QString firstCharToLower(const QString string) { QString resultString = string; if (!resultString.isEmpty()) resultString[0] = resultString.at(0).toLower(); return resultString; } QString AbstractView::generateNewId(const QString prefixName) const { int counter = 1; QString newId = QString("%1%2").arg(firstCharToLower(prefixName)).arg(counter); newId.remove(QRegExp(QLatin1String("[^a-zA-Z0-9_]"))); while (hasId(newId)) { counter += 1; newId = QString("%1%2").arg(firstCharToLower(prefixName)).arg(counter); newId.remove(QRegExp(QLatin1String("[^a-zA-Z0-9_]"))); } return newId; } ModelNode AbstractView::modelNodeForInternalId(qint32 internalId) const { return ModelNode(model()->d->nodeForInternalId(internalId), model(), this); } bool AbstractView::hasModelNodeForInternalId(qint32 internalId) const { return model()->d->hasNodeForInternalId(internalId); } NodeInstanceView *AbstractView::nodeInstanceView() const { if (model()) return model()->d->nodeInstanceView(); else return 0; } RewriterView *AbstractView::rewriterView() const { if (model()) return model()->d->rewriterView(); else return 0; } void AbstractView::resetView() { if (!model()) return; Model *currentModel = model(); currentModel->detachView(this); currentModel->attachView(this); } bool AbstractView::hasWidget() const { return false; } WidgetInfo AbstractView::widgetInfo() { return createWidgetInfo(); } QList AbstractView::allModelNodes() const { return toModelNodeList(model()->d->allNodes()); } void AbstractView::emitCustomNotification(const QString &identifier) { emitCustomNotification(identifier, QList()); } void AbstractView::emitCustomNotification(const QString &identifier, const QList &nodeList) { emitCustomNotification(identifier, nodeList, QList()); } void AbstractView::emitCustomNotification(const QString &identifier, const QList &nodeList, const QList &data) { model()->d->notifyCustomNotification(this, identifier, nodeList, data); } void AbstractView::emitInstancePropertyChange(const QList > &propertyList) { if (model() && nodeInstanceView() == this) model()->d->notifyInstancePropertyChange(propertyList); } void AbstractView::emitInstancesCompleted(const QVector &nodeVector) { if (model() && nodeInstanceView() == this) model()->d->notifyInstancesCompleted(nodeVector); } void AbstractView::emitInstanceInformationsChange(const QMultiHash &informationChangeHash) { if (model() && nodeInstanceView() == this) model()->d->notifyInstancesInformationsChange(informationChangeHash); } void AbstractView::emitInstancesRenderImageChanged(const QVector &nodeVector) { if (model() && nodeInstanceView() == this) model()->d->notifyInstancesRenderImageChanged(nodeVector); } void AbstractView::emitInstancesPreviewImageChanged(const QVector &nodeVector) { if (model() && nodeInstanceView() == this) model()->d->notifyInstancesPreviewImageChanged(nodeVector); } void AbstractView::emitInstancesChildrenChanged(const QVector &nodeVector) { if (model() && nodeInstanceView() == this) model()->d->notifyInstancesChildrenChanged(nodeVector); } void AbstractView::emitRewriterBeginTransaction() { if (model()) model()->d->notifyRewriterBeginTransaction(); } void AbstractView::sendTokenToInstances(const QString &token, int number, const QVector &nodeVector) { if (nodeInstanceView()) nodeInstanceView()->sendToken(token, number, nodeVector); } void AbstractView::emitInstanceToken(const QString &token, int number, const QVector &nodeVector) { if (nodeInstanceView()) model()->d->notifyInstanceToken(token, number, nodeVector); } void AbstractView::emitRewriterEndTransaction() { if (model()) model()->d->notifyRewriterEndTransaction(); } void AbstractView::setCurrentStateNode(const ModelNode &node) { Internal::WriteLocker locker(m_model.data()); if (model()) model()->d->notifyCurrentStateChanged(node); } void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion) { Internal::WriteLocker locker(m_model.data()); m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion); } ModelNode AbstractView::currentStateNode() const { if (model()) return ModelNode(m_model.data()->d->currentStateNode(), m_model.data(), const_cast(this)); return ModelNode(); } QmlModelState AbstractView::currentState() const { return QmlModelState(currentStateNode()); } static int getMajorVersionFromImport(const Model *model) { foreach (const Import &import, model->imports()) { if (import.isLibraryImport() && import.url() == QLatin1String("QtQuick")) { const QString versionString = import.version(); if (versionString.contains(QLatin1String("."))) { const QString majorVersionString = versionString.split(QLatin1String(".")).first(); return majorVersionString.toInt(); } } } return -1; } static int getMajorVersionFromNode(const ModelNode &modelNode) { if (modelNode.metaInfo().isValid()) { if (modelNode.type() == "QtQuick.QtObject" || modelNode.type() == "QtQuick.Item") return modelNode.majorVersion(); foreach (const NodeMetaInfo &superClass, modelNode.metaInfo().superClasses()) { if (modelNode.type() == "QtQuick.QtObject" || modelNode.type() == "QtQuick.Item") return superClass.majorVersion(); } } return 1; //default } int AbstractView::majorQtQuickVersion() const { int majorVersionFromImport = getMajorVersionFromImport(model()); if (majorVersionFromImport >= 0) return majorVersionFromImport; return getMajorVersionFromNode(rootModelNode()); } } // namespace QmlDesigner