forked from qt-creator/qt-creator
Merge branch 'qmljsinspector'
Conflicts: src/plugins/qmlinspector/qmlinspectorplugin.cpp src/plugins/qmljseditor/qmljseditor.h src/plugins/qmljsinspector/QmlJSInspector.pluginspec src/tools/qml/qmlobserver/editor/resizehandleitem.h
This commit is contained in:
@@ -878,8 +878,19 @@ void CodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCompletion::complete(const TextEditor::CompletionItem &item)
|
||||
bool CodeCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar)
|
||||
{
|
||||
if (item.data.canConvert<QString>()) // snippet
|
||||
return false;
|
||||
|
||||
return (item.text.endsWith(QLatin1String(": ")) && typedChar == QLatin1Char(':'))
|
||||
|| (item.text.endsWith(QLatin1Char('.')) && typedChar == QLatin1Char('.'));
|
||||
}
|
||||
|
||||
void CodeCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar)
|
||||
{
|
||||
Q_UNUSED(typedChar) // Currently always included in the completion item when used
|
||||
|
||||
QString toInsert = item.text;
|
||||
|
||||
if (QmlJSTextEditor *edit = qobject_cast<QmlJSTextEditor *>(m_editor->widget())) {
|
||||
@@ -895,7 +906,7 @@ void CodeCompletion::complete(const TextEditor::CompletionItem &item)
|
||||
QString replacableChars;
|
||||
if (toInsert.endsWith(QLatin1String(": ")))
|
||||
replacableChars = QLatin1String(": ");
|
||||
else if (toInsert.endsWith(QLatin1String(".")))
|
||||
else if (toInsert.endsWith(QLatin1Char('.')))
|
||||
replacableChars = QLatin1String(".");
|
||||
|
||||
int replacedLength = 0;
|
||||
@@ -924,7 +935,7 @@ bool CodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &
|
||||
const TextEditor::CompletionItem item = completionItems.first();
|
||||
|
||||
if (!item.data.canConvert<QString>()) {
|
||||
complete(item);
|
||||
complete(item, QChar());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,8 @@ public:
|
||||
virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
|
||||
virtual int startCompletion(TextEditor::ITextEditable *editor);
|
||||
virtual void completions(QList<TextEditor::CompletionItem> *completions);
|
||||
virtual void complete(const TextEditor::CompletionItem &item);
|
||||
virtual bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar);
|
||||
virtual void complete(const TextEditor::CompletionItem &item, QChar typedChar);
|
||||
virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
|
||||
virtual QList<TextEditor::CompletionItem> getCompletions();
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "qmljshighlighter.h"
|
||||
#include "qmljseditorplugin.h"
|
||||
#include "qmljsmodelmanager.h"
|
||||
#include "qmloutlinemodel.h"
|
||||
|
||||
#include <qmljs/qmljsindenter.h>
|
||||
#include <qmljs/qmljsinterpreter.h>
|
||||
@@ -49,6 +50,7 @@
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/modemanager.h>
|
||||
@@ -60,6 +62,7 @@
|
||||
#include <texteditor/textblockiterator.h>
|
||||
#include <texteditor/texteditorconstants.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
#include <texteditor/syntaxhighlighter.h>
|
||||
#include <qmldesigner/qmldesignerconstants.h>
|
||||
#include <utils/changeset.h>
|
||||
#include <utils/uncommentselection.h>
|
||||
@@ -69,13 +72,16 @@
|
||||
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QComboBox>
|
||||
#include <QtGui/QHeaderView>
|
||||
#include <QtGui/QInputDialog>
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QToolBar>
|
||||
#include <QtGui/QTreeView>
|
||||
|
||||
enum {
|
||||
UPDATE_DOCUMENT_DEFAULT_INTERVAL = 50,
|
||||
UPDATE_USES_DEFAULT_INTERVAL = 150
|
||||
UPDATE_USES_DEFAULT_INTERVAL = 150,
|
||||
UPDATE_OUTLINE_INTERVAL = 150 // msecs after new semantic info has been arrived / cursor has moved
|
||||
};
|
||||
|
||||
using namespace QmlJS;
|
||||
@@ -610,7 +616,8 @@ QString QmlJSEditorEditable::preferredMode() const
|
||||
|
||||
QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
|
||||
TextEditor::BaseTextEditor(parent),
|
||||
m_methodCombo(0),
|
||||
m_outlineCombo(0),
|
||||
m_outlineModel(new QmlOutlineModel(this)),
|
||||
m_modelManager(0),
|
||||
m_contextPane(0)
|
||||
{
|
||||
@@ -642,13 +649,23 @@ QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
|
||||
connect(this, SIGNAL(textChanged()), this, SLOT(updateDocument()));
|
||||
connect(this, SIGNAL(textChanged()), this, SLOT(updateUses()));
|
||||
|
||||
m_updateOutlineTimer = new QTimer(this);
|
||||
m_updateOutlineTimer->setInterval(UPDATE_OUTLINE_INTERVAL);
|
||||
m_updateOutlineTimer->setSingleShot(true);
|
||||
connect(m_updateOutlineTimer, SIGNAL(timeout()), this, SLOT(updateOutlineNow()));
|
||||
|
||||
m_updateOutlineIndexTimer = new QTimer(this);
|
||||
m_updateOutlineIndexTimer->setInterval(UPDATE_OUTLINE_INTERVAL);
|
||||
m_updateOutlineIndexTimer->setSingleShot(true);
|
||||
connect(m_updateOutlineIndexTimer, SIGNAL(timeout()), this, SLOT(updateOutlineIndexNow()));
|
||||
|
||||
baseTextDocument()->setSyntaxHighlighter(new Highlighter(document()));
|
||||
|
||||
m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<ModelManagerInterface>();
|
||||
m_contextPane = ExtensionSystem::PluginManager::instance()->getObject<QmlJS::IContextPane>();
|
||||
if (m_contextPane)
|
||||
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(onCursorPositionChanged()));
|
||||
m_oldCurserPosition = -1;
|
||||
m_oldCursorPosition = -1;
|
||||
|
||||
if (m_modelManager) {
|
||||
m_semanticHighlighter->setModelManager(m_modelManager);
|
||||
@@ -674,19 +691,33 @@ SemanticInfo QmlJSTextEditor::semanticInfo() const
|
||||
return m_semanticInfo;
|
||||
}
|
||||
|
||||
int QmlJSTextEditor::documentRevision() const
|
||||
int QmlJSTextEditor::editorRevision() const
|
||||
{
|
||||
return document()->revision();
|
||||
}
|
||||
|
||||
bool QmlJSTextEditor::isOutdated() const
|
||||
{
|
||||
if (m_semanticInfo.revision() != documentRevision())
|
||||
if (m_semanticInfo.revision() != editorRevision())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QmlOutlineModel *QmlJSTextEditor::outlineModel() const
|
||||
{
|
||||
return m_outlineModel;
|
||||
}
|
||||
|
||||
QModelIndex QmlJSTextEditor::outlineModelIndex()
|
||||
{
|
||||
if (!m_outlineModelIndex.isValid()) {
|
||||
m_outlineModelIndex = indexForPosition(position());
|
||||
emit outlineModelIndexChanged(m_outlineModelIndex);
|
||||
}
|
||||
return m_outlineModelIndex;
|
||||
}
|
||||
|
||||
Core::IEditor *QmlJSEditorEditable::duplicate(QWidget *parent)
|
||||
{
|
||||
QmlJSTextEditor *newEditor = new QmlJSTextEditor(parent);
|
||||
@@ -779,6 +810,8 @@ void QmlJSTextEditor::onDocumentUpdated(QmlJS::Document::Ptr doc)
|
||||
|
||||
const SemanticHighlighter::Source source = currentSource(/*force = */ true);
|
||||
m_semanticHighlighter->rehighlight(source);
|
||||
|
||||
m_updateOutlineTimer->start();
|
||||
} else {
|
||||
// show parsing errors
|
||||
QList<QTextEdit::ExtraSelection> selections;
|
||||
@@ -793,33 +826,70 @@ void QmlJSTextEditor::modificationChanged(bool changed)
|
||||
m_modelManager->fileChangedOnDisk(file()->fileName());
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::jumpToMethod(int index)
|
||||
void QmlJSTextEditor::jumpToOutlineElement(int /*index*/)
|
||||
{
|
||||
if (index > 0 && index <= m_semanticInfo.declarations.size()) { // indexes are 1-based
|
||||
Declaration d = m_semanticInfo.declarations.at(index - 1);
|
||||
gotoLine(d.startLine, d.startColumn - 1);
|
||||
setFocus();
|
||||
}
|
||||
QModelIndex index = m_outlineCombo->view()->currentIndex();
|
||||
AST::SourceLocation location = index.data(QmlOutlineModel::SourceLocationRole).value<AST::SourceLocation>();
|
||||
|
||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||
editorManager->cutForwardNavigationHistory();
|
||||
editorManager->addCurrentPositionToNavigationHistory();
|
||||
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.setPosition(location.offset);
|
||||
setTextCursor(cursor);
|
||||
|
||||
setFocus();
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateMethodBoxIndex()
|
||||
void QmlJSTextEditor::updateOutlineNow()
|
||||
{
|
||||
int line = 0, column = 0;
|
||||
convertPosition(position(), &line, &column);
|
||||
const Snapshot snapshot = m_modelManager->snapshot();
|
||||
Document::Ptr document = snapshot.document(file()->fileName());
|
||||
|
||||
int currentSymbolIndex = 0;
|
||||
if (!document)
|
||||
return;
|
||||
|
||||
int index = 0;
|
||||
while (index < m_semanticInfo.declarations.size()) {
|
||||
const Declaration &d = m_semanticInfo.declarations.at(index++);
|
||||
|
||||
if (line < d.startLine)
|
||||
break;
|
||||
else
|
||||
currentSymbolIndex = index;
|
||||
if (document->editorRevision() != editorRevision()) {
|
||||
m_updateOutlineTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
m_outlineModel->update(document, snapshot);
|
||||
|
||||
QTreeView *treeView = static_cast<QTreeView*>(m_outlineCombo->view());
|
||||
treeView->expandAll();
|
||||
|
||||
updateOutlineIndexNow();
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateOutlineIndexNow()
|
||||
{
|
||||
if (m_updateOutlineTimer->isActive())
|
||||
return; // updateOutlineNow will call this function soon anyway
|
||||
|
||||
if (!m_outlineModel->document())
|
||||
return;
|
||||
|
||||
if (m_outlineModel->document()->editorRevision() != editorRevision()) {
|
||||
m_updateOutlineIndexTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
m_outlineModelIndex = QModelIndex(); // invalidate
|
||||
QModelIndex comboIndex = outlineModelIndex();
|
||||
|
||||
if (comboIndex.isValid()) {
|
||||
bool blocked = m_outlineCombo->blockSignals(true);
|
||||
|
||||
// There is no direct way to select a non-root item
|
||||
m_outlineCombo->setRootModelIndex(comboIndex.parent());
|
||||
m_outlineCombo->setCurrentIndex(comboIndex.row());
|
||||
m_outlineCombo->setRootModelIndex(QModelIndex());
|
||||
|
||||
m_outlineCombo->blockSignals(blocked);
|
||||
}
|
||||
|
||||
m_methodCombo->setCurrentIndex(currentSymbolIndex);
|
||||
updateUses();
|
||||
}
|
||||
|
||||
@@ -995,10 +1065,6 @@ void QmlJSTextEditor::setSelectedElement()
|
||||
emit selectedElementsChanged(offsets, wordAtCursor);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateMethodBoxToolTip()
|
||||
{
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::updateFileName()
|
||||
{
|
||||
}
|
||||
@@ -1122,25 +1188,33 @@ TextEditor::BaseTextEditorEditable *QmlJSTextEditor::createEditableInterface()
|
||||
|
||||
void QmlJSTextEditor::createToolBar(QmlJSEditorEditable *editable)
|
||||
{
|
||||
m_methodCombo = new QComboBox;
|
||||
m_methodCombo->setMinimumContentsLength(22);
|
||||
//m_methodCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
m_outlineCombo = new QComboBox;
|
||||
m_outlineCombo->setMinimumContentsLength(22);
|
||||
m_outlineCombo->setModel(m_outlineModel);
|
||||
|
||||
QTreeView *treeView = new QTreeView;
|
||||
treeView->header()->hide();
|
||||
treeView->setItemsExpandable(false);
|
||||
treeView->setRootIsDecorated(false);
|
||||
m_outlineCombo->setView(treeView);
|
||||
treeView->expandAll();
|
||||
|
||||
//m_outlineCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
|
||||
// Make the combo box prefer to expand
|
||||
QSizePolicy policy = m_methodCombo->sizePolicy();
|
||||
QSizePolicy policy = m_outlineCombo->sizePolicy();
|
||||
policy.setHorizontalPolicy(QSizePolicy::Expanding);
|
||||
m_methodCombo->setSizePolicy(policy);
|
||||
m_outlineCombo->setSizePolicy(policy);
|
||||
|
||||
connect(m_methodCombo, SIGNAL(activated(int)), this, SLOT(jumpToMethod(int)));
|
||||
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateMethodBoxIndex()));
|
||||
connect(m_methodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMethodBoxToolTip()));
|
||||
connect(m_outlineCombo, SIGNAL(activated(int)), this, SLOT(jumpToOutlineElement(int)));
|
||||
connect(this, SIGNAL(cursorPositionChanged()), m_updateOutlineIndexTimer, SLOT(start()));
|
||||
|
||||
connect(file(), SIGNAL(changed()), this, SLOT(updateFileName()));
|
||||
|
||||
QToolBar *toolBar = static_cast<QToolBar*>(editable->toolBar());
|
||||
|
||||
QList<QAction*> actions = toolBar->actions();
|
||||
toolBar->insertWidget(actions.first(), m_methodCombo);
|
||||
toolBar->insertWidget(actions.first(), m_outlineCombo);
|
||||
}
|
||||
|
||||
TextEditor::BaseTextEditor::Link QmlJSTextEditor::findLinkAt(const QTextCursor &cursor, bool /*resolveTarget*/)
|
||||
@@ -1226,7 +1300,7 @@ bool QmlJSTextEditor::event(QEvent *e)
|
||||
switch (e->type()) {
|
||||
case QEvent::ShortcutOverride:
|
||||
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && m_contextPane) {
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, 0, false);
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, 0, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1241,7 +1315,7 @@ void QmlJSTextEditor::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
BaseTextEditor::wheelEvent(event);
|
||||
if (m_contextPane)
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.declaringMember(position()), true);
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, m_semanticInfo.declaringMember(position()), true);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::unCommentSelection()
|
||||
@@ -1473,20 +1547,11 @@ void QmlJSTextEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
|
||||
FindDeclarations findDeclarations;
|
||||
m_semanticInfo.declarations = findDeclarations(doc->ast());
|
||||
|
||||
QStringList items;
|
||||
items.append(tr("<Select Symbol>"));
|
||||
|
||||
foreach (Declaration decl, m_semanticInfo.declarations)
|
||||
items.append(decl.text);
|
||||
|
||||
m_methodCombo->clear();
|
||||
m_methodCombo->addItems(items);
|
||||
updateMethodBoxIndex();
|
||||
if (m_contextPane) {
|
||||
Node *newNode = m_semanticInfo.declaringMember(position());
|
||||
if (newNode) {
|
||||
m_contextPane->apply(editableInterface(), doc, newNode, true);
|
||||
m_oldCurserPosition = position();
|
||||
m_contextPane->apply(editableInterface(), doc, m_semanticInfo.snapshot, newNode, true);
|
||||
m_oldCursorPosition = position();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1496,21 +1561,45 @@ void QmlJSTextEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
|
||||
appendExtraSelectionsForMessages(&selections, doc->diagnosticMessages(), document());
|
||||
appendExtraSelectionsForMessages(&selections, m_semanticInfo.semanticMessages, document());
|
||||
setExtraSelections(CodeWarningsSelection, selections);
|
||||
|
||||
emit semanticInfoUpdated(semanticInfo);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::onCursorPositionChanged()
|
||||
{
|
||||
|
||||
|
||||
if (m_contextPane) {
|
||||
Node *newNode = m_semanticInfo.declaringMember(position());
|
||||
Node *oldNode = m_semanticInfo.declaringMember(m_oldCurserPosition);
|
||||
Node *oldNode = m_semanticInfo.declaringMember(m_oldCursorPosition);
|
||||
if (oldNode != newNode)
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, newNode, false);
|
||||
m_oldCurserPosition = position();
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, newNode, false);
|
||||
m_oldCursorPosition = position();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex QmlJSTextEditor::indexForPosition(unsigned cursorPosition, const QModelIndex &rootIndex) const
|
||||
{
|
||||
QModelIndex lastIndex = rootIndex;
|
||||
|
||||
|
||||
const int rowCount = m_outlineModel->rowCount(rootIndex);
|
||||
for (int i = 0; i < rowCount; ++i) {
|
||||
QModelIndex childIndex = m_outlineModel->index(i, 0, rootIndex);
|
||||
AST::SourceLocation location = childIndex.data(QmlOutlineModel::SourceLocationRole).value<AST::SourceLocation>();
|
||||
|
||||
if ((cursorPosition >= location.offset)
|
||||
&& (cursorPosition <= location.offset + location.length)) {
|
||||
lastIndex = childIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastIndex != rootIndex) {
|
||||
// recurse
|
||||
lastIndex = indexForPosition(cursorPosition, lastIndex);
|
||||
}
|
||||
return lastIndex;
|
||||
}
|
||||
|
||||
SemanticHighlighter::Source QmlJSTextEditor::currentSource(bool force)
|
||||
{
|
||||
int line = 0, column = 0;
|
||||
@@ -1633,3 +1722,4 @@ void SemanticHighlighter::setModelManager(QmlJS::ModelManagerInterface *modelMan
|
||||
{
|
||||
m_modelManager = modelManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <texteditor/basetexteditor.h>
|
||||
|
||||
#include <QtCore/QWaitCondition>
|
||||
#include <QtCore/QModelIndex>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
@@ -60,6 +61,7 @@ class Highlighter;
|
||||
namespace Internal {
|
||||
|
||||
class QmlJSTextEditor;
|
||||
class QmlOutlineModel;
|
||||
|
||||
class QmlJSEditorEditable : public TextEditor::BaseTextEditorEditable
|
||||
{
|
||||
@@ -213,18 +215,19 @@ public:
|
||||
virtual void unCommentSelection();
|
||||
|
||||
SemanticInfo semanticInfo() const;
|
||||
int documentRevision() const;
|
||||
int editorRevision() const;
|
||||
bool isOutdated() const;
|
||||
|
||||
signals:
|
||||
void selectedElementsChanged(QList<int> offsets, const QString &wordAtCursor);
|
||||
QmlOutlineModel *outlineModel() const;
|
||||
QModelIndex outlineModelIndex();
|
||||
|
||||
public slots:
|
||||
void followSymbolUnderCursor();
|
||||
virtual void setFontSettings(const TextEditor::FontSettings &);
|
||||
|
||||
signals:
|
||||
void semanticInfoUpdated(const QmlJSEditor::Internal::SemanticInfo &semanticInfo);
|
||||
void outlineModelIndexChanged(const QModelIndex &index);
|
||||
void selectedElementsChanged(QList<int> offsets, const QString &wordAtCursor);
|
||||
|
||||
private slots:
|
||||
void onDocumentUpdated(QmlJS::Document::Ptr doc);
|
||||
@@ -232,9 +235,9 @@ private slots:
|
||||
|
||||
void updateDocument();
|
||||
void updateDocumentNow();
|
||||
void jumpToMethod(int index);
|
||||
void updateMethodBoxIndex();
|
||||
void updateMethodBoxToolTip();
|
||||
void jumpToOutlineElement(int index);
|
||||
void updateOutlineNow();
|
||||
void updateOutlineIndexNow();
|
||||
void updateFileName();
|
||||
|
||||
void updateUses();
|
||||
@@ -272,13 +275,18 @@ private:
|
||||
QString wordUnderCursor() const;
|
||||
|
||||
SemanticHighlighter::Source currentSource(bool force = false);
|
||||
QModelIndex indexForPosition(unsigned cursorPosition, const QModelIndex &rootIndex = QModelIndex()) const;
|
||||
|
||||
const Core::Context m_context;
|
||||
|
||||
QTimer *m_updateDocumentTimer;
|
||||
QTimer *m_updateUsesTimer;
|
||||
QTimer *m_semanticRehighlightTimer;
|
||||
QComboBox *m_methodCombo;
|
||||
QTimer *m_updateOutlineTimer;
|
||||
QTimer *m_updateOutlineIndexTimer;
|
||||
QComboBox *m_outlineCombo;
|
||||
QmlOutlineModel *m_outlineModel;
|
||||
QModelIndex m_outlineModelIndex;
|
||||
QmlJS::ModelManagerInterface *m_modelManager;
|
||||
QTextCharFormat m_occurrencesFormat;
|
||||
QTextCharFormat m_occurrencesUnusedFormat;
|
||||
@@ -288,7 +296,7 @@ private:
|
||||
SemanticInfo m_semanticInfo;
|
||||
|
||||
QmlJS::IContextPane *m_contextPane;
|
||||
int m_oldCurserPosition;
|
||||
int m_oldCursorPosition;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -24,7 +24,9 @@ HEADERS += \
|
||||
qmljsquickfix.h \
|
||||
qmljsrefactoringchanges.h \
|
||||
qmljscomponentfromobjectdef.h \
|
||||
qmljsoutline.h
|
||||
qmljsoutline.h \
|
||||
qmloutlinemodel.h \
|
||||
qmltaskmanager.h
|
||||
|
||||
SOURCES += \
|
||||
qmljscodecompletion.cpp \
|
||||
@@ -41,7 +43,9 @@ SOURCES += \
|
||||
qmljsquickfix.cpp \
|
||||
qmljsrefactoringchanges.cpp \
|
||||
qmljscomponentfromobjectdef.cpp \
|
||||
qmljsoutline.cpp
|
||||
qmljsoutline.cpp \
|
||||
qmloutlinemodel.cpp \
|
||||
qmltaskmanager.cpp
|
||||
|
||||
RESOURCES += qmljseditor.qrc
|
||||
OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml
|
||||
|
||||
@@ -49,7 +49,7 @@ const char * const FOLLOW_SYMBOL_UNDER_CURSOR = "QmlJSEditor.FollowSymbolUnderCu
|
||||
const char * const QML_MIMETYPE = "application/x-qml";
|
||||
const char * const JS_MIMETYPE = "application/javascript";
|
||||
|
||||
|
||||
const char *const TASK_CATEGORY_QML = "Task.Category.Qml";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include "qmljsoutline.h"
|
||||
#include "qmljspreviewrunner.h"
|
||||
#include "qmljsquickfix.h"
|
||||
#include "qmljs/qmljsicons.h"
|
||||
#include "qmltaskmanager.h"
|
||||
|
||||
#include <qmldesigner/qmldesignerconstants.h>
|
||||
|
||||
@@ -51,6 +53,7 @@
|
||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <texteditor/fontsettings.h>
|
||||
#include <texteditor/storagesettings.h>
|
||||
@@ -179,11 +182,29 @@ bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *e
|
||||
|
||||
addAutoReleasedObject(new QmlJSOutlineWidgetFactory);
|
||||
|
||||
m_qmlTaskManager = new QmlTaskManager;
|
||||
addAutoReleasedObject(m_qmlTaskManager);
|
||||
|
||||
connect(m_modelManager, SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
|
||||
m_qmlTaskManager, SLOT(documentChangedOnDisk(QmlJS::Document::Ptr)));
|
||||
connect(m_modelManager, SIGNAL(aboutToRemoveFiles(QStringList)),
|
||||
m_qmlTaskManager, SLOT(documentsRemoved(QStringList)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QmlJSEditorPlugin::extensionsInitialized()
|
||||
{
|
||||
ProjectExplorer::TaskHub *taskHub =
|
||||
ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::TaskHub>();
|
||||
taskHub->addCategory(Constants::TASK_CATEGORY_QML, tr("QML"));
|
||||
}
|
||||
|
||||
ExtensionSystem::IPlugin::ShutdownFlag QmlJSEditorPlugin::aboutToShutdown()
|
||||
{
|
||||
delete QmlJS::Icons::instance(); // delete object held by singleton
|
||||
|
||||
return IPlugin::aboutToShutdown();
|
||||
}
|
||||
|
||||
void QmlJSEditorPlugin::openPreview()
|
||||
@@ -251,7 +272,7 @@ void QmlJSEditorPlugin::quickFixNow()
|
||||
if (QmlJSTextEditor *editor = qobject_cast<QmlJSTextEditor*>(m_currentTextEditable->widget())) {
|
||||
if (currentEditor == editor) {
|
||||
if (editor->isOutdated()) {
|
||||
// qDebug() << "TODO: outdated document" << editor->documentRevision() << editor->semanticInfo().revision();
|
||||
// qDebug() << "TODO: outdated document" << editor->editorRevision() << editor->semanticInfo().revision();
|
||||
// ### FIXME: m_quickFixTimer->start(QUICKFIX_INTERVAL);
|
||||
m_quickFixTimer->stop();
|
||||
} else {
|
||||
|
||||
@@ -65,6 +65,7 @@ class QmlJSEditorFactory;
|
||||
class QmlJSTextEditor;
|
||||
class QmlJSPreviewRunner;
|
||||
class QmlJSQuickFixCollector;
|
||||
class QmlTaskManager;
|
||||
|
||||
class QmlJSEditorPlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
@@ -77,6 +78,7 @@ public:
|
||||
// IPlugin
|
||||
bool initialize(const QStringList &arguments, QString *errorMessage = 0);
|
||||
void extensionsInitialized();
|
||||
ShutdownFlag aboutToShutdown();
|
||||
|
||||
static QmlJSEditorPlugin *instance()
|
||||
{ return m_instance; }
|
||||
@@ -111,6 +113,7 @@ private:
|
||||
|
||||
QTimer *m_quickFixTimer;
|
||||
QPointer<TextEditor::ITextEditable> m_currentTextEditable;
|
||||
QmlTaskManager *m_qmlTaskManager;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -39,7 +39,7 @@ using namespace QmlJSEditor;
|
||||
using namespace QmlJS;
|
||||
|
||||
Highlighter::Highlighter(QTextDocument *parent)
|
||||
: QSyntaxHighlighter(parent),
|
||||
: TextEditor::SyntaxHighlighter(parent),
|
||||
m_qmlEnabled(true),
|
||||
m_inMultilineComment(false)
|
||||
{
|
||||
|
||||
@@ -39,10 +39,11 @@
|
||||
#include <QtGui/QSyntaxHighlighter>
|
||||
|
||||
#include <texteditor/basetextdocumentlayout.h>
|
||||
#include <texteditor/syntaxhighlighter.h>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
|
||||
class QMLJSEDITOR_EXPORT Highlighter : public QSyntaxHighlighter
|
||||
class QMLJSEDITOR_EXPORT Highlighter : public TextEditor::SyntaxHighlighter
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ void HoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, int p
|
||||
|
||||
const SemanticInfo semanticInfo = edit->semanticInfo();
|
||||
|
||||
if (semanticInfo.revision() != edit->documentRevision())
|
||||
if (semanticInfo.revision() != edit->editorRevision())
|
||||
return;
|
||||
|
||||
const Snapshot snapshot = semanticInfo.snapshot;
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#include "qmljsoutline.h"
|
||||
#include "qmloutlinemodel.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <coreplugin/ifile.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
#include <QDebug>
|
||||
using namespace QmlJS;
|
||||
|
||||
enum {
|
||||
@@ -19,11 +15,6 @@ enum {
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
QmlOutlineModel::QmlOutlineModel(QObject *parent) :
|
||||
QStandardItemModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QmlJSOutlineTreeView::QmlJSOutlineTreeView(QWidget *parent) :
|
||||
QTreeView(parent)
|
||||
{
|
||||
@@ -38,207 +29,9 @@ QmlJSOutlineTreeView::QmlJSOutlineTreeView(QWidget *parent) :
|
||||
setExpandsOnDoubleClick(false);
|
||||
}
|
||||
|
||||
void QmlOutlineModel::startSync()
|
||||
{
|
||||
m_treePos.clear();
|
||||
m_treePos.append(0);
|
||||
m_currentItem = invisibleRootItem();
|
||||
}
|
||||
|
||||
QModelIndex QmlOutlineModel::enterElement(const QString &type, const AST::SourceLocation &sourceLocation)
|
||||
{
|
||||
QStandardItem *item = enterNode(sourceLocation);
|
||||
item->setText(type);
|
||||
item->setIcon(m_icons.objectDefinitionIcon());
|
||||
return item->index();
|
||||
}
|
||||
|
||||
void QmlOutlineModel::leaveElement()
|
||||
{
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
QModelIndex QmlOutlineModel::enterProperty(const QString &name, const AST::SourceLocation &sourceLocation)
|
||||
{
|
||||
QStandardItem *item = enterNode(sourceLocation);
|
||||
item->setText(name);
|
||||
item->setIcon(m_icons.scriptBindingIcon());
|
||||
return item->index();
|
||||
}
|
||||
|
||||
void QmlOutlineModel::leaveProperty()
|
||||
{
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
QStandardItem *QmlOutlineModel::enterNode(const QmlJS::AST::SourceLocation &location)
|
||||
{
|
||||
int siblingIndex = m_treePos.last();
|
||||
if (siblingIndex == 0) {
|
||||
// first child
|
||||
if (!m_currentItem->hasChildren()) {
|
||||
QStandardItem *parentItem = m_currentItem;
|
||||
m_currentItem = new QStandardItem;
|
||||
m_currentItem->setEditable(false);
|
||||
parentItem->appendRow(m_currentItem);
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - Adding" << "element to" << parentItem->text();
|
||||
} else {
|
||||
m_currentItem = m_currentItem->child(0);
|
||||
}
|
||||
} else {
|
||||
// sibling
|
||||
if (m_currentItem->rowCount() <= siblingIndex) {
|
||||
// attach
|
||||
QStandardItem *oldItem = m_currentItem;
|
||||
m_currentItem = new QStandardItem;
|
||||
m_currentItem->setEditable(false);
|
||||
oldItem->appendRow(m_currentItem);
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - Adding" << "element to" << oldItem->text();
|
||||
} else {
|
||||
m_currentItem = m_currentItem->child(siblingIndex);
|
||||
}
|
||||
}
|
||||
|
||||
m_treePos.append(0);
|
||||
m_currentItem->setData(QVariant::fromValue(location), SourceLocationRole);
|
||||
|
||||
return m_currentItem;
|
||||
}
|
||||
|
||||
void QmlOutlineModel::leaveNode()
|
||||
{
|
||||
int lastIndex = m_treePos.takeLast();
|
||||
|
||||
|
||||
if (lastIndex > 0) {
|
||||
// element has children
|
||||
if (lastIndex < m_currentItem->rowCount()) {
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << lastIndex << m_currentItem->rowCount() - lastIndex;
|
||||
m_currentItem->removeRows(lastIndex, m_currentItem->rowCount() - lastIndex);
|
||||
}
|
||||
m_currentItem = parentItem();
|
||||
} else {
|
||||
if (m_currentItem->hasChildren()) {
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << 0 << m_currentItem->rowCount();
|
||||
m_currentItem->removeRows(0, m_currentItem->rowCount());
|
||||
}
|
||||
m_currentItem = parentItem();
|
||||
}
|
||||
|
||||
|
||||
m_treePos.last()++;
|
||||
}
|
||||
|
||||
QStandardItem *QmlOutlineModel::parentItem()
|
||||
{
|
||||
QStandardItem *parent = m_currentItem->parent();
|
||||
if (!parent)
|
||||
parent = invisibleRootItem();
|
||||
return parent;
|
||||
}
|
||||
|
||||
class QmlOutlineModelSync : protected AST::Visitor
|
||||
{
|
||||
public:
|
||||
QmlOutlineModelSync(QmlOutlineModel *model) :
|
||||
m_model(model),
|
||||
indent(0)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(Document::Ptr doc)
|
||||
{
|
||||
m_nodeToIndex.clear();
|
||||
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel ------";
|
||||
m_model->startSync();
|
||||
if (doc && doc->ast())
|
||||
doc->ast()->accept(this);
|
||||
}
|
||||
|
||||
private:
|
||||
bool preVisit(AST::Node *node)
|
||||
{
|
||||
if (!node)
|
||||
return false;
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel -" << QByteArray(indent++, '-').constData() << node << typeid(*node).name();
|
||||
return true;
|
||||
}
|
||||
|
||||
void postVisit(AST::Node *)
|
||||
{
|
||||
indent--;
|
||||
}
|
||||
|
||||
QString asString(AST::UiQualifiedId *id)
|
||||
{
|
||||
QString text;
|
||||
for (; id; id = id->next) {
|
||||
if (id->name)
|
||||
text += id->name->asString();
|
||||
else
|
||||
text += QLatin1Char('?');
|
||||
|
||||
if (id->next)
|
||||
text += QLatin1Char('.');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
bool visit(AST::UiObjectDefinition *objDef)
|
||||
{
|
||||
AST::SourceLocation location;
|
||||
location.offset = objDef->firstSourceLocation().offset;
|
||||
location.length = objDef->lastSourceLocation().offset
|
||||
- objDef->firstSourceLocation().offset
|
||||
+ objDef->lastSourceLocation().length;
|
||||
|
||||
QModelIndex index = m_model->enterElement(asString(objDef->qualifiedTypeNameId), location);
|
||||
m_nodeToIndex.insert(objDef, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
void endVisit(AST::UiObjectDefinition * /*objDefinition*/)
|
||||
{
|
||||
m_model->leaveElement();
|
||||
}
|
||||
|
||||
bool visit(AST::UiScriptBinding *scriptBinding)
|
||||
{
|
||||
AST::SourceLocation location;
|
||||
location.offset = scriptBinding->firstSourceLocation().offset;
|
||||
location.length = scriptBinding->lastSourceLocation().offset
|
||||
- scriptBinding->firstSourceLocation().offset
|
||||
+ scriptBinding->lastSourceLocation().length;
|
||||
|
||||
QModelIndex index = m_model->enterProperty(asString(scriptBinding->qualifiedId), location);
|
||||
m_nodeToIndex.insert(scriptBinding, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void endVisit(AST::UiScriptBinding * /*scriptBinding*/)
|
||||
{
|
||||
m_model->leaveProperty();
|
||||
}
|
||||
|
||||
QmlOutlineModel *m_model;
|
||||
QHash<AST::Node*, QModelIndex> m_nodeToIndex;
|
||||
int indent;
|
||||
};
|
||||
|
||||
|
||||
QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent) :
|
||||
TextEditor::IOutlineWidget(parent),
|
||||
m_treeView(new QmlJSOutlineTreeView()),
|
||||
m_model(new QmlOutlineModel),
|
||||
m_treeView(new QmlJSOutlineTreeView(this)),
|
||||
m_enableCursorSync(true),
|
||||
m_blockCursorSync(false)
|
||||
{
|
||||
@@ -249,94 +42,44 @@ QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent) :
|
||||
layout->addWidget(m_treeView);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
m_treeView->setModel(m_model);
|
||||
|
||||
connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||
this, SLOT(updateSelectionInText(QItemSelection)));
|
||||
}
|
||||
|
||||
void QmlJSOutlineWidget::setEditor(QmlJSTextEditor *editor)
|
||||
{
|
||||
m_editor = editor;
|
||||
|
||||
connect(m_editor.data(), SIGNAL(semanticInfoUpdated(QmlJSEditor::Internal::SemanticInfo)),
|
||||
this, SLOT(updateOutline(QmlJSEditor::Internal::SemanticInfo)));
|
||||
connect(m_editor.data(), SIGNAL(cursorPositionChanged()),
|
||||
this, SLOT(updateSelectionInTree()));
|
||||
m_treeView->setModel(m_editor.data()->outlineModel());
|
||||
modelUpdated();
|
||||
|
||||
updateOutline(m_editor.data()->semanticInfo());
|
||||
connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
||||
this, SLOT(updateSelectionInText(QItemSelection)));
|
||||
|
||||
connect(m_editor.data(), SIGNAL(outlineModelIndexChanged(QModelIndex)),
|
||||
this, SLOT(updateSelectionInTree(QModelIndex)));
|
||||
connect(m_editor.data()->outlineModel(), SIGNAL(updated()),
|
||||
this, SLOT(modelUpdated()));
|
||||
}
|
||||
|
||||
void QmlJSOutlineWidget::setCursorSynchronization(bool syncWithCursor)
|
||||
{
|
||||
m_enableCursorSync = syncWithCursor;
|
||||
if (m_enableCursorSync)
|
||||
updateSelectionInTree();
|
||||
updateSelectionInTree(m_editor.data()->outlineModelIndex());
|
||||
}
|
||||
|
||||
void QmlJSOutlineWidget::updateOutline(const QmlJSEditor::Internal::SemanticInfo &semanticInfo)
|
||||
void QmlJSOutlineWidget::modelUpdated()
|
||||
{
|
||||
Document::Ptr doc = semanticInfo.document;
|
||||
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_editor
|
||||
|| m_editor.data()->file()->fileName() != doc->fileName()
|
||||
|| m_editor.data()->documentRevision() != doc->editorRevision()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (doc->ast()
|
||||
&& m_model) {
|
||||
|
||||
// got a correctly parsed (or recovered) file.
|
||||
|
||||
if (QmlOutlineModel *qmlModel = qobject_cast<QmlOutlineModel*>(m_model)) {
|
||||
QmlOutlineModelSync syncModel(qmlModel);
|
||||
syncModel(doc);
|
||||
}
|
||||
} else {
|
||||
// TODO: Maybe disable view?
|
||||
}
|
||||
|
||||
m_treeView->expandAll();
|
||||
}
|
||||
|
||||
QModelIndex QmlJSOutlineWidget::indexForPosition(const QModelIndex &rootIndex, int cursorPosition)
|
||||
{
|
||||
if (!rootIndex.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
AST::SourceLocation location = rootIndex.data(QmlOutlineModel::SourceLocationRole).value<AST::SourceLocation>();
|
||||
|
||||
if (!offsetInsideLocation(cursorPosition, location)) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
const int rowCount = rootIndex.model()->rowCount(rootIndex);
|
||||
for (int i = 0; i < rowCount; ++i) {
|
||||
QModelIndex childIndex = rootIndex.child(i, 0);
|
||||
QModelIndex resultIndex = indexForPosition(childIndex, cursorPosition);
|
||||
if (resultIndex.isValid())
|
||||
return resultIndex;
|
||||
}
|
||||
|
||||
return rootIndex;
|
||||
}
|
||||
|
||||
void QmlJSOutlineWidget::updateSelectionInTree()
|
||||
void QmlJSOutlineWidget::updateSelectionInTree(const QModelIndex &index)
|
||||
{
|
||||
if (!syncCursor())
|
||||
return;
|
||||
|
||||
int absoluteCursorPos = m_editor.data()->textCursor().position();
|
||||
QModelIndex index = indexForPosition(m_model->index(0, 0), absoluteCursorPos);
|
||||
|
||||
m_blockCursorSync = true;
|
||||
m_treeView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
|
||||
m_treeView->scrollTo(index);
|
||||
m_blockCursorSync = false;
|
||||
}
|
||||
|
||||
@@ -350,6 +93,10 @@ void QmlJSOutlineWidget::updateSelectionInText(const QItemSelection &selection)
|
||||
QModelIndex index = selection.indexes().first();
|
||||
AST::SourceLocation location = index.data(QmlOutlineModel::SourceLocationRole).value<AST::SourceLocation>();
|
||||
|
||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||
editorManager->cutForwardNavigationHistory();
|
||||
editorManager->addCurrentPositionToNavigationHistory();
|
||||
|
||||
QTextCursor textCursor = m_editor.data()->textCursor();
|
||||
m_blockCursorSync = true;
|
||||
textCursor.setPosition(location.offset);
|
||||
@@ -358,12 +105,6 @@ void QmlJSOutlineWidget::updateSelectionInText(const QItemSelection &selection)
|
||||
}
|
||||
}
|
||||
|
||||
bool QmlJSOutlineWidget::offsetInsideLocation(quint32 offset, const QmlJS::AST::SourceLocation &location)
|
||||
{
|
||||
return ((offset >= location.offset)
|
||||
&& (offset <= location.offset + location.length));
|
||||
}
|
||||
|
||||
bool QmlJSOutlineWidget::syncCursor()
|
||||
{
|
||||
return m_enableCursorSync && !m_blockCursorSync;
|
||||
|
||||
@@ -3,16 +3,9 @@
|
||||
|
||||
#include "qmljseditor.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/inavigationwidgetfactory.h>
|
||||
#include <texteditor/ioutlinewidget.h>
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qmljs/qmljsicons.h>
|
||||
|
||||
#include <QtGui/QStandardItemModel>
|
||||
#include <QtGui/QTreeView>
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
namespace Core {
|
||||
class IEditor;
|
||||
@@ -25,35 +18,6 @@ class Editor;
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlOutlineModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum CustomRoles {
|
||||
SourceLocationRole = Qt::UserRole + 1
|
||||
};
|
||||
|
||||
QmlOutlineModel(QObject *parent = 0);
|
||||
|
||||
void startSync();
|
||||
|
||||
QModelIndex enterElement(const QString &typeName, const QmlJS::AST::SourceLocation &location);
|
||||
void leaveElement();
|
||||
|
||||
QModelIndex enterProperty(const QString &name, const QmlJS::AST::SourceLocation &location);
|
||||
void leaveProperty();
|
||||
|
||||
private:
|
||||
QStandardItem *enterNode(const QmlJS::AST::SourceLocation &location);
|
||||
void leaveNode();
|
||||
|
||||
QStandardItem *parentItem();
|
||||
|
||||
QList<int> m_treePos;
|
||||
QStandardItem *m_currentItem;
|
||||
QmlJS::Icons m_icons;
|
||||
};
|
||||
|
||||
class QmlJSOutlineTreeView : public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -61,7 +25,6 @@ public:
|
||||
QmlJSOutlineTreeView(QWidget *parent = 0);
|
||||
};
|
||||
|
||||
|
||||
class QmlJSOutlineWidget : public TextEditor::IOutlineWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -74,18 +37,15 @@ public:
|
||||
virtual void setCursorSynchronization(bool syncWithCursor);
|
||||
|
||||
private slots:
|
||||
void updateOutline(const QmlJSEditor::Internal::SemanticInfo &semanticInfo);
|
||||
void updateSelectionInTree();
|
||||
void modelUpdated();
|
||||
void updateSelectionInTree(const QModelIndex &index);
|
||||
void updateSelectionInText(const QItemSelection &selection);
|
||||
|
||||
private:
|
||||
QModelIndex indexForPosition(const QModelIndex &rootIndex, int cursorPosition);
|
||||
bool offsetInsideLocation(quint32 offset, const QmlJS::AST::SourceLocation &location);
|
||||
bool syncCursor();
|
||||
|
||||
private:
|
||||
QmlJSOutlineTreeView *m_treeView;
|
||||
QAbstractItemModel *m_model;
|
||||
QWeakPointer<QmlJSTextEditor> m_editor;
|
||||
|
||||
bool m_enableCursorSync;
|
||||
@@ -103,6 +63,4 @@ public:
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
Q_DECLARE_METATYPE(QmlJS::AST::SourceLocation);
|
||||
|
||||
#endif // QMLJSOUTLINE_H
|
||||
|
||||
337
src/plugins/qmljseditor/qmloutlinemodel.cpp
Normal file
337
src/plugins/qmljseditor/qmloutlinemodel.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
#include "qmloutlinemodel.h"
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
#include <qmljs/qmljsinterpreter.h>
|
||||
#include <qmljs/qmljslookupcontext.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QTime>
|
||||
#include <typeinfo>
|
||||
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJSEditor::Internal;
|
||||
|
||||
enum {
|
||||
debug = false
|
||||
};
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlOutlineModelSync : protected AST::Visitor
|
||||
{
|
||||
public:
|
||||
QmlOutlineModelSync(QmlOutlineModel *model) :
|
||||
m_model(model),
|
||||
indent(0)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(Document::Ptr doc, const Snapshot &snapshot)
|
||||
{
|
||||
m_nodeToIndex.clear();
|
||||
|
||||
// Set up lookup context once to do the element type lookup
|
||||
//
|
||||
// We're simplifying here by using the root context everywhere
|
||||
// (empty node list). However, creating the LookupContext is quite expensive (about 3ms),
|
||||
// and there is AFAIK no way to introduce new type names in a sub-context.
|
||||
m_context = LookupContext::create(doc, snapshot, QList<AST::Node*>());
|
||||
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel ------";
|
||||
if (doc && doc->ast())
|
||||
doc->ast()->accept(this);
|
||||
|
||||
m_context.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
bool preVisit(AST::Node *node)
|
||||
{
|
||||
if (!node)
|
||||
return false;
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel -" << QByteArray(indent++, '-').constData() << node << typeid(*node).name();
|
||||
return true;
|
||||
}
|
||||
|
||||
void postVisit(AST::Node *)
|
||||
{
|
||||
indent--;
|
||||
}
|
||||
|
||||
QString asString(AST::UiQualifiedId *id)
|
||||
{
|
||||
QString text;
|
||||
for (; id; id = id->next) {
|
||||
if (id->name)
|
||||
text += id->name->asString();
|
||||
else
|
||||
text += QLatin1Char('?');
|
||||
|
||||
if (id->next)
|
||||
text += QLatin1Char('.');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
typedef QPair<QString,QString> ElementType;
|
||||
bool visit(AST::UiObjectDefinition *objDef)
|
||||
{
|
||||
if (!validElement(objDef)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AST::SourceLocation location = getLocation(objDef);
|
||||
|
||||
const QString typeName = asString(objDef->qualifiedTypeNameId);
|
||||
|
||||
if (!m_typeToIcon.contains(typeName)) {
|
||||
m_typeToIcon.insert(typeName, getIcon(objDef));
|
||||
}
|
||||
const QIcon icon = m_typeToIcon.value(typeName);
|
||||
QString id = getId(objDef);
|
||||
|
||||
QModelIndex index = m_model->enterElement(typeName, id, icon, location);
|
||||
m_nodeToIndex.insert(objDef, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
void endVisit(AST::UiObjectDefinition *objDef)
|
||||
{
|
||||
if (!validElement(objDef)) {
|
||||
return;
|
||||
}
|
||||
m_model->leaveElement();
|
||||
}
|
||||
|
||||
bool visit(AST::UiScriptBinding *scriptBinding)
|
||||
{
|
||||
AST::SourceLocation location = getLocation(scriptBinding);
|
||||
|
||||
QModelIndex index = m_model->enterProperty(asString(scriptBinding->qualifiedId), false, location);
|
||||
m_nodeToIndex.insert(scriptBinding, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void endVisit(AST::UiScriptBinding * /*scriptBinding*/)
|
||||
{
|
||||
m_model->leaveProperty();
|
||||
}
|
||||
|
||||
bool visit(AST::UiPublicMember *publicMember)
|
||||
{
|
||||
AST::SourceLocation location = getLocation(publicMember);
|
||||
QModelIndex index = m_model->enterProperty(publicMember->name->asString(), true, location);
|
||||
m_nodeToIndex.insert(publicMember, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void endVisit(AST::UiPublicMember * /*publicMember*/)
|
||||
{
|
||||
m_model->leaveProperty();
|
||||
}
|
||||
|
||||
bool validElement(AST::UiObjectDefinition *objDef) {
|
||||
// For 'Rectangle { id }', id is parsed as UiObjectDefinition ... Filter this out.
|
||||
return objDef->qualifiedTypeNameId->name->asString().at(0).isUpper();
|
||||
}
|
||||
|
||||
QIcon getIcon(AST::UiObjectDefinition *objDef) {
|
||||
const QmlJS::Interpreter::Value *value = m_context->evaluate(objDef->qualifiedTypeNameId);
|
||||
|
||||
if (const Interpreter::ObjectValue *objectValue = value->asObjectValue()) {
|
||||
do {
|
||||
QString module;
|
||||
QString typeName;
|
||||
if (const Interpreter::QmlObjectValue *qmlObjectValue =
|
||||
dynamic_cast<const Interpreter::QmlObjectValue*>(objectValue)) {
|
||||
module = qmlObjectValue->packageName();
|
||||
}
|
||||
typeName = objectValue->className();
|
||||
|
||||
QIcon icon = m_model->m_icons->icon(module, typeName);
|
||||
if (! icon.isNull())
|
||||
return icon;
|
||||
|
||||
objectValue = objectValue->prototype(m_context->context());
|
||||
} while (objectValue);
|
||||
}
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
QString getId(AST::UiObjectDefinition *objDef) {
|
||||
QString id;
|
||||
for (AST::UiObjectMemberList *it = objDef->initializer->members; it; it = it->next) {
|
||||
if (AST::UiScriptBinding *binding = dynamic_cast<AST::UiScriptBinding*>(it->member)) {
|
||||
if (binding->qualifiedId->name->asString() == "id") {
|
||||
AST::ExpressionStatement *expr = dynamic_cast<AST::ExpressionStatement*>(binding->statement);
|
||||
if (!expr)
|
||||
continue;
|
||||
AST::IdentifierExpression *idExpr = dynamic_cast<AST::IdentifierExpression*>(expr->expression);
|
||||
if (!idExpr)
|
||||
continue;
|
||||
id = idExpr->name->asString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
AST::SourceLocation getLocation(AST::UiObjectMember *objMember) {
|
||||
AST::SourceLocation location;
|
||||
location.offset = objMember->firstSourceLocation().offset;
|
||||
location.length = objMember->lastSourceLocation().offset
|
||||
- objMember->firstSourceLocation().offset
|
||||
+ objMember->lastSourceLocation().length;
|
||||
return location;
|
||||
}
|
||||
|
||||
QmlOutlineModel *m_model;
|
||||
LookupContext::Ptr m_context;
|
||||
|
||||
QHash<AST::Node*, QModelIndex> m_nodeToIndex;
|
||||
QHash<QString, QIcon> m_typeToIcon;
|
||||
int indent;
|
||||
};
|
||||
|
||||
QmlOutlineModel::QmlOutlineModel(QObject *parent) :
|
||||
QStandardItemModel(parent)
|
||||
{
|
||||
m_icons = Icons::instance();
|
||||
const QString resourcePath = Core::ICore::instance()->resourcePath();
|
||||
QmlJS::Icons::instance()->setIconFilesPath(resourcePath + "/qmlicons");
|
||||
}
|
||||
|
||||
QmlJS::Document::Ptr QmlOutlineModel::document() const
|
||||
{
|
||||
return m_document;
|
||||
}
|
||||
|
||||
void QmlOutlineModel::update(QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot)
|
||||
{
|
||||
m_document = doc;
|
||||
|
||||
m_treePos.clear();
|
||||
m_treePos.append(0);
|
||||
m_currentItem = invisibleRootItem();
|
||||
|
||||
QmlOutlineModelSync syncModel(this);
|
||||
syncModel(doc, snapshot);
|
||||
|
||||
emit updated();
|
||||
}
|
||||
|
||||
QModelIndex QmlOutlineModel::enterElement(const QString &type, const QString &id, const QIcon &icon, const AST::SourceLocation &sourceLocation)
|
||||
{
|
||||
QStandardItem *item = enterNode(sourceLocation);
|
||||
if (!id.isEmpty()) {
|
||||
item->setText(id);
|
||||
} else {
|
||||
item->setText(type);
|
||||
}
|
||||
item->setIcon(icon);
|
||||
item->setToolTip(type);
|
||||
return item->index();
|
||||
}
|
||||
|
||||
void QmlOutlineModel::leaveElement()
|
||||
{
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
QModelIndex QmlOutlineModel::enterProperty(const QString &name, bool isCustomProperty, const AST::SourceLocation &sourceLocation)
|
||||
{
|
||||
QStandardItem *item = enterNode(sourceLocation);
|
||||
item->setText(name);
|
||||
if (isCustomProperty) {
|
||||
item->setIcon(m_icons->publicMemberIcon());
|
||||
} else {
|
||||
item->setIcon(m_icons->scriptBindingIcon());
|
||||
}
|
||||
return item->index();
|
||||
}
|
||||
|
||||
void QmlOutlineModel::leaveProperty()
|
||||
{
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
QStandardItem *QmlOutlineModel::enterNode(const QmlJS::AST::SourceLocation &location)
|
||||
{
|
||||
int siblingIndex = m_treePos.last();
|
||||
if (siblingIndex == 0) {
|
||||
// first child
|
||||
if (!m_currentItem->hasChildren()) {
|
||||
QStandardItem *parentItem = m_currentItem;
|
||||
m_currentItem = new QStandardItem;
|
||||
m_currentItem->setEditable(false);
|
||||
parentItem->appendRow(m_currentItem);
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - Adding" << "element to" << parentItem->text();
|
||||
} else {
|
||||
m_currentItem = m_currentItem->child(0);
|
||||
}
|
||||
} else {
|
||||
// sibling
|
||||
if (m_currentItem->rowCount() <= siblingIndex) {
|
||||
// attach
|
||||
QStandardItem *oldItem = m_currentItem;
|
||||
m_currentItem = new QStandardItem;
|
||||
m_currentItem->setEditable(false);
|
||||
oldItem->appendRow(m_currentItem);
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - Adding" << "element to" << oldItem->text();
|
||||
} else {
|
||||
m_currentItem = m_currentItem->child(siblingIndex);
|
||||
}
|
||||
}
|
||||
|
||||
m_treePos.append(0);
|
||||
m_currentItem->setData(QVariant::fromValue(location), SourceLocationRole);
|
||||
|
||||
return m_currentItem;
|
||||
}
|
||||
|
||||
void QmlOutlineModel::leaveNode()
|
||||
{
|
||||
int lastIndex = m_treePos.takeLast();
|
||||
|
||||
|
||||
if (lastIndex > 0) {
|
||||
// element has children
|
||||
if (lastIndex < m_currentItem->rowCount()) {
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << lastIndex << m_currentItem->rowCount() - lastIndex;
|
||||
m_currentItem->removeRows(lastIndex, m_currentItem->rowCount() - lastIndex);
|
||||
}
|
||||
m_currentItem = parentItem();
|
||||
} else {
|
||||
if (m_currentItem->hasChildren()) {
|
||||
if (debug)
|
||||
qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << 0 << m_currentItem->rowCount();
|
||||
m_currentItem->removeRows(0, m_currentItem->rowCount());
|
||||
}
|
||||
m_currentItem = parentItem();
|
||||
}
|
||||
|
||||
|
||||
m_treePos.last()++;
|
||||
}
|
||||
|
||||
QStandardItem *QmlOutlineModel::parentItem()
|
||||
{
|
||||
QStandardItem *parent = m_currentItem->parent();
|
||||
if (!parent)
|
||||
parent = invisibleRootItem();
|
||||
return parent;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
55
src/plugins/qmljseditor/qmloutlinemodel.h
Normal file
55
src/plugins/qmljseditor/qmloutlinemodel.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef QMLOUTLINEMODEL_H
|
||||
#define QMLOUTLINEMODEL_H
|
||||
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qmljs/qmljsicons.h>
|
||||
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlOutlineModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum CustomRoles {
|
||||
SourceLocationRole = Qt::UserRole + 1
|
||||
};
|
||||
|
||||
QmlOutlineModel(QObject *parent = 0);
|
||||
|
||||
QmlJS::Document::Ptr document() const;
|
||||
void update(QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot);
|
||||
|
||||
QModelIndex enterElement(const QString &typeName, const QString &id, const QIcon &icon,
|
||||
const QmlJS::AST::SourceLocation &location);
|
||||
void leaveElement();
|
||||
|
||||
QModelIndex enterProperty(const QString &name, bool isCustomProperty,
|
||||
const QmlJS::AST::SourceLocation &location);
|
||||
void leaveProperty();
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
|
||||
private:
|
||||
QStandardItem *enterNode(const QmlJS::AST::SourceLocation &location);
|
||||
void leaveNode();
|
||||
|
||||
QStandardItem *parentItem();
|
||||
|
||||
QmlJS::Document::Ptr m_document;
|
||||
QList<int> m_treePos;
|
||||
QStandardItem *m_currentItem;
|
||||
QmlJS::Icons *m_icons;
|
||||
|
||||
friend class QmlOutlineModelSync;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSEditor
|
||||
|
||||
Q_DECLARE_METATYPE(QmlJS::AST::SourceLocation);
|
||||
|
||||
#endif // QMLOUTLINEMODEL_H
|
||||
90
src/plugins/qmljseditor/qmltaskmanager.cpp
Normal file
90
src/plugins/qmljseditor/qmltaskmanager.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmltaskmanager.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
QmlTaskManager::QmlTaskManager(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_taskHub(0)
|
||||
{
|
||||
m_taskHub = ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::TaskHub>();
|
||||
}
|
||||
|
||||
void QmlTaskManager::documentChangedOnDisk(QmlJS::Document::Ptr doc)
|
||||
{
|
||||
const QString fileName = doc->fileName();
|
||||
removeTasksForFile(fileName);
|
||||
|
||||
foreach (const QmlJS::DiagnosticMessage &msg, doc->diagnosticMessages()) {
|
||||
ProjectExplorer::Task::TaskType type
|
||||
= msg.isError() ? ProjectExplorer::Task::Error
|
||||
: ProjectExplorer::Task::Warning;
|
||||
|
||||
ProjectExplorer::Task task(type, msg.message, fileName, msg.loc.startLine,
|
||||
Constants::TASK_CATEGORY_QML);
|
||||
insertTask(fileName, task);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlTaskManager::documentsRemoved(const QStringList path)
|
||||
{
|
||||
foreach (const QString &item, path)
|
||||
removeTasksForFile(item);
|
||||
}
|
||||
|
||||
void QmlTaskManager::insertTask(const QString &fileName, const ProjectExplorer::Task &task)
|
||||
{
|
||||
QList<ProjectExplorer::Task> tasks = m_docsWithTasks.value(fileName);
|
||||
tasks.append(task);
|
||||
m_docsWithTasks.insert(fileName, tasks);
|
||||
m_taskHub->addTask(task);
|
||||
}
|
||||
|
||||
void QmlTaskManager::removeTasksForFile(const QString &fileName)
|
||||
{
|
||||
if (m_docsWithTasks.contains(fileName)) {
|
||||
const QList<ProjectExplorer::Task> tasks = m_docsWithTasks.value(fileName);
|
||||
foreach (const ProjectExplorer::Task &task, tasks)
|
||||
m_taskHub->removeTask(task);
|
||||
m_docsWithTasks.remove(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // QmlProjectManager
|
||||
72
src/plugins/qmljseditor/qmltaskmanager.h
Normal file
72
src/plugins/qmljseditor/qmltaskmanager.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** Commercial Usage
|
||||
**
|
||||
** Licensees holding valid Qt Commercial licenses may use this file in
|
||||
** accordance with the Qt Commercial License Agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Nokia.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** contact the sales department at http://qt.nokia.com/contact.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLTASKMANAGER_H
|
||||
#define QMLTASKMANAGER_H
|
||||
|
||||
#include <projectexplorer/task.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QString>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class TaskHub;
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
namespace QmlJSEditor {
|
||||
namespace Internal {
|
||||
|
||||
class QmlTaskManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QmlTaskManager(QObject *parent = 0);
|
||||
|
||||
void extensionsInitialized();
|
||||
|
||||
public slots:
|
||||
void documentChangedOnDisk(QmlJS::Document::Ptr doc);
|
||||
void documentsRemoved(const QStringList path);
|
||||
|
||||
private:
|
||||
void insertTask(const QString &fileName, const ProjectExplorer::Task &task);
|
||||
void removeTasksForFile(const QString &fileName);
|
||||
|
||||
private:
|
||||
ProjectExplorer::TaskHub *m_taskHub;
|
||||
QMap<QString, QList<ProjectExplorer::Task> > m_docsWithTasks;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // QmlJSEditor
|
||||
|
||||
#endif // QMLTASKMANAGER_H
|
||||
Reference in New Issue
Block a user