From 2c15b30a2098a1ce127ab5d5b1d067e43eb3b817 Mon Sep 17 00:00:00 2001 From: Lasse Holmstedt <lasse.holmstedt@nokia.com> Date: Fri, 30 Jul 2010 15:28:05 +0200 Subject: [PATCH] Qml JS Live Preview: Show warnings when running Live Preview Two kinds of warnings are now shown: one for warning about the Live Preview itself, as it is experimental, and another when user changes id's of objects during runtime, as this is not supported at the moment. More warnings will be added later for other unsupported changes. --- .../qmljsinspector/qmlinspectortoolbar.cpp | 7 ++- .../qmljsinspector/qmlinspectortoolbar.h | 2 + src/plugins/qmljsinspector/qmljsinspector.cpp | 20 +++++++ src/plugins/qmljsinspector/qmljsinspector.h | 11 ++++ .../qmljsinspector/qmljsinspectorconstants.h | 3 + .../qmljsinspector/qmljsinspectorplugin.cpp | 1 + .../qmljsinspector/qmljslivetextpreview.cpp | 56 ++++++++++++++++++- .../qmljsinspector/qmljslivetextpreview.h | 7 ++- 8 files changed, 104 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp b/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp index 0b7870eef0f..98d4dd3adab 100644 --- a/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp +++ b/src/plugins/qmljsinspector/qmlinspectortoolbar.cpp @@ -166,7 +166,7 @@ void QmlInspectorToolbar::createActions(const Core::Context &context) m_selectMarqueeAction = new QAction(QIcon(":/qml/images/select-marquee-small.png"), tr("Select (Marquee)"), this); m_zoomAction = new QAction(QIcon(":/qml/images/zoom-small.png"), tr("Zoom"), this); m_colorPickerAction = new QAction(QIcon(":/qml/images/color-picker-small.png"), tr("Color Picker"), this); - m_toQmlAction = new QAction(QIcon(":/qml/images/to-qml-small.png"), tr("Apply Changes to QML Viewer"), this); + m_toQmlAction = new QAction(QIcon(":/qml/images/to-qml-small.png"), tr("Live Preview Changes in QML Viewer"), this); m_designmodeAction->setCheckable(true); m_designmodeAction->setChecked(false); @@ -401,6 +401,11 @@ void QmlInspectorToolbar::activateZoomOnClick() } } +void QmlInspectorToolbar::setLivePreviewChecked(bool value) +{ + m_fromQmlAction->setChecked(value); +} + void QmlInspectorToolbar::setSelectedColor(const QColor &color) { m_colorBox->setColor(color); diff --git a/src/plugins/qmljsinspector/qmlinspectortoolbar.h b/src/plugins/qmljsinspector/qmlinspectortoolbar.h index efed26f50f6..21d3c9d7196 100644 --- a/src/plugins/qmljsinspector/qmlinspectortoolbar.h +++ b/src/plugins/qmljsinspector/qmlinspectortoolbar.h @@ -46,6 +46,8 @@ public slots: void setDesignModeBehavior(bool inDesignMode); void setSelectedColor(const QColor &color); + void setLivePreviewChecked(bool value); + signals: void animationSpeedChanged(qreal slowdownFactor = 1.0f); diff --git a/src/plugins/qmljsinspector/qmljsinspector.cpp b/src/plugins/qmljsinspector/qmljsinspector.cpp index eb477773f7c..0201deaddfd 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.cpp +++ b/src/plugins/qmljsinspector/qmljsinspector.cpp @@ -116,6 +116,8 @@ enum { ConnectionAttemptSimultaneousInterval = 500 }; +bool Inspector::m_showExperimentalWarning = true; + Inspector::Inspector(QObject *parent) : QObject(parent), m_connectionTimer(new QTimer(this)), @@ -275,6 +277,9 @@ void Inspector::createPreviewForEditor(Core::IEditor *newEditor) connect(preview, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)), SLOT(changeSelectedItems(QList<QDeclarativeDebugObjectReference>))); + connect(preview, SIGNAL(reloadQmlViewerRequested()), m_clientProxy, SLOT(reloadQmlViewer())); + connect(preview, SIGNAL(disableLivePreviewRequested()), SLOT(disableLivePreview())); + m_textPreviews.insert(newEditor->file()->fileName(), preview); preview->associateEditor(newEditor); preview->updateDebugIds(m_clientProxy->rootObjectReference()); @@ -640,6 +645,7 @@ bool Inspector::addQuotesForData(const QVariant &value) const void Inspector::setApplyChangesToQmlObserver(bool applyChanges) { + emit livePreviewActivated(applyChanges); QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews); while(iter.hasNext()) { iter.next(); @@ -647,3 +653,17 @@ void Inspector::setApplyChangesToQmlObserver(bool applyChanges) } } +bool Inspector::showExperimentalWarning() +{ + return m_showExperimentalWarning; +} + +void Inspector::setShowExperimentalWarning(bool value) +{ + m_showExperimentalWarning = value; +} + +void Inspector::disableLivePreview() +{ + setApplyChangesToQmlObserver(false); +} diff --git a/src/plugins/qmljsinspector/qmljsinspector.h b/src/plugins/qmljsinspector/qmljsinspector.h index 81dc606aa0f..fb83678b3cf 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.h +++ b/src/plugins/qmljsinspector/qmljsinspector.h @@ -79,6 +79,7 @@ public: Inspector(QObject *parent = 0); virtual ~Inspector(); + bool connectToViewer(); // using host, port from widgets void shutdown(); @@ -92,8 +93,13 @@ public: QDeclarativeDebugExpressionQuery *setBindingForObject(int objectDebugId, const QString &objectId, const QString &propertyName, const QVariant &value, bool isLiteralValue); + static bool showExperimentalWarning(); + static void setShowExperimentalWarning(bool value); + + signals: void statusMessage(const QString &text); + void livePreviewActivated(bool isActivated); public slots: void setSimpleDockWidgetArrangement(); @@ -122,6 +128,8 @@ private slots: void removePreviewForEditor(Core::IEditor *newEditor); void createPreviewForEditor(Core::IEditor *newEditor); + void disableLivePreview(); + private: Debugger::DebuggerRunControl *createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig, const QString &executableFile = QString(), @@ -136,6 +144,7 @@ private: bool addQuotesForData(const QVariant &value) const; void resetViews(); + QmlJS::ModelManagerInterface *modelManager(); void initializeDocuments(); @@ -151,6 +160,8 @@ private: DebugMode m_debugMode; ClientProxy *m_clientProxy; + static bool m_showExperimentalWarning; + // Qml/JS integration QHash<QString, QmlJSLiveTextPreview *> m_textPreviews; QmlJS::Snapshot m_loadedSnapshot; //the snapshot loaded by the viewer diff --git a/src/plugins/qmljsinspector/qmljsinspectorconstants.h b/src/plugins/qmljsinspector/qmljsinspectorconstants.h index 5915d1bb2b9..b8ffb798b93 100644 --- a/src/plugins/qmljsinspector/qmljsinspectorconstants.h +++ b/src/plugins/qmljsinspector/qmljsinspectorconstants.h @@ -40,6 +40,9 @@ const char * const COMPLETE_THIS = "QmlInspector.CompleteThis"; const char * const M_DEBUG_SIMULTANEOUSLY = "QmlInspector.Menu.SimultaneousDebug"; +const char * const INFO_EXPERIMENTAL = "QmlInspector.Experimental"; +const char * const INFO_OUT_OF_SYNC = "QmlInspector.OutOfSyncWarning"; + const char * const LANG_QML = "QML"; const char * const DESIGNMODE_ACTION = "QmlInspector.DesignMode"; diff --git a/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp b/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp index f69fb16967f..8a5a0dc9629 100644 --- a/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp +++ b/src/plugins/qmljsinspector/qmljsinspectorplugin.cpp @@ -168,6 +168,7 @@ void InspectorPlugin::extensionsInitialized() connect(m_toolbar, SIGNAL(marqueeSelectToolSelected()), _clientProxy, SLOT(changeToSelectMarqueeTool())); connect(m_toolbar, SIGNAL(applyChangesFromQmlFileTriggered(bool)), _inspector, SLOT(setApplyChangesToQmlObserver(bool))); + connect(_inspector, SIGNAL(livePreviewActivated(bool)), m_toolbar, SLOT(setLivePreviewChecked(bool))); connect(_clientProxy, SIGNAL(colorPickerActivated()), m_toolbar, SLOT(activateColorPicker())); connect(_clientProxy, SIGNAL(selectToolActivated()), m_toolbar, SLOT(activateSelectTool())); connect(_clientProxy, SIGNAL(selectMarqueeToolActivated()), m_toolbar, SLOT(activateMarqueeSelectTool())); diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp index 2793d9ee6fd..4c1707254a0 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp @@ -29,10 +29,12 @@ #include <typeinfo> +#include "qmljsinspector.h" #include "qmljsclientproxy.h" #include "qmljslivetextpreview.h" #include "qmljsprivateapi.h" +#include "qmljsinspectorconstants.h" #include <qmljseditor/qmljseditorconstants.h> #include <qmljseditor/qmljseditor.h> #include <qmljs/qmljsdelta.h> @@ -430,6 +432,12 @@ protected: virtual void updateScriptBinding(DebugId debugId, UiScriptBinding* scriptBinding, const QString& propertyName, const QString& scriptCode) { + if (propertyName == QLatin1String("id") && !hasUnsyncronizableChanges) { + hasUnsyncronizableChanges = true; + unsyncronizableChangeLine = scriptBinding->firstSourceLocation().startLine; + unsyncronizableChangeColumn = scriptBinding->firstSourceLocation().startColumn; + } + QVariant expr = scriptCode; const bool isLiteral = isLiteralValue(scriptBinding); if (isLiteral) @@ -455,8 +463,12 @@ virtual void updateScriptBinding(DebugId debugId, UiScriptBinding* scriptBinding } public: - UpdateObserver() : referenceRefreshRequired(false) {} + UpdateObserver() : referenceRefreshRequired(false), hasUnsyncronizableChanges(false) {} bool referenceRefreshRequired; + bool hasUnsyncronizableChanges; + unsigned unsyncronizableChangeLine; + unsigned unsyncronizableChangeColumn; + }; void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) @@ -470,9 +482,17 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) if (!core->hasContext(dbgcontext)) return; + bool experimentalWarningShown = false; + if (m_applyChangesToQmlObserver) { m_docWithUnappliedChanges.clear(); + if (Inspector::showExperimentalWarning()) { + showExperimentalWarning(); + experimentalWarningShown = true; + Inspector::setShowExperimentalWarning(false); + } + if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName() && doc->qmlProgram() && m_previousDoc->qmlProgram()) { @@ -482,6 +502,9 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) if (delta.referenceRefreshRequired) ClientProxy::instance()->refreshObjectTree(); + if (delta.hasUnsyncronizableChanges && !experimentalWarningShown) + showSyncWarning(delta.unsyncronizableChangeLine, delta.unsyncronizableChangeColumn); + m_previousDoc = doc; if (!delta.newObjects.isEmpty()) m_createdObjects[doc] += delta.newObjects; @@ -491,6 +514,37 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) } } +void QmlJSLiveTextPreview::showExperimentalWarning() +{ + Core::EditorManager *em = Core::EditorManager::instance(); + em->showEditorInfoBar(Constants::INFO_EXPERIMENTAL, + tr("You changed a QML file in in Live Preview mode, and the changes were applied to the running QML application. " + "This feature is experimental, and behavior can be unexpected."), + tr("Disable Live Preview"), this, SLOT(disableLivePreview())); +} + +void QmlJSLiveTextPreview::showSyncWarning(unsigned line, unsigned column) +{ + Core::EditorManager *em = Core::EditorManager::instance(); + em->showEditorInfoBar(Constants::INFO_OUT_OF_SYNC, + tr("The change at line %1, column %2 cannot be applied without reloading the QML application. " + "You can continue debugging, but behavior can be unexpected."). + arg(QString::number(line), QString::number(column)), + tr("Reload"), this, SLOT(reloadQmlViewer())); +} + +void QmlJSLiveTextPreview::reloadQmlViewer() +{ + Core::EditorManager::instance()->hideEditorInfoBar(Constants::INFO_OUT_OF_SYNC); + emit reloadQmlViewerRequested(); +} + +void QmlJSLiveTextPreview::disableLivePreview() +{ + Core::EditorManager::instance()->hideEditorInfoBar(Constants::INFO_EXPERIMENTAL); + emit disableLivePreviewRequested(); +} + void QmlJSLiveTextPreview::setApplyChangesToQmlObserver(bool applyChanges) { if (applyChanges && !m_applyChangesToQmlObserver) { diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.h b/src/plugins/qmljsinspector/qmljslivetextpreview.h index 83faa2b04ea..6173e5c0150 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.h +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.h @@ -73,6 +73,8 @@ public: signals: void selectedItemsChanged(const QList<QDeclarativeDebugObjectReference> &objects); + void reloadQmlViewerRequested(); + void disableLivePreviewRequested(); public slots: void setApplyChangesToQmlObserver(bool applyChanges); @@ -81,11 +83,14 @@ public slots: private slots: void changeSelectedElements(QList<int> offsets, const QString &wordAtCursor); void documentChanged(QmlJS::Document::Ptr doc); - + void disableLivePreview(); + void reloadQmlViewer(); private: QList<int> objectReferencesForOffset(quint32 offset) const; QVariant castToLiteral(const QString &expression, QmlJS::AST::UiScriptBinding *scriptBinding); + void showSyncWarning(unsigned line, unsigned column); + void showExperimentalWarning(); private: QHash<QmlJS::AST::UiObjectMember*, QList<int> > m_debugIds; -- GitLab