Commit d8e3121a authored by Simjees Abraham's avatar Simjees Abraham Committed by Kai Koehne

Debugger:Apply Changes on Save modified for unsync. changes.

The user is given an option to reload the QML app if he has done
any unsynchronizable change. If the user opts to reload the QML,
Inspector informs the qtdevlarative to do so.

Change-Id: Iefc044e64380e64415630b051a60d6fe9fedfe04
Reviewed-by: default avatarKai Koehne <kai.koehne@nokia.com>
parent f1d3b432
...@@ -44,7 +44,7 @@ public: ...@@ -44,7 +44,7 @@ public:
BaseToolsClient(QmlDebugConnection *client, QLatin1String clientName); BaseToolsClient(QmlDebugConnection *client, QLatin1String clientName);
virtual void setCurrentObjects(const QList<int> &debugIds) = 0; virtual void setCurrentObjects(const QList<int> &debugIds) = 0;
virtual void reloadViewer() = 0; virtual void reload(const QHash<QString, QByteArray> &changesHash) = 0;
virtual void setDesignModeBehavior(bool inDesignMode) = 0; virtual void setDesignModeBehavior(bool inDesignMode) = 0;
virtual void setAnimationSpeed(qreal slowDownFactor) = 0; virtual void setAnimationSpeed(qreal slowDownFactor) = 0;
virtual void setAnimationPaused(bool paused) = 0; virtual void setAnimationPaused(bool paused) = 0;
...@@ -81,7 +81,7 @@ signals: ...@@ -81,7 +81,7 @@ signals:
void animationPausedChanged(bool paused); void animationPausedChanged(bool paused);
void designModeBehaviorChanged(bool inDesignMode); void designModeBehaviorChanged(bool inDesignMode);
void showAppOnTopChanged(bool showAppOnTop); void showAppOnTopChanged(bool showAppOnTop);
void reloaded(); // the server has reloadetd he document void reloaded(); // the server has reloaded the document
void logActivity(QString client, QString message); void logActivity(QString client, QString message);
......
...@@ -306,8 +306,11 @@ void DeclarativeToolsClient::clearComponentCache() ...@@ -306,8 +306,11 @@ void DeclarativeToolsClient::clearComponentCache()
sendMessage(message); sendMessage(message);
} }
void DeclarativeToolsClient::reloadViewer() void DeclarativeToolsClient::reload(const QHash<QString,
QByteArray> &changesHash)
{ {
Q_UNUSED(changesHash);
if (!m_connection || !m_connection->isConnected()) if (!m_connection || !m_connection->isConnected())
return; return;
......
...@@ -43,7 +43,7 @@ public: ...@@ -43,7 +43,7 @@ public:
DeclarativeToolsClient(QmlDebugConnection *client); DeclarativeToolsClient(QmlDebugConnection *client);
void setCurrentObjects(const QList<int> &debugIds); void setCurrentObjects(const QList<int> &debugIds);
void reloadViewer(); void reload(const QHash<QString, QByteArray> &changesHash);
void setDesignModeBehavior(bool inDesignMode); void setDesignModeBehavior(bool inDesignMode);
void setAnimationSpeed(qreal slowDownFactor); void setAnimationSpeed(qreal slowDownFactor);
void setAnimationPaused(bool paused); void setAnimationPaused(bool paused);
......
...@@ -66,7 +66,8 @@ QmlToolsClient::QmlToolsClient(QmlDebugConnection *client) ...@@ -66,7 +66,8 @@ QmlToolsClient::QmlToolsClient(QmlDebugConnection *client)
: BaseToolsClient(client, QLatin1String("QmlInspector")), : BaseToolsClient(client, QLatin1String("QmlInspector")),
m_connection(client), m_connection(client),
m_requestId(0), m_requestId(0),
m_slowDownFactor(1) m_slowDownFactor(1),
m_reloadQueryId(-1)
{ {
setObjectName(name()); setObjectName(name());
} }
...@@ -82,6 +83,10 @@ void QmlToolsClient::messageReceived(const QByteArray &message) ...@@ -82,6 +83,10 @@ void QmlToolsClient::messageReceived(const QByteArray &message)
if (type == QByteArray(RESPONSE)) { if (type == QByteArray(RESPONSE)) {
bool success = false; bool success = false;
ds >> success; ds >> success;
if ((m_reloadQueryId != -1) && (m_reloadQueryId == requestId) && success)
emit reloaded();
log(LogReceive, type, QString(QLatin1String("requestId: %1 success: %2")) log(LogReceive, type, QString(QLatin1String("requestId: %1 success: %2"))
.arg(QString::number(requestId)).arg(QString::number(success))); .arg(QString::number(requestId)).arg(QString::number(success)));
} else if (type == QByteArray(EVENT)) { } else if (type == QByteArray(EVENT)) {
...@@ -150,15 +155,17 @@ void QmlToolsClient::clearComponentCache() ...@@ -150,15 +155,17 @@ void QmlToolsClient::clearComponentCache()
sendMessage(message); sendMessage(message);
} }
void QmlToolsClient::reloadViewer() void QmlToolsClient::reload(const QHash<QString, QByteArray> &changesHash)
{ {
if (!m_connection || !m_connection->isConnected()) if (!m_connection || !m_connection->isConnected())
return; return;
m_reloadQueryId = m_requestId;
QByteArray message; QByteArray message;
QDataStream ds(&message, QIODevice::WriteOnly); QDataStream ds(&message, QIODevice::WriteOnly);
ds << QByteArray(REQUEST) << m_requestId++ ds << QByteArray(REQUEST) << m_requestId++
<< QByteArray(RELOAD); << QByteArray(RELOAD) << changesHash;
log(LogSend, RELOAD); log(LogSend, RELOAD);
......
...@@ -43,7 +43,7 @@ public: ...@@ -43,7 +43,7 @@ public:
explicit QmlToolsClient(QmlDebugConnection *client); explicit QmlToolsClient(QmlDebugConnection *client);
void setCurrentObjects(const QList<int> &debugIds); void setCurrentObjects(const QList<int> &debugIds);
void reloadViewer(); void reload(const QHash<QString, QByteArray> &changesHash);
void setDesignModeBehavior(bool inDesignMode); void setDesignModeBehavior(bool inDesignMode);
void setAnimationSpeed(qreal slowDownFactor); void setAnimationSpeed(qreal slowDownFactor);
void setAnimationPaused(bool paused); void setAnimationPaused(bool paused);
...@@ -81,6 +81,7 @@ private: ...@@ -81,6 +81,7 @@ private:
QmlDebugConnection *m_connection; QmlDebugConnection *m_connection;
int m_requestId; int m_requestId;
qreal m_slowDownFactor; qreal m_slowDownFactor;
int m_reloadQueryId;
}; };
} // namespace QmlDebug } // namespace QmlDebug
......
...@@ -202,6 +202,7 @@ void QmlInspectorAdapter::toolsClientStatusChanged(QmlDebug::ClientStatus status ...@@ -202,6 +202,7 @@ void QmlInspectorAdapter::toolsClientStatusChanged(QmlDebug::ClientStatus status
SLOT(selectObjectsFromToolsClient(QList<int>))); SLOT(selectObjectsFromToolsClient(QList<int>)));
connect(client, SIGNAL(logActivity(QString,QString)), connect(client, SIGNAL(logActivity(QString,QString)),
m_debugAdapter, SLOT(logServiceActivity(QString,QString))); m_debugAdapter, SLOT(logServiceActivity(QString,QString)));
connect(client, SIGNAL(reloaded()), SLOT(onReloaded()));
// only enable zoom action for Qt 4.x/old client // only enable zoom action for Qt 4.x/old client
// (zooming is integrated into selection tool in Qt 5). // (zooming is integrated into selection tool in Qt 5).
...@@ -340,14 +341,14 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor) ...@@ -340,14 +341,14 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor)
QmlJS::ModelManagerInterface::instance(); QmlJS::ModelManagerInterface::instance();
QmlJS::Document::Ptr doc = modelManager->snapshot().document(filename); QmlJS::Document::Ptr doc = modelManager->snapshot().document(filename);
if (!doc) { if (!doc) {
if (filename.endsWith(".qml")) { if (filename.endsWith(".qml") || filename.endsWith(".js")) {
// add to list of docs that we have to update when // add to list of docs that we have to update when
// snapshot figures out that there's a new document // snapshot figures out that there's a new document
m_pendingPreviewDocumentNames.append(filename); m_pendingPreviewDocumentNames.append(filename);
} }
return; return;
} }
if (!doc->qmlProgram()) if (!doc->qmlProgram() && !filename.endsWith(".js"))
return; return;
QmlJS::Document::Ptr initdoc = m_loadedSnapshot.document(filename); QmlJS::Document::Ptr initdoc = m_loadedSnapshot.document(filename);
...@@ -366,6 +367,8 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor) ...@@ -366,6 +367,8 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor)
preview->setApplyChangesToQmlInspector( preview->setApplyChangesToQmlInspector(
debuggerCore()->action(QmlUpdateOnSave)->isChecked()); debuggerCore()->action(QmlUpdateOnSave)->isChecked());
connect(preview, SIGNAL(reloadRequest()),
this, SLOT(onReload()));
m_textPreviews.insert(newEditor->document()->fileName(), preview); m_textPreviews.insert(newEditor->document()->fileName(), preview);
preview->associateEditor(newEditor); preview->associateEditor(newEditor);
...@@ -606,5 +609,39 @@ void QmlInspectorAdapter::selectObject(const ObjectReference &obj, ...@@ -606,5 +609,39 @@ void QmlInspectorAdapter::selectObject(const ObjectReference &obj,
emit selectionChanged(); emit selectionChanged();
} }
void QmlInspectorAdapter::onReload()
{
QHash<QString, QByteArray> changesHash;
for (QHash<QString, QmlLiveTextPreview *>::const_iterator it
= m_textPreviews.constBegin();
it != m_textPreviews.constEnd(); ++it) {
if (it.value()->hasUnsynchronizableChange()) {
QFileInfo info = QFileInfo(it.value()->fileName());
QFile changedFile(it.value()->fileName());
QByteArray fileContents;
if (changedFile.open(QFile::ReadOnly))
fileContents = changedFile.readAll();
changedFile.close();
changesHash.insert(info.fileName(),
fileContents);
}
}
m_toolsClient->reload(changesHash);
}
void QmlInspectorAdapter::onReloaded()
{
QmlJS::ModelManagerInterface *modelManager =
QmlJS::ModelManagerInterface::instance();
QmlJS::Snapshot snapshot = modelManager->snapshot();
m_loadedSnapshot = snapshot;
for (QHash<QString, QmlLiveTextPreview *>::const_iterator it
= m_textPreviews.constBegin();
it != m_textPreviews.constEnd(); ++it) {
QmlJS::Document::Ptr doc = snapshot.document(it.key());
it.value()->resetInitialDoc(doc);
}
}
} // namespace Internal } // namespace Internal
} // namespace Debugger } // namespace Debugger
...@@ -97,6 +97,8 @@ private slots: ...@@ -97,6 +97,8 @@ private slots:
void onZoomActionTriggered(bool checked); void onZoomActionTriggered(bool checked);
void onShowAppOnTopChanged(const QVariant &value); void onShowAppOnTopChanged(const QVariant &value);
void onUpdateOnSaveChanged(const QVariant &value); void onUpdateOnSaveChanged(const QVariant &value);
void onReload();
void onReloaded();
private: private:
void setActiveEngineClient(QmlDebug::BaseEngineDebugClient *client); void setActiveEngineClient(QmlDebug::BaseEngineDebugClient *client);
......
...@@ -50,6 +50,8 @@ using namespace QmlJS::AST; ...@@ -50,6 +50,8 @@ using namespace QmlJS::AST;
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
const char INFO_OUT_OF_SYNC[] = "Debugger.Inspector.OutOfSyncWarning";
/*! /*!
Associates the UiObjectMember* to their QDeclarativeDebugObjectReference. Associates the UiObjectMember* to their QDeclarativeDebugObjectReference.
*/ */
...@@ -351,6 +353,7 @@ QmlLiveTextPreview::QmlLiveTextPreview(const QmlJS::Document::Ptr &doc, ...@@ -351,6 +353,7 @@ QmlLiveTextPreview::QmlLiveTextPreview(const QmlJS::Document::Ptr &doc,
, m_inspectorAdapter(inspectorAdapter) , m_inspectorAdapter(inspectorAdapter)
, m_nodeForOffset(0) , m_nodeForOffset(0)
, m_updateNodeForOffset(false) , m_updateNodeForOffset(false)
, m_changesUnsynchronizable(false)
{ {
QTC_CHECK(doc->fileName() == initDoc->fileName()); QTC_CHECK(doc->fileName() == initDoc->fileName());
...@@ -413,6 +416,13 @@ void QmlLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc) ...@@ -413,6 +416,13 @@ void QmlLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc)
m_createdObjects.clear(); m_createdObjects.clear();
m_debugIds.clear(); m_debugIds.clear();
m_docWithUnappliedChanges.clear(); m_docWithUnappliedChanges.clear();
m_changesUnsynchronizable = false;
removeOutofSyncInfo();
}
const QString QmlLiveTextPreview::fileName()
{
return m_previousDoc->fileName();
} }
void QmlLiveTextPreview::setApplyChangesToQmlInspector(bool applyChanges) void QmlLiveTextPreview::setApplyChangesToQmlInspector(bool applyChanges)
...@@ -582,27 +592,36 @@ void QmlLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) ...@@ -582,27 +592,36 @@ void QmlLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
if (m_applyChangesToQmlInspector) { if (m_applyChangesToQmlInspector) {
m_docWithUnappliedChanges.clear(); m_docWithUnappliedChanges.clear();
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName() if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()) {
&& doc->qmlProgram() && m_previousDoc->qmlProgram()) if (doc->fileName().endsWith(".js")) {
{ m_changesUnsynchronizable = true;
UpdateInspector delta(m_inspectorAdapter); showSyncWarning(JSChangeWarning, QString(), -1, -1);
m_debugIds = delta(m_previousDoc, doc, m_debugIds); m_previousDoc = doc;
return;
if (delta.referenceRefreshRequired) }
m_inspectorAdapter->agent()->refreshObjectTree(); if (doc->qmlProgram() && m_previousDoc->qmlProgram()) {
UpdateInspector delta(m_inspectorAdapter);
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges)
showSyncWarning(delta.unsyncronizableChanges, if (delta.referenceRefreshRequired)
delta.unsyncronizableElementName, m_inspectorAdapter->agent()->refreshObjectTree();
delta.unsyncronizableChangeLine,
delta.unsyncronizableChangeColumn);
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges) {
m_previousDoc = doc; m_changesUnsynchronizable = true;
if (!delta.newObjects.isEmpty()) showSyncWarning(delta.unsyncronizableChanges,
m_createdObjects[doc] += delta.newObjects; delta.unsyncronizableElementName,
delta.unsyncronizableChangeLine,
delta.unsyncronizableChangeColumn);
m_previousDoc = doc;
return;
}
m_previousDoc = doc;
if (!delta.newObjects.isEmpty())
m_createdObjects[doc] += delta.newObjects;
m_inspectorAdapter->toolsClient()->clearComponentCache(); m_inspectorAdapter->toolsClient()->clearComponentCache();
}
} }
} else { } else {
m_docWithUnappliedChanges = doc; m_docWithUnappliedChanges = doc;
...@@ -655,6 +674,10 @@ void QmlLiveTextPreview::showSyncWarning( ...@@ -655,6 +674,10 @@ void QmlLiveTextPreview::showSyncWarning(
"changed without reloading the QML application. ") "changed without reloading the QML application. ")
.arg(elementName, QString::number(line), QString::number(column)); .arg(elementName, QString::number(line), QString::number(column));
break; break;
case JSChangeWarning:
errorMessage = tr("The changes in Java script cannot be applied "
"without reloading the QML application. ");
break;
case QmlLiveTextPreview::NoUnsyncronizableChanges: case QmlLiveTextPreview::NoUnsyncronizableChanges:
default: default:
return; return;
...@@ -662,12 +685,33 @@ void QmlLiveTextPreview::showSyncWarning( ...@@ -662,12 +685,33 @@ void QmlLiveTextPreview::showSyncWarning(
errorMessage.append(tr("You can continue debugging, but behavior can be unexpected.")); errorMessage.append(tr("You can continue debugging, but behavior can be unexpected."));
// Clear infobars if present before showing the same. Otherwise multiple infobars
// will be shown in case the user changes and saves the file multiple times.
removeOutofSyncInfo();
foreach (TextEditor::BaseTextEditorWidget *editor, m_editors) {
if (editor) {
Core::InfoBar *infoBar = editor->editorDocument()->infoBar();
Core::InfoBarEntry info(INFO_OUT_OF_SYNC, errorMessage);
info.setCustomButtonInfo(tr("Reload QML"), this,
SLOT(reloadQml()));
infoBar->addInfo(info);
}
}
}
void QmlLiveTextPreview::reloadQml()
{
removeOutofSyncInfo();
emit reloadRequest();
}
void QmlLiveTextPreview::removeOutofSyncInfo()
{
foreach (TextEditor::BaseTextEditorWidget *editor, m_editors) { foreach (TextEditor::BaseTextEditorWidget *editor, m_editors) {
if (editor) { if (editor) {
Core::InfoBar *infoBar = editor->editorDocument()->infoBar(); Core::InfoBar *infoBar = editor->editorDocument()->infoBar();
infoBar->addInfo(Core::InfoBarEntry( infoBar->removeInfo(INFO_OUT_OF_SYNC);
QLatin1String("Debugger.Inspector.OutOfSyncWarning"),
errorMessage));
} }
} }
} }
......
...@@ -65,15 +65,19 @@ public: ...@@ -65,15 +65,19 @@ public:
void associateEditor(Core::IEditor *editor); void associateEditor(Core::IEditor *editor);
void unassociateEditor(Core::IEditor *editor); void unassociateEditor(Core::IEditor *editor);
void resetInitialDoc(const QmlJS::Document::Ptr &doc); void resetInitialDoc(const QmlJS::Document::Ptr &doc);
const QString fileName();
bool hasUnsynchronizableChange() { return m_changesUnsynchronizable; }
signals: signals:
void selectedItemsChanged(const QList<int> &debugIds); void selectedItemsChanged(const QList<int> &debugIds);
void fetchObjectsForLocation(const QString &file, void fetchObjectsForLocation(const QString &file,
int lineNumber, int columnNumber); int lineNumber, int columnNumber);
void reloadRequest();
public slots: public slots:
void setApplyChangesToQmlInspector(bool applyChanges); void setApplyChangesToQmlInspector(bool applyChanges);
void updateDebugIds(); void updateDebugIds();
void reloadQml();
private slots: private slots:
void changeSelectedElements(const QList<QmlJS::AST::UiObjectMember *> offsets, void changeSelectedElements(const QList<QmlJS::AST::UiObjectMember *> offsets,
...@@ -84,7 +88,8 @@ private: ...@@ -84,7 +88,8 @@ private:
enum UnsyncronizableChangeType { enum UnsyncronizableChangeType {
NoUnsyncronizableChanges, NoUnsyncronizableChanges,
AttributeChangeWarning, AttributeChangeWarning,
ElementChangeWarning ElementChangeWarning,
JSChangeWarning
}; };
bool changeSelectedElements(const QList<int> offsets, const QString &wordAtCursor); bool changeSelectedElements(const QList<int> offsets, const QString &wordAtCursor);
...@@ -92,6 +97,7 @@ private: ...@@ -92,6 +97,7 @@ private:
void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType, void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType,
const QString &elementName, const QString &elementName,
unsigned line, unsigned column); unsigned line, unsigned column);
void removeOutofSyncInfo();
private: private:
QHash<QmlJS::AST::UiObjectMember*, QList<int> > m_debugIds; QHash<QmlJS::AST::UiObjectMember*, QList<int> > m_debugIds;
...@@ -108,6 +114,7 @@ private: ...@@ -108,6 +114,7 @@ private:
QList<int> m_lastOffsets; QList<int> m_lastOffsets;
QmlJS::AST::UiObjectMember *m_nodeForOffset; QmlJS::AST::UiObjectMember *m_nodeForOffset;
bool m_updateNodeForOffset; bool m_updateNodeForOffset;
bool m_changesUnsynchronizable;
friend class UpdateInspector; friend class UpdateInspector;
}; };
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment