OSDN Git Service

Qml JS Live Preview: Show warnings when running Live Preview
authorLasse Holmstedt <lasse.holmstedt@nokia.com>
Fri, 30 Jul 2010 13:28:05 +0000 (15:28 +0200)
committerLasse Holmstedt <lasse.holmstedt@nokia.com>
Fri, 30 Jul 2010 13:28:19 +0000 (15:28 +0200)
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.

src/plugins/qmljsinspector/qmlinspectortoolbar.cpp
src/plugins/qmljsinspector/qmlinspectortoolbar.h
src/plugins/qmljsinspector/qmljsinspector.cpp
src/plugins/qmljsinspector/qmljsinspector.h
src/plugins/qmljsinspector/qmljsinspectorconstants.h
src/plugins/qmljsinspector/qmljsinspectorplugin.cpp
src/plugins/qmljsinspector/qmljslivetextpreview.cpp
src/plugins/qmljsinspector/qmljslivetextpreview.h

index 0b7870e..98d4dd3 100644 (file)
@@ -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);
index efed26f..21d3c9d 100644 (file)
@@ -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);
 
index eb47777..0201dea 100644 (file)
@@ -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);
+}
index 81dc606..fb83678 100644 (file)
@@ -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
index 5915d1b..b8ffb79 100644 (file)
@@ -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";
index f69fb16..8a5a0dc 100644 (file)
@@ -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()));
index 2793d9e..4c17072 100644 (file)
 
 #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) {
index 83faa2b..6173e5c 100644 (file)
@@ -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;