forked from qt-creator/qt-creator
QML JS Inspector: Improve warning messages
When a change is done to an element that cannot be changed due to debugger/qdeclarative limitations, a warning is shown to the user in QML JS Editor. Reviewed-by: Olivier Goffart
This commit is contained in:
@@ -382,7 +382,7 @@ void Delta::update(UiObjectDefinition* oldObject, const QmlJS::Document::Ptr& ol
|
|||||||
if (!previousScript || _scriptCode(previousScript, oldDoc) != scriptCode) {
|
if (!previousScript || _scriptCode(previousScript, oldDoc) != scriptCode) {
|
||||||
foreach (DebugId ref, debugReferences) {
|
foreach (DebugId ref, debugReferences) {
|
||||||
if (ref != -1)
|
if (ref != -1)
|
||||||
updateScriptBinding(ref, script, property, scriptCode);
|
updateScriptBinding(ref, newObject, script, property, scriptCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (UiSourceElement *uiSource = cast<UiSourceElement*>(*it)) {
|
} else if (UiSourceElement *uiSource = cast<UiSourceElement*>(*it)) {
|
||||||
@@ -393,7 +393,7 @@ void Delta::update(UiObjectDefinition* oldObject, const QmlJS::Document::Ptr& ol
|
|||||||
if (!previousSource || _methodCode(previousSource, oldDoc) != methodCode) {
|
if (!previousSource || _methodCode(previousSource, oldDoc) != methodCode) {
|
||||||
foreach (DebugId ref, debugReferences) {
|
foreach (DebugId ref, debugReferences) {
|
||||||
if (ref != -1)
|
if (ref != -1)
|
||||||
updateMethodBody(ref, script, methodName, methodCode);
|
updateMethodBody(ref, newObject, script, methodName, methodCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,10 +506,10 @@ void Delta::removeObject(int)
|
|||||||
{}
|
{}
|
||||||
void Delta::resetBindingForObject(int, const QString &)
|
void Delta::resetBindingForObject(int, const QString &)
|
||||||
{}
|
{}
|
||||||
void Delta::updateMethodBody(DebugId, UiScriptBinding *, const QString &, const QString &)
|
void Delta::updateMethodBody(DebugId, UiObjectDefinition *, UiScriptBinding *, const QString &, const QString &)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void Delta::updateScriptBinding(DebugId, UiScriptBinding *, const QString &, const QString &)
|
void Delta::updateScriptBinding(DebugId, UiObjectDefinition *, UiScriptBinding *, const QString &, const QString &)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
} //namespace QmlJs
|
} //namespace QmlJs
|
||||||
|
|||||||
@@ -57,10 +57,12 @@ private:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void updateScriptBinding(DebugId objectReference,
|
virtual void updateScriptBinding(DebugId objectReference,
|
||||||
|
AST::UiObjectDefinition *parentObject,
|
||||||
AST::UiScriptBinding *scriptBinding,
|
AST::UiScriptBinding *scriptBinding,
|
||||||
const QString &propertyName,
|
const QString &propertyName,
|
||||||
const QString &scriptCode);
|
const QString &scriptCode);
|
||||||
virtual void updateMethodBody(DebugId objectReference,
|
virtual void updateMethodBody(DebugId objectReference,
|
||||||
|
AST::UiObjectDefinition *parentObject,
|
||||||
AST::UiScriptBinding *scriptBinding,
|
AST::UiScriptBinding *scriptBinding,
|
||||||
const QString &methodName,
|
const QString &methodName,
|
||||||
const QString &methodBody);
|
const QString &methodBody);
|
||||||
|
|||||||
@@ -422,50 +422,100 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void updateMethodBody(DebugId debugId, UiScriptBinding* scriptBinding,
|
virtual void updateMethodBody(DebugId debugId,
|
||||||
|
UiObjectDefinition *parentDefinition, UiScriptBinding* scriptBinding,
|
||||||
const QString& methodName, const QString& methodBody)
|
const QString& methodName, const QString& methodBody)
|
||||||
{
|
{
|
||||||
Q_UNUSED(scriptBinding);
|
Q_UNUSED(scriptBinding);
|
||||||
|
checkUnsyncronizableElementChanges(parentDefinition);
|
||||||
|
appliedChangesToViewer = true;
|
||||||
ClientProxy::instance()->setMethodBodyForObject(debugId, methodName, methodBody);
|
ClientProxy::instance()->setMethodBodyForObject(debugId, methodName, methodBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateScriptBinding(DebugId debugId, UiScriptBinding* scriptBinding,
|
virtual void updateScriptBinding(DebugId debugId,
|
||||||
|
UiObjectDefinition *parentDefinition, UiScriptBinding* scriptBinding,
|
||||||
const QString& propertyName, const QString& scriptCode)
|
const QString& propertyName, const QString& scriptCode)
|
||||||
{
|
{
|
||||||
if (propertyName == QLatin1String("id") && !hasUnsyncronizableChanges) {
|
if (unsyncronizableChanges == QmlJSLiveTextPreview::NoUnsyncronizableChanges) {
|
||||||
hasUnsyncronizableChanges = true;
|
if (propertyName == QLatin1String("id")) {
|
||||||
unsyncronizableChangeLine = scriptBinding->firstSourceLocation().startLine;
|
unsyncronizableElementName = propertyName;
|
||||||
unsyncronizableChangeColumn = scriptBinding->firstSourceLocation().startColumn;
|
unsyncronizableChanges = QmlJSLiveTextPreview::AttributeChangeWarning;
|
||||||
|
unsyncronizableChangeLine = parentDefinition->firstSourceLocation().startLine;
|
||||||
|
unsyncronizableChangeColumn = parentDefinition->firstSourceLocation().startColumn;
|
||||||
|
}
|
||||||
|
checkUnsyncronizableElementChanges(parentDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant expr = scriptCode;
|
QVariant expr = scriptCode;
|
||||||
const bool isLiteral = isLiteralValue(scriptBinding);
|
const bool isLiteral = isLiteralValue(scriptBinding);
|
||||||
if (isLiteral)
|
if (isLiteral)
|
||||||
expr = castToLiteral(scriptCode, scriptBinding);
|
expr = castToLiteral(scriptCode, scriptBinding);
|
||||||
|
appliedChangesToViewer = true;
|
||||||
ClientProxy::instance()->setBindingForObject(debugId, propertyName, expr, isLiteral);
|
ClientProxy::instance()->setBindingForObject(debugId, propertyName, expr, isLiteral);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void resetBindingForObject(int debugId, const QString &propertyName)
|
virtual void resetBindingForObject(int debugId, const QString &propertyName)
|
||||||
{
|
{
|
||||||
|
appliedChangesToViewer = true;
|
||||||
ClientProxy::instance()->resetBindingForObject(debugId, propertyName);
|
ClientProxy::instance()->resetBindingForObject(debugId, propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void removeObject(int debugId)
|
virtual void removeObject(int debugId)
|
||||||
{
|
{
|
||||||
|
appliedChangesToViewer = true;
|
||||||
ClientProxy::instance()->destroyQmlObject(debugId);
|
ClientProxy::instance()->destroyQmlObject(debugId);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void createObject(const QString& qmlText, DebugId ref,
|
virtual void createObject(const QString& qmlText, DebugId ref,
|
||||||
const QStringList& importList, const QString& filename)
|
const QStringList& importList, const QString& filename)
|
||||||
{
|
{
|
||||||
|
appliedChangesToViewer = true;
|
||||||
referenceRefreshRequired = true;
|
referenceRefreshRequired = true;
|
||||||
ClientProxy::instance()->createQmlObject(qmlText, ref, importList, filename);
|
ClientProxy::instance()->createQmlObject(qmlText, ref, importList, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkUnsyncronizableElementChanges(UiObjectDefinition *parentDefinition)
|
||||||
|
{
|
||||||
|
if (unsyncronizableChanges == QmlJSLiveTextPreview::NoUnsyncronizableChanges) {
|
||||||
|
|
||||||
|
if (parentDefinition->qualifiedTypeNameId
|
||||||
|
&& parentDefinition->qualifiedTypeNameId->name)
|
||||||
|
{
|
||||||
|
QString elementName = parentDefinition->qualifiedTypeNameId->name->asString();
|
||||||
|
if (elementName == QLatin1String("PropertyChanges")
|
||||||
|
// State element can be changed, but not its contents like PropertyChanges.
|
||||||
|
|| elementName == QLatin1String("StateGroup")
|
||||||
|
|| elementName == QLatin1String("StateChangeScript")
|
||||||
|
|| elementName == QLatin1String("ParentChange")
|
||||||
|
|| elementName == QLatin1String("AnchorChanges")
|
||||||
|
|| elementName == QLatin1String("Connections")
|
||||||
|
|| elementName == QLatin1String("Binding")
|
||||||
|
|| elementName == QLatin1String("ListModel")
|
||||||
|
|| elementName == QLatin1String("ListElement")
|
||||||
|
|| elementName == QLatin1String("VisualItemModel")
|
||||||
|
|| elementName == QLatin1String("VisualDataModel")
|
||||||
|
|| elementName == QLatin1String("Package")
|
||||||
|
// XmlListModel properties *can* be edited but XmlRole doesn't refresh the model when changed
|
||||||
|
|| elementName == QLatin1String("XmlRole"))
|
||||||
|
{
|
||||||
|
unsyncronizableElementName = elementName;
|
||||||
|
unsyncronizableChanges = QmlJSLiveTextPreview::ElementChangeWarning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unsyncronizableChanges != QmlJSLiveTextPreview::NoUnsyncronizableChanges) {
|
||||||
|
unsyncronizableChangeLine = parentDefinition->firstSourceLocation().startLine;
|
||||||
|
unsyncronizableChangeColumn = parentDefinition->firstSourceLocation().startColumn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UpdateObserver() : referenceRefreshRequired(false), hasUnsyncronizableChanges(false) {}
|
UpdateObserver() : appliedChangesToViewer(false), referenceRefreshRequired(false), unsyncronizableChanges(QmlJSLiveTextPreview::NoUnsyncronizableChanges) {}
|
||||||
|
bool appliedChangesToViewer;
|
||||||
bool referenceRefreshRequired;
|
bool referenceRefreshRequired;
|
||||||
bool hasUnsyncronizableChanges;
|
QString unsyncronizableElementName;
|
||||||
|
QmlJSLiveTextPreview::UnsyncronizableChangeType unsyncronizableChanges;
|
||||||
unsigned unsyncronizableChangeLine;
|
unsigned unsyncronizableChangeLine;
|
||||||
unsigned unsyncronizableChangeColumn;
|
unsigned unsyncronizableChangeColumn;
|
||||||
|
|
||||||
@@ -487,12 +537,6 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
|||||||
if (m_applyChangesToQmlObserver) {
|
if (m_applyChangesToQmlObserver) {
|
||||||
m_docWithUnappliedChanges.clear();
|
m_docWithUnappliedChanges.clear();
|
||||||
|
|
||||||
if (Inspector::showExperimentalWarning()) {
|
|
||||||
showExperimentalWarning();
|
|
||||||
experimentalWarningShown = true;
|
|
||||||
Inspector::setShowExperimentalWarning(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
|
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
|
||||||
&& doc->qmlProgram() && m_previousDoc->qmlProgram())
|
&& doc->qmlProgram() && m_previousDoc->qmlProgram())
|
||||||
{
|
{
|
||||||
@@ -502,8 +546,15 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
|||||||
if (delta.referenceRefreshRequired)
|
if (delta.referenceRefreshRequired)
|
||||||
ClientProxy::instance()->refreshObjectTree();
|
ClientProxy::instance()->refreshObjectTree();
|
||||||
|
|
||||||
if (delta.hasUnsyncronizableChanges && !experimentalWarningShown)
|
if (Inspector::showExperimentalWarning() && delta.appliedChangesToViewer) {
|
||||||
showSyncWarning(delta.unsyncronizableChangeLine, delta.unsyncronizableChangeColumn);
|
showExperimentalWarning();
|
||||||
|
experimentalWarningShown = true;
|
||||||
|
Inspector::setShowExperimentalWarning(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges && !experimentalWarningShown)
|
||||||
|
showSyncWarning(delta.unsyncronizableChanges, delta.unsyncronizableElementName,
|
||||||
|
delta.unsyncronizableChangeLine, delta.unsyncronizableChangeColumn);
|
||||||
|
|
||||||
m_previousDoc = doc;
|
m_previousDoc = doc;
|
||||||
if (!delta.newObjects.isEmpty())
|
if (!delta.newObjects.isEmpty())
|
||||||
@@ -526,14 +577,29 @@ void QmlJSLiveTextPreview::showExperimentalWarning()
|
|||||||
tr("Disable Live Preview"), this, SLOT(disableLivePreview()));
|
tr("Disable Live Preview"), this, SLOT(disableLivePreview()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlJSLiveTextPreview::showSyncWarning(unsigned line, unsigned column)
|
void QmlJSLiveTextPreview::showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType,
|
||||||
|
const QString &elementName, unsigned line, unsigned column)
|
||||||
{
|
{
|
||||||
Core::EditorManager *em = Core::EditorManager::instance();
|
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. "
|
QString errorMessage;
|
||||||
"You can continue debugging, but behavior can be unexpected.").
|
switch (unsyncronizableChangeType) {
|
||||||
arg(QString::number(line), QString::number(column)),
|
case AttributeChangeWarning:
|
||||||
tr("Reload"), this, SLOT(reloadQmlViewer()));
|
errorMessage = tr("The %1 attribute at line %2, column %3 cannot be changed without reloading the QML application. ")
|
||||||
|
.arg(elementName, QString::number(line), QString::number(column));
|
||||||
|
break;
|
||||||
|
case ElementChangeWarning:
|
||||||
|
errorMessage = tr("The %1 element at line %2, column %3 cannot be changed without reloading the QML application. ")
|
||||||
|
.arg(elementName, QString::number(line), QString::number(column));
|
||||||
|
break;
|
||||||
|
case QmlJSLiveTextPreview::NoUnsyncronizableChanges:
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMessage.append(tr("You can continue debugging, but behavior can be unexpected."));
|
||||||
|
|
||||||
|
em->showEditorInfoBar(Constants::INFO_OUT_OF_SYNC, errorMessage, tr("Reload"), this, SLOT(reloadQmlViewer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlJSLiveTextPreview::reloadQmlViewer()
|
void QmlJSLiveTextPreview::reloadQmlViewer()
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ class QmlJSLiveTextPreview : public QObject
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc, const QmlJS::Document::Ptr &initDoc, QObject *parent = 0);
|
explicit QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc, const QmlJS::Document::Ptr &initDoc, QObject *parent = 0);
|
||||||
static QmlJS::ModelManagerInterface *modelManager();
|
|
||||||
//void updateDocuments();
|
//void updateDocuments();
|
||||||
|
|
||||||
void associateEditor(Core::IEditor *editor);
|
void associateEditor(Core::IEditor *editor);
|
||||||
@@ -71,6 +70,12 @@ public:
|
|||||||
void mapObjectToQml(const QDeclarativeDebugObjectReference &object);
|
void mapObjectToQml(const QDeclarativeDebugObjectReference &object);
|
||||||
void resetInitialDoc(const QmlJS::Document::Ptr &doc);
|
void resetInitialDoc(const QmlJS::Document::Ptr &doc);
|
||||||
|
|
||||||
|
enum UnsyncronizableChangeType {
|
||||||
|
NoUnsyncronizableChanges,
|
||||||
|
AttributeChangeWarning,
|
||||||
|
ElementChangeWarning
|
||||||
|
};
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void selectedItemsChanged(const QList<QDeclarativeDebugObjectReference> &objects);
|
void selectedItemsChanged(const QList<QDeclarativeDebugObjectReference> &objects);
|
||||||
void reloadQmlViewerRequested();
|
void reloadQmlViewerRequested();
|
||||||
@@ -87,9 +92,11 @@ private slots:
|
|||||||
void reloadQmlViewer();
|
void reloadQmlViewer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static QmlJS::ModelManagerInterface *modelManager();
|
||||||
QList<int> objectReferencesForOffset(quint32 offset) const;
|
QList<int> objectReferencesForOffset(quint32 offset) const;
|
||||||
QVariant castToLiteral(const QString &expression, QmlJS::AST::UiScriptBinding *scriptBinding);
|
QVariant castToLiteral(const QString &expression, QmlJS::AST::UiScriptBinding *scriptBinding);
|
||||||
void showSyncWarning(unsigned line, unsigned column);
|
void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType, const QString &elementName,
|
||||||
|
unsigned line, unsigned column);
|
||||||
void showExperimentalWarning();
|
void showExperimentalWarning();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user