Commit e0aa4f86 authored by Lasse Holmstedt's avatar Lasse Holmstedt
Browse files

changing QmlJsLivePreview to work with multiple documents

parent d875953d
......@@ -113,6 +113,21 @@ bool ClientProxy::connectToViewer(const QString &host, quint16 port)
return true;
}
void ClientProxy::refreshObjectTree()
{
if (!m_objectTreeQuery) {
m_objectTreeQuery = m_client->queryObjectRecursive(m_rootObject, this);
if (!m_objectTreeQuery->isWaiting()) {
objectTreeFetched();
} else {
connect(m_objectTreeQuery,
SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
SLOT(objectTreeFetched(QDeclarativeDebugQuery::State)));
}
}
}
void ClientProxy::onCurrentObjectsChanged(const QList<int> &debugIds)
{
QList<QDeclarativeDebugObjectReference> selectedItems;
......@@ -126,10 +141,8 @@ void ClientProxy::onCurrentObjectsChanged(const QList<int> &debugIds)
// a) get some item and know its parent (although that's possible by adding it to a separate plugin)
// b) add children to part of an existing tree.
// So the only choice that remains is to update the complete tree when we have an unknown debug id.
if (!m_objectTreeQuery) {
if (!m_objectTreeQuery)
m_objectTreeQuery = m_client->queryObjectRecursive(m_rootObject, this);
}
}
}
......
......@@ -62,6 +62,7 @@ public:
// returns the object references for the given url.
QList<QDeclarativeDebugObjectReference> objectReferences(const QUrl &url = QUrl()) const;
QDeclarativeDebugObjectReference objectReferenceForId(int debugId) const;
void refreshObjectTree();
bool isConnected() const;
bool isUnconnected() const;
......
......@@ -300,6 +300,7 @@ void Delta::insert(UiObjectMember *member, UiObjectMember *parentMember, const Q
foreach(const QDeclarativeDebugObjectReference &ref, debugReferences) {
if (ref.debugId() != -1) {
_referenceRefreshRequired = true;
ClientProxy::instance()->createQmlObject(qmlText, ref, importList, doc->fileName());
}
}
......@@ -395,6 +396,7 @@ Delta::DebugIdMap Delta::operator()(const Document::Ptr &doc1, const Document::P
QHash< UiObjectMember*, QList<QDeclarativeDebugObjectReference > > newDebuggIds;
Map M = Mapping(doc1, doc2);
_referenceRefreshRequired = false;
BuildParentHash parents2;
doc2->qmlProgram()->accept(&parents2);
......@@ -635,3 +637,8 @@ QList<Delta::Change> Delta::changes() const
{
return _changes;
}
bool Delta::referenceRefreshRequired() const
{
return _referenceRefreshRequired;
}
......@@ -64,6 +64,14 @@ public:
QmlJS::Document::Ptr previousDocument() const;
public:
bool referenceRefreshRequired() const;
static bool compare(UiSourceElement *source, UiSourceElement *other);
static bool compare(QmlJS::AST::UiQualifiedId *id, QmlJS::AST::UiQualifiedId *other);
static QmlJS::AST::UiObjectMemberList *objectMembers(QmlJS::AST::UiObjectMember *object);
private:
void insert(UiObjectMember *member, UiObjectMember *parentMember,
const QList<QDeclarativeDebugObjectReference> &debugReferences, const Document::Ptr &doc);
void updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference,
QmlJS::AST::UiScriptBinding *scriptBinding,
const QString &propertyName,
......@@ -73,14 +81,6 @@ public:
const QString &methodName,
const QString &methodBody);
static bool compare(UiSourceElement *source, UiSourceElement *other);
static bool compare(QmlJS::AST::UiQualifiedId *id, QmlJS::AST::UiQualifiedId *other);
static QmlJS::AST::UiObjectMemberList *objectMembers(QmlJS::AST::UiObjectMember *object);
private:
void insert(UiObjectMember *member, UiObjectMember *parentMember,
const QList<QDeclarativeDebugObjectReference> &debugReferences, const Document::Ptr &doc);
void update(UiObjectDefinition* oldObject, const QmlJS::Document::Ptr& oldDoc,
UiObjectDefinition* newObject, const QmlJS::Document::Ptr& newDoc,
const QList<QDeclarativeDebugObjectReference >& debugReferences);
......@@ -90,6 +90,7 @@ private:
QmlJS::Document::Ptr _previousDoc;
QList<Change> _changes;
QUrl _url;
bool _referenceRefreshRequired;
};
} // namespace Internal
......
......@@ -34,6 +34,8 @@
#include "qmljslivetextpreview.h"
#include "qmljsprivateapi.h"
#include <qmljseditor/qmljseditorconstants.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/qmljsdocument.h>
......@@ -128,12 +130,6 @@ Inspector::Inspector(QObject *parent)
QWidget *contextWidget = 0;
m_context = new InspectorContext(contextWidget);
m_textPreview = new QmlJSLiveTextPreview(this);
connect(m_textPreview,
SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
SLOT(changeSelectedItems(QList<QDeclarativeDebugObjectReference>)));
connect(m_clientProxy, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
SLOT(setSelectedItemsByObjectReference(QList<QDeclarativeDebugObjectReference>)));
......@@ -161,6 +157,9 @@ void Inspector::disconnectWidgets()
void Inspector::disconnected()
{
Core::EditorManager *em = Core::EditorManager::instance();
disconnect(em, SIGNAL(editorAboutToClose(Core::IEditor*)), this, SLOT(removePreviewForEditor(Core::IEditor*)));
disconnect(em, SIGNAL(editorOpened(Core::IEditor*)), this, SLOT(createPreviewForEditor(Core::IEditor*)));
resetViews();
updateMenuActions();
}
......@@ -201,7 +200,7 @@ void Inspector::pollInspector()
const quint16 port = quint16(m_runConfigurationDebugData.serverPort);
if (m_clientProxy->connectToViewer(host, port)) {
m_textPreview->updateDocuments();
initializeDocuments();
m_connectionTimer->stop();
m_connectionAttempts = 0;
} else if (m_connectionAttempts == MaxConnectionAttempts) {
......@@ -215,6 +214,57 @@ void Inspector::pollInspector()
updateMenuActions();
}
QmlJS::ModelManagerInterface *Inspector::modelManager()
{
return ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
}
void Inspector::initializeDocuments()
{
if (!modelManager())
return;
QmlJS::Snapshot snapshot = modelManager()->snapshot();
Core::EditorManager *em = Core::EditorManager::instance();
connect(em, SIGNAL(editorAboutToClose(Core::IEditor*)), SLOT(removePreviewForEditor(Core::IEditor*)));
connect(em, SIGNAL(editorOpened(Core::IEditor*)), SLOT(createPreviewForEditor(Core::IEditor*)));
// initial update
foreach (QmlJS::Document::Ptr doc, snapshot) {
QmlJSLiveTextPreview *preview = new QmlJSLiveTextPreview(doc, this);
connect(preview,
SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
SLOT(changeSelectedItems(QList<QDeclarativeDebugObjectReference>)));
m_textPreviews.insert(doc->fileName(), preview);
}
}
void Inspector::removePreviewForEditor(Core::IEditor *oldEditor)
{
if (QmlJSLiveTextPreview *preview = m_textPreviews.value(oldEditor->file()->fileName())) {
preview->unassociateEditor(oldEditor);
}
}
void Inspector::createPreviewForEditor(Core::IEditor *newEditor)
{
if (newEditor && newEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
QString filename = newEditor->file()->fileName();
QmlJS::Document::Ptr doc = modelManager()->snapshot().document(filename);
if (m_textPreviews.contains(filename)) {
m_textPreviews.value(filename)->associateEditor(newEditor);
} else {
QmlJSLiveTextPreview *preview = new QmlJSLiveTextPreview(doc, this);
connect(preview,
SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
SLOT(changeSelectedItems(QList<QDeclarativeDebugObjectReference>)));
m_textPreviews.insert(newEditor->file()->fileName(), preview);
}
}
}
bool Inspector::setDebugConfigurationDataFromProject(ProjectExplorer::Project *projectToDebug)
{
if (!projectToDebug) {
......
......@@ -54,6 +54,10 @@ namespace Debugger {
class DebuggerRunControl;
}
namespace QmlJS {
class ModelManagerInterface;
}
namespace QmlJSInspector {
namespace Internal {
......@@ -117,6 +121,9 @@ private slots:
void disconnectWidgets();
void disconnected();
void removePreviewForEditor(Core::IEditor *newEditor);
void createPreviewForEditor(Core::IEditor *newEditor);
private:
Debugger::DebuggerRunControl *createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig,
const QString &executableFile = QString(),
......@@ -131,6 +138,9 @@ private:
bool addQuotesForData(const QVariant &value) const;
void resetViews();
QmlJS::ModelManagerInterface *modelManager();
void initializeDocuments();
private:
QWeakPointer<QDeclarativeEngineDebug> m_client;
QmlProjectManager::QmlProjectRunConfigurationDebugData m_runConfigurationDebugData;
......@@ -144,7 +154,7 @@ private:
ClientProxy *m_clientProxy;
// Qml/JS integration
QmlJSLiveTextPreview *m_textPreview;
QHash<QString, QmlJSLiveTextPreview *> m_textPreviews;
};
} // Internal
......
......@@ -65,38 +65,56 @@ void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObject
}
}
QmlJSLiveTextPreview::QmlJSLiveTextPreview(QObject *parent) :
QObject(parent)
QmlJS::ModelManagerInterface *QmlJSLiveTextPreview::modelManager()
{
Core::EditorManager *editorManager = Core::EditorManager::instance();
ClientProxy *clientProxy = ClientProxy::instance();
connect(editorManager->instance(),
SIGNAL(currentEditorChanged(Core::IEditor*)),
SLOT(setEditor(Core::IEditor*)));
connect(clientProxy,
SIGNAL(objectTreeUpdated(QDeclarativeDebugObjectReference)),
SLOT(updateDebugIds(QDeclarativeDebugObjectReference)));
return ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
}
QmlJS::ModelManagerInterface *QmlJSLiveTextPreview::modelManager()
void QmlJSLiveTextPreview::associateEditor(Core::IEditor *editor)
{
return ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
QmlJSEditor::Internal::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(editor->widget());
if (qmljsEditor && !m_editors.contains(qmljsEditor)) {
m_editors << qmljsEditor;
connect(qmljsEditor,
SIGNAL(selectedElementsChanged(QList<int>,QString)),
SLOT(changeSelectedElements(QList<int>,QString)));
}
}
}
void QmlJSLiveTextPreview::updateDocuments()
void QmlJSLiveTextPreview::unassociateEditor(Core::IEditor *oldEditor)
{
if (!modelManager())
return;
if (oldEditor && oldEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
QmlJSEditor::Internal::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(oldEditor->widget());
if (qmljsEditor && m_editors.contains(qmljsEditor)) {
m_editors.removeOne(qmljsEditor);
disconnect(qmljsEditor,
SIGNAL(selectedElementsChanged(QList<int>,QString)),
this,
SLOT(changeSelectedElements(QList<int>,QString)));
}
}
}
m_snapshot = modelManager()->snapshot();
setEditor(Core::EditorManager::instance()->currentEditor());
QmlJSLiveTextPreview::QmlJSLiveTextPreview(QmlJS::Document::Ptr doc, QObject *parent) :
QObject(parent), m_previousDoc(doc)
{
ClientProxy *clientProxy = ClientProxy::instance();
m_filename = doc->fileName();
// initial update
foreach (QmlJS::Document::Ptr doc, m_snapshot) {
documentChanged(doc);
}
connect(modelManager(), SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
SLOT(documentChanged(QmlJS::Document::Ptr)));
connect(clientProxy,
SIGNAL(objectTreeUpdated(QDeclarativeDebugObjectReference)),
SLOT(updateDebugIds(QDeclarativeDebugObjectReference)));
Core::EditorManager *em = Core::EditorManager::instance();
QList<Core::IEditor *> editors = em->editorsForFileName(m_filename);
foreach(Core::IEditor *editor, editors)
associateEditor(editor);
}
QList<QDeclarativeDebugObjectReference > QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset) const
......@@ -116,12 +134,9 @@ QList<QDeclarativeDebugObjectReference > QmlJSLiveTextPreview::objectReferencesF
void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets, const QString &wordAtCursor)
{
if (!m_currentEditor || !m_previousDoc)
if (m_editors.isEmpty() || !m_previousDoc)
return;
if (m_debugIds.isEmpty())
m_debugIds = m_initialTable.value(m_previousDoc->fileName());
ClientProxy *clientProxy = ClientProxy::instance();
QDeclarativeDebugObjectReference objectRefUnderCursor;
......@@ -160,47 +175,26 @@ void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets, const QStr
emit selectedItemsChanged(selectedReferences);
}
void QmlJSLiveTextPreview::setEditor(Core::IEditor *editor)
void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference &rootReference)
{
if (!m_currentEditor.isNull()) {
disconnect(m_currentEditor.data(), SIGNAL(selectedElementsChanged(QList<int>, QString)), this, SLOT(changeSelectedElements(QList<int>, QString)));
m_currentEditor.clear();
m_previousDoc.clear();
m_debugIds.clear();
}
QmlJS::Document::Ptr doc = m_previousDoc;
if (editor) {
m_currentEditor = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(editor->widget());
if (m_currentEditor) {
connect(m_currentEditor.data(), SIGNAL(selectedElementsChanged(QList<int>, QString)), SLOT(changeSelectedElements(QList<int>, QString)));
m_previousDoc = m_snapshot.document(editor->file()->fileName());
m_debugIds = m_initialTable.value(editor->file()->fileName());
}
}
}
if (!doc->qmlProgram())
return;
void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference &rootReference)
{
QmlJS::ModelManagerInterface *m = QmlJS::ModelManagerInterface::instance();
Snapshot snapshot = m->snapshot();
QHash<QString, QHash<UiObjectMember *, QList< QDeclarativeDebugObjectReference> > > allDebugIds;
foreach(const Document::Ptr &doc, snapshot) {
if (!doc->qmlProgram())
continue;
MapObjectWithDebugReference visitor;
visitor.root = rootReference;
QString filename = doc->fileName();
visitor.filename = filename;
doc->qmlProgram()->accept(&visitor);
allDebugIds[filename] = visitor.result;
}
MapObjectWithDebugReference visitor;
visitor.root = rootReference;
visitor.filename = doc->fileName();
doc->qmlProgram()->accept(&visitor);
m_initialTable = allDebugIds;
m_debugIds.clear();
m_debugIds = visitor.result;
}
void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
{
{
if (doc->fileName() != m_previousDoc->fileName())
return;
Core::ICore *core = Core::ICore::instance();
const int dbgcontext = core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_DEBUGMODE);
......@@ -210,12 +204,11 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
&& doc->qmlProgram() && m_previousDoc->qmlProgram())
{
if (m_debugIds.isEmpty())
m_debugIds = m_initialTable.value(doc->fileName());
Delta delta;
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
m_initialTable[doc->fileName()] = m_debugIds;
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
if (delta.referenceRefreshRequired())
ClientProxy::instance()->refreshObjectTree();
m_previousDoc = doc;
}
......
......@@ -33,16 +33,15 @@ class QmlJSLiveTextPreview : public QObject
Q_OBJECT
public:
explicit QmlJSLiveTextPreview(QObject *parent = 0);
explicit QmlJSLiveTextPreview(QmlJS::Document::Ptr doc, QObject *parent = 0);
static QmlJS::ModelManagerInterface *modelManager();
void updateDocuments();
//void updateDocuments();
void associateEditor(Core::IEditor *editor);
void unassociateEditor(Core::IEditor *editor);
void setActiveObject(const QDeclarativeDebugObjectReference &object);
void mapObjectToQml(const QDeclarativeDebugObjectReference &object);
QHash<QString, QHash<QmlJS::AST::UiObjectMember *, QList< QDeclarativeDebugObjectReference> > > m_initialTable;
QHash< QmlJS::AST::UiObjectMember*, QList<QDeclarativeDebugObjectReference > > m_debugIds;
signals:
void selectedItemsChanged(const QList<QDeclarativeDebugObjectReference> &objects);
......@@ -57,10 +56,13 @@ private:
QVariant castToLiteral(const QString &expression, QmlJS::AST::UiScriptBinding *scriptBinding);
private:
QHash<QmlJS::AST::UiObjectMember*, QList<QDeclarativeDebugObjectReference> > m_initialTable;
QHash<QmlJS::AST::UiObjectMember*, QList<QDeclarativeDebugObjectReference> > m_debugIds;
QmlJS::Document::Ptr m_previousDoc;
QString m_filename;
QmlJS::Snapshot m_snapshot;
QWeakPointer<QmlJSEditor::Internal::QmlJSTextEditor> m_currentEditor;
QList<QWeakPointer<QmlJSEditor::Internal::QmlJSTextEditor> > m_editors;
};
......
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