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);
}
}
+void QmlInspectorToolbar::setLivePreviewChecked(bool value)
+{
+ m_fromQmlAction->setChecked(value);
+}
+
void QmlInspectorToolbar::setSelectedColor(const QColor &color)
{
m_colorBox->setColor(color);
void setDesignModeBehavior(bool inDesignMode);
void setSelectedColor(const QColor &color);
+ void setLivePreviewChecked(bool value);
+
signals:
void animationSpeedChanged(qreal slowdownFactor = 1.0f);
ConnectionAttemptSimultaneousInterval = 500
};
+bool Inspector::m_showExperimentalWarning = true;
+
Inspector::Inspector(QObject *parent)
: QObject(parent),
m_connectionTimer(new QTimer(this)),
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());
void Inspector::setApplyChangesToQmlObserver(bool applyChanges)
{
+ emit livePreviewActivated(applyChanges);
QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews);
while(iter.hasNext()) {
iter.next();
}
}
+bool Inspector::showExperimentalWarning()
+{
+ return m_showExperimentalWarning;
+}
+
+void Inspector::setShowExperimentalWarning(bool value)
+{
+ m_showExperimentalWarning = value;
+}
+
+void Inspector::disableLivePreview()
+{
+ setApplyChangesToQmlObserver(false);
+}
Inspector(QObject *parent = 0);
virtual ~Inspector();
+
bool connectToViewer(); // using host, port from widgets
void shutdown();
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();
void removePreviewForEditor(Core::IEditor *newEditor);
void createPreviewForEditor(Core::IEditor *newEditor);
+ void disableLivePreview();
+
private:
Debugger::DebuggerRunControl *createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
const QString &executableFile = QString(),
bool addQuotesForData(const QVariant &value) const;
void resetViews();
+
QmlJS::ModelManagerInterface *modelManager();
void initializeDocuments();
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
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";
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()));
#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>
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)
}
public:
- UpdateObserver() : referenceRefreshRequired(false) {}
+ UpdateObserver() : referenceRefreshRequired(false), hasUnsyncronizableChanges(false) {}
bool referenceRefreshRequired;
+ bool hasUnsyncronizableChanges;
+ unsigned unsyncronizableChangeLine;
+ unsigned unsyncronizableChangeColumn;
+
};
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())
{
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;
}
}
+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) {
signals:
void selectedItemsChanged(const QList<QDeclarativeDebugObjectReference> &objects);
+ void reloadQmlViewerRequested();
+ void disableLivePreviewRequested();
public slots:
void setApplyChangesToQmlObserver(bool applyChanges);
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;