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:
BaseToolsClient(QmlDebugConnection *client, QLatin1String clientName);
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 setAnimationSpeed(qreal slowDownFactor) = 0;
virtual void setAnimationPaused(bool paused) = 0;
......@@ -81,7 +81,7 @@ signals:
void animationPausedChanged(bool paused);
void designModeBehaviorChanged(bool inDesignMode);
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);
......
......@@ -306,8 +306,11 @@ void DeclarativeToolsClient::clearComponentCache()
sendMessage(message);
}
void DeclarativeToolsClient::reloadViewer()
void DeclarativeToolsClient::reload(const QHash<QString,
QByteArray> &changesHash)
{
Q_UNUSED(changesHash);
if (!m_connection || !m_connection->isConnected())
return;
......
......@@ -43,7 +43,7 @@ public:
DeclarativeToolsClient(QmlDebugConnection *client);
void setCurrentObjects(const QList<int> &debugIds);
void reloadViewer();
void reload(const QHash<QString, QByteArray> &changesHash);
void setDesignModeBehavior(bool inDesignMode);
void setAnimationSpeed(qreal slowDownFactor);
void setAnimationPaused(bool paused);
......
......@@ -66,7 +66,8 @@ QmlToolsClient::QmlToolsClient(QmlDebugConnection *client)
: BaseToolsClient(client, QLatin1String("QmlInspector")),
m_connection(client),
m_requestId(0),
m_slowDownFactor(1)
m_slowDownFactor(1),
m_reloadQueryId(-1)
{
setObjectName(name());
}
......@@ -82,6 +83,10 @@ void QmlToolsClient::messageReceived(const QByteArray &message)
if (type == QByteArray(RESPONSE)) {
bool success = false;
ds >> success;
if ((m_reloadQueryId != -1) && (m_reloadQueryId == requestId) && success)
emit reloaded();
log(LogReceive, type, QString(QLatin1String("requestId: %1 success: %2"))
.arg(QString::number(requestId)).arg(QString::number(success)));
} else if (type == QByteArray(EVENT)) {
......@@ -150,15 +155,17 @@ void QmlToolsClient::clearComponentCache()
sendMessage(message);
}
void QmlToolsClient::reloadViewer()
void QmlToolsClient::reload(const QHash<QString, QByteArray> &changesHash)
{
if (!m_connection || !m_connection->isConnected())
return;
m_reloadQueryId = m_requestId;
QByteArray message;
QDataStream ds(&message, QIODevice::WriteOnly);
ds << QByteArray(REQUEST) << m_requestId++
<< QByteArray(RELOAD);
<< QByteArray(RELOAD) << changesHash;
log(LogSend, RELOAD);
......
......@@ -43,7 +43,7 @@ public:
explicit QmlToolsClient(QmlDebugConnection *client);
void setCurrentObjects(const QList<int> &debugIds);
void reloadViewer();
void reload(const QHash<QString, QByteArray> &changesHash);
void setDesignModeBehavior(bool inDesignMode);
void setAnimationSpeed(qreal slowDownFactor);
void setAnimationPaused(bool paused);
......@@ -81,6 +81,7 @@ private:
QmlDebugConnection *m_connection;
int m_requestId;
qreal m_slowDownFactor;
int m_reloadQueryId;
};
} // namespace QmlDebug
......
......@@ -202,6 +202,7 @@ void QmlInspectorAdapter::toolsClientStatusChanged(QmlDebug::ClientStatus status
SLOT(selectObjectsFromToolsClient(QList<int>)));
connect(client, SIGNAL(logActivity(QString,QString)),
m_debugAdapter, SLOT(logServiceActivity(QString,QString)));
connect(client, SIGNAL(reloaded()), SLOT(onReloaded()));
// only enable zoom action for Qt 4.x/old client
// (zooming is integrated into selection tool in Qt 5).
......@@ -340,14 +341,14 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor)
QmlJS::ModelManagerInterface::instance();
QmlJS::Document::Ptr doc = modelManager->snapshot().document(filename);
if (!doc) {
if (filename.endsWith(".qml")) {
if (filename.endsWith(".qml") || filename.endsWith(".js")) {
// add to list of docs that we have to update when
// snapshot figures out that there's a new document
m_pendingPreviewDocumentNames.append(filename);
}
return;
}
if (!doc->qmlProgram())
if (!doc->qmlProgram() && !filename.endsWith(".js"))
return;
QmlJS::Document::Ptr initdoc = m_loadedSnapshot.document(filename);
......@@ -366,6 +367,8 @@ void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor)
preview->setApplyChangesToQmlInspector(
debuggerCore()->action(QmlUpdateOnSave)->isChecked());
connect(preview, SIGNAL(reloadRequest()),
this, SLOT(onReload()));
m_textPreviews.insert(newEditor->document()->fileName(), preview);
preview->associateEditor(newEditor);
......@@ -606,5 +609,39 @@ void QmlInspectorAdapter::selectObject(const ObjectReference &obj,
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 Debugger
......@@ -97,6 +97,8 @@ private slots:
void onZoomActionTriggered(bool checked);
void onShowAppOnTopChanged(const QVariant &value);
void onUpdateOnSaveChanged(const QVariant &value);
void onReload();
void onReloaded();
private:
void setActiveEngineClient(QmlDebug::BaseEngineDebugClient *client);
......
......@@ -50,6 +50,8 @@ using namespace QmlJS::AST;
namespace Debugger {
namespace Internal {
const char INFO_OUT_OF_SYNC[] = "Debugger.Inspector.OutOfSyncWarning";
/*!
Associates the UiObjectMember* to their QDeclarativeDebugObjectReference.
*/
......@@ -351,6 +353,7 @@ QmlLiveTextPreview::QmlLiveTextPreview(const QmlJS::Document::Ptr &doc,
, m_inspectorAdapter(inspectorAdapter)
, m_nodeForOffset(0)
, m_updateNodeForOffset(false)
, m_changesUnsynchronizable(false)
{
QTC_CHECK(doc->fileName() == initDoc->fileName());
......@@ -413,6 +416,13 @@ void QmlLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc)
m_createdObjects.clear();
m_debugIds.clear();
m_docWithUnappliedChanges.clear();
m_changesUnsynchronizable = false;
removeOutofSyncInfo();
}
const QString QmlLiveTextPreview::fileName()
{
return m_previousDoc->fileName();
}
void QmlLiveTextPreview::setApplyChangesToQmlInspector(bool applyChanges)
......@@ -582,27 +592,36 @@ void QmlLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
if (m_applyChangesToQmlInspector) {
m_docWithUnappliedChanges.clear();
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
&& doc->qmlProgram() && m_previousDoc->qmlProgram())
{
UpdateInspector delta(m_inspectorAdapter);
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
if (delta.referenceRefreshRequired)
m_inspectorAdapter->agent()->refreshObjectTree();
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges)
showSyncWarning(delta.unsyncronizableChanges,
delta.unsyncronizableElementName,
delta.unsyncronizableChangeLine,
delta.unsyncronizableChangeColumn);
m_previousDoc = doc;
if (!delta.newObjects.isEmpty())
m_createdObjects[doc] += delta.newObjects;
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()) {
if (doc->fileName().endsWith(".js")) {
m_changesUnsynchronizable = true;
showSyncWarning(JSChangeWarning, QString(), -1, -1);
m_previousDoc = doc;
return;
}
if (doc->qmlProgram() && m_previousDoc->qmlProgram()) {
UpdateInspector delta(m_inspectorAdapter);
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
if (delta.referenceRefreshRequired)
m_inspectorAdapter->agent()->refreshObjectTree();
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges) {
m_changesUnsynchronizable = true;
showSyncWarning(delta.unsyncronizableChanges,
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 {
m_docWithUnappliedChanges = doc;
......@@ -655,6 +674,10 @@ void QmlLiveTextPreview::showSyncWarning(
"changed without reloading the QML application. ")
.arg(elementName, QString::number(line), QString::number(column));
break;
case JSChangeWarning:
errorMessage = tr("The changes in Java script cannot be applied "
"without reloading the QML application. ");
break;
case QmlLiveTextPreview::NoUnsyncronizableChanges:
default:
return;
......@@ -662,12 +685,33 @@ void QmlLiveTextPreview::showSyncWarning(
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) {
if (editor) {
Core::InfoBar *infoBar = editor->editorDocument()->infoBar();
infoBar->addInfo(Core::InfoBarEntry(
QLatin1String("Debugger.Inspector.OutOfSyncWarning"),
errorMessage));
infoBar->removeInfo(INFO_OUT_OF_SYNC);
}
}
}
......
......@@ -65,15 +65,19 @@ public:
void associateEditor(Core::IEditor *editor);
void unassociateEditor(Core::IEditor *editor);
void resetInitialDoc(const QmlJS::Document::Ptr &doc);
const QString fileName();
bool hasUnsynchronizableChange() { return m_changesUnsynchronizable; }
signals:
void selectedItemsChanged(const QList<int> &debugIds);
void fetchObjectsForLocation(const QString &file,
int lineNumber, int columnNumber);
void reloadRequest();
public slots:
void setApplyChangesToQmlInspector(bool applyChanges);
void updateDebugIds();
void reloadQml();
private slots:
void changeSelectedElements(const QList<QmlJS::AST::UiObjectMember *> offsets,
......@@ -84,7 +88,8 @@ private:
enum UnsyncronizableChangeType {
NoUnsyncronizableChanges,
AttributeChangeWarning,
ElementChangeWarning
ElementChangeWarning,
JSChangeWarning
};
bool changeSelectedElements(const QList<int> offsets, const QString &wordAtCursor);
......@@ -92,6 +97,7 @@ private:
void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType,
const QString &elementName,
unsigned line, unsigned column);
void removeOutofSyncInfo();
private:
QHash<QmlJS::AST::UiObjectMember*, QList<int> > m_debugIds;
......@@ -108,6 +114,7 @@ private:
QList<int> m_lastOffsets;
QmlJS::AST::UiObjectMember *m_nodeForOffset;
bool m_updateNodeForOffset;
bool m_changesUnsynchronizable;
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