2010-07-08 11:34:51 +02:00
|
|
|
#include <typeinfo>
|
|
|
|
|
|
|
|
|
|
#include "qmljsclientproxy.h"
|
|
|
|
|
#include "qmljslivetextpreview.h"
|
|
|
|
|
#include "qmljsdelta.h"
|
|
|
|
|
#include "qmljsprivateapi.h"
|
|
|
|
|
|
|
|
|
|
#include <qmljseditor/qmljseditorconstants.h>
|
|
|
|
|
#include <qmljseditor/qmljseditor.h>
|
|
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
|
|
|
|
#include <coreplugin/uniqueidmanager.h>
|
|
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
|
|
|
|
|
|
|
|
#include <debugger/debuggerconstants.h>
|
|
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
|
|
using namespace QmlJS::AST;
|
|
|
|
|
|
|
|
|
|
namespace QmlJSInspector {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2010-07-14 17:38:04 +02:00
|
|
|
/*!
|
|
|
|
|
Associates the UiObjectMember* to their QDeclarativeDebugObjectReference.
|
|
|
|
|
*/
|
|
|
|
|
class MapObjectWithDebugReference : public Visitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual void endVisit(UiObjectDefinition *ast) ;
|
|
|
|
|
virtual void endVisit(UiObjectBinding *ast) ;
|
|
|
|
|
|
|
|
|
|
QDeclarativeDebugObjectReference root;
|
|
|
|
|
QString filename;
|
|
|
|
|
QHash<UiObjectMember *, QList<QDeclarativeDebugObjectReference> > result;
|
|
|
|
|
private:
|
|
|
|
|
void processRecursive(const QDeclarativeDebugObjectReference &object, UiObjectMember *ast);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void MapObjectWithDebugReference::endVisit(UiObjectDefinition* ast)
|
|
|
|
|
{
|
2010-07-19 11:02:59 +02:00
|
|
|
processRecursive(root, ast);
|
2010-07-14 17:38:04 +02:00
|
|
|
}
|
|
|
|
|
void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast)
|
|
|
|
|
{
|
2010-07-19 11:02:59 +02:00
|
|
|
processRecursive(root, ast);
|
2010-07-14 17:38:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObjectReference& object, UiObjectMember* ast)
|
|
|
|
|
{
|
|
|
|
|
// If this is too slow, it can be speed up by indexing
|
|
|
|
|
// the QDeclarativeDebugObjectReference by filename/loc in a fist pass
|
|
|
|
|
|
|
|
|
|
SourceLocation loc = ast->firstSourceLocation();
|
|
|
|
|
if (object.source().lineNumber() == int(loc.startLine) && object.source().columnNumber() == int(loc.startColumn) && object.source().url().toLocalFile() == filename) {
|
|
|
|
|
result[ast] += object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (const QDeclarativeDebugObjectReference &it, object.children()) {
|
|
|
|
|
processRecursive(it, ast);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
QmlJS::ModelManagerInterface *QmlJSLiveTextPreview::modelManager()
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
return ExtensionSystem::PluginManager::instance()->getObject<QmlJS::ModelManagerInterface>();
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
void QmlJSLiveTextPreview::associateEditor(Core::IEditor *editor)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
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)));
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
void QmlJSLiveTextPreview::unassociateEditor(Core::IEditor *oldEditor)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
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)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-08 11:34:51 +02:00
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
QmlJSLiveTextPreview::QmlJSLiveTextPreview(QmlJS::Document::Ptr doc, QObject *parent) :
|
2010-07-16 16:37:40 +02:00
|
|
|
QObject(parent), m_previousDoc(doc), m_initialDoc(doc)
|
2010-07-16 15:59:08 +02:00
|
|
|
{
|
|
|
|
|
ClientProxy *clientProxy = ClientProxy::instance();
|
|
|
|
|
m_filename = doc->fileName();
|
2010-07-08 11:34:51 +02:00
|
|
|
|
|
|
|
|
connect(modelManager(), SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
|
|
|
|
|
SLOT(documentChanged(QmlJS::Document::Ptr)));
|
2010-07-16 15:59:08 +02:00
|
|
|
|
|
|
|
|
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);
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-13 14:08:11 +02:00
|
|
|
QList<QDeclarativeDebugObjectReference > QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset) const
|
|
|
|
|
{
|
|
|
|
|
QList<QDeclarativeDebugObjectReference > result;
|
|
|
|
|
QHashIterator<QmlJS::AST::UiObjectMember*, QList<QDeclarativeDebugObjectReference > > iter(m_debugIds);
|
|
|
|
|
while(iter.hasNext()) {
|
|
|
|
|
iter.next();
|
|
|
|
|
QmlJS::AST::UiObjectMember *member = iter.key();
|
|
|
|
|
if (member->firstSourceLocation().offset == offset) {
|
|
|
|
|
result = iter.value();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets, const QString &wordAtCursor)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 15:59:08 +02:00
|
|
|
if (m_editors.isEmpty() || !m_previousDoc)
|
2010-07-08 11:34:51 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ClientProxy *clientProxy = ClientProxy::instance();
|
|
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
QDeclarativeDebugObjectReference objectRefUnderCursor;
|
2010-07-08 11:34:51 +02:00
|
|
|
|
|
|
|
|
QList<QDeclarativeDebugObjectReference> refs = clientProxy->objectReferences();
|
|
|
|
|
foreach (const QDeclarativeDebugObjectReference &ref, refs) {
|
|
|
|
|
if (ref.idString() == wordAtCursor) {
|
2010-07-12 17:18:05 +02:00
|
|
|
objectRefUnderCursor = ref;
|
2010-07-08 11:34:51 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
QList<QDeclarativeDebugObjectReference> selectedReferences;
|
2010-07-13 14:08:11 +02:00
|
|
|
bool containsReference = false;
|
2010-07-08 11:34:51 +02:00
|
|
|
|
2010-07-12 17:18:05 +02:00
|
|
|
foreach(int offset, offsets) {
|
|
|
|
|
if (offset >= 0) {
|
2010-07-13 14:08:11 +02:00
|
|
|
QList<QDeclarativeDebugObjectReference> list = objectReferencesForOffset(offset);
|
|
|
|
|
|
2010-07-13 16:13:26 +02:00
|
|
|
if (!containsReference && objectRefUnderCursor.debugId() != -1) {
|
2010-07-13 14:08:11 +02:00
|
|
|
foreach(const QDeclarativeDebugObjectReference &ref, list) {
|
|
|
|
|
if (ref.debugId() == objectRefUnderCursor.debugId()) {
|
|
|
|
|
containsReference = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
selectedReferences << list;
|
2010-07-12 17:18:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!containsReference && objectRefUnderCursor.debugId() != -1)
|
|
|
|
|
selectedReferences << objectRefUnderCursor;
|
|
|
|
|
|
|
|
|
|
if (!selectedReferences.isEmpty())
|
|
|
|
|
emit selectedItemsChanged(selectedReferences);
|
2010-07-08 11:34:51 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
void QmlJSLiveTextPreview::updateDebugIds(const QDeclarativeDebugObjectReference &rootReference)
|
2010-07-08 11:34:51 +02:00
|
|
|
{
|
2010-07-16 16:37:40 +02:00
|
|
|
QmlJS::Document::Ptr doc = m_initialDoc;
|
2010-07-13 14:08:11 +02:00
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
if (!doc->qmlProgram())
|
|
|
|
|
return;
|
2010-07-08 11:34:51 +02:00
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
MapObjectWithDebugReference visitor;
|
|
|
|
|
visitor.root = rootReference;
|
|
|
|
|
visitor.filename = doc->fileName();
|
|
|
|
|
doc->qmlProgram()->accept(&visitor);
|
2010-07-14 17:38:04 +02:00
|
|
|
|
2010-07-16 15:59:08 +02:00
|
|
|
m_debugIds = visitor.result;
|
2010-07-16 16:37:40 +02:00
|
|
|
Delta delta;
|
|
|
|
|
delta.doNotSendChanges = true;
|
|
|
|
|
m_debugIds = delta(doc, m_previousDoc, m_debugIds);
|
2010-07-14 17:38:04 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-08 11:34:51 +02:00
|
|
|
void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
2010-07-16 15:59:08 +02:00
|
|
|
{
|
|
|
|
|
if (doc->fileName() != m_previousDoc->fileName())
|
|
|
|
|
return;
|
|
|
|
|
|
2010-07-08 11:34:51 +02:00
|
|
|
Core::ICore *core = Core::ICore::instance();
|
|
|
|
|
const int dbgcontext = core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_DEBUGMODE);
|
|
|
|
|
|
2010-07-08 16:51:25 +02:00
|
|
|
if (!core->hasContext(dbgcontext))
|
2010-07-08 11:34:51 +02:00
|
|
|
return;
|
|
|
|
|
|
2010-07-14 17:38:04 +02:00
|
|
|
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
|
|
|
|
|
&& doc->qmlProgram() && m_previousDoc->qmlProgram())
|
|
|
|
|
{
|
2010-07-08 11:34:51 +02:00
|
|
|
Delta delta;
|
2010-07-16 15:59:08 +02:00
|
|
|
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
|
|
|
|
|
|
|
|
|
|
if (delta.referenceRefreshRequired())
|
|
|
|
|
ClientProxy::instance()->refreshObjectTree();
|
2010-07-13 14:08:11 +02:00
|
|
|
|
2010-07-08 11:34:51 +02:00
|
|
|
m_previousDoc = doc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace QmlJSInspector
|