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: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
Simjees Abraham
2012-05-11 16:25:53 +02:00
committed by Kai Koehne
parent f1d3b432d5
commit d8e3121a64
9 changed files with 132 additions and 31 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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,9 +592,14 @@ 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())
{
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);
@@ -592,18 +607,22 @@ void QmlLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
m_inspectorAdapter->agent()->refreshObjectTree();
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges)
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();
}
}
} 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();
infoBar->addInfo(Core::InfoBarEntry(
QLatin1String("Debugger.Inspector.OutOfSyncWarning"),
errorMessage));
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->removeInfo(INFO_OUT_OF_SYNC);
}
}
}

View File

@@ -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;
};