diff --git a/src/plugins/qtscripteditor/qtscripteditor.cpp b/src/plugins/qtscripteditor/qtscripteditor.cpp index fb70e52562deb8c1cd818a0ff32558b4e59ff58a..2bcc36bfa500d40dc9c73e64f108da922bbcbe30 100644 --- a/src/plugins/qtscripteditor/qtscripteditor.cpp +++ b/src/plugins/qtscripteditor/qtscripteditor.cpp @@ -49,16 +49,81 @@ #include <texteditor/texteditorconstants.h> #include <texteditor/texteditorsettings.h> -#include <QtGui/QMenu> #include <QtCore/QTimer> +#include <QtCore/QtDebug> + +#include <QtGui/QMenu> +#include <QtGui/QComboBox> enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100 }; +using namespace JavaScript::AST; + + namespace QtScriptEditor { namespace Internal { +class FindDeclarations: protected Visitor +{ + QList<Declaration> declarations; + +public: + QList<Declaration> accept(JavaScript::AST::Node *node) + { + JavaScript::AST::Node::acceptChild(node, this); + return declarations; + } + +protected: + using Visitor::visit; + + virtual bool visit(FunctionExpression *) + { + return false; + } + + virtual bool visit(FunctionDeclaration *ast) + { + QString text = ast->name->asString(); + + text += QLatin1Char('('); + for (FormalParameterList *it = ast->formals; it; it = it->next) { + text += it->name->asString(); + + if (it->next) + text += QLatin1String(", "); + } + + text += QLatin1Char(')'); + + Declaration d; + d.text = text; + d.startLine= ast->startLine; + d.startColumn = ast->startColumn; + d.endLine = ast->endLine; + d.endColumn = ast->endColumn; + + declarations.append(d); + + return false; + } + + virtual bool visit(VariableDeclaration *ast) + { + Declaration d; + d.text = ast->name->asString(); + d.startLine= ast->startLine; + d.startColumn = ast->startColumn; + d.endLine = ast->endLine; + d.endColumn = ast->endColumn; + + declarations.append(d); + return false; + } +}; + ScriptEditorEditable::ScriptEditorEditable(ScriptEditor *editor, const QList<int>& context) : BaseTextEditorEditable(editor), m_context(context) { @@ -67,7 +132,8 @@ ScriptEditorEditable::ScriptEditorEditable(ScriptEditor *editor, const QList<int ScriptEditor::ScriptEditor(const Context &context, QWidget *parent) : TextEditor::BaseTextEditor(parent), - m_context(context) + m_context(context), + m_methodCombo(0) { setParenthesesMatchingEnabled(true); setMarksVisible(true); @@ -135,7 +201,20 @@ void ScriptEditor::updateDocumentNow() QList<QTextEdit::ExtraSelection> selections; if (parser.parse(&driver)) { - // do something here + + FindDeclarations decls; + m_declarations = decls.accept(driver.ast()); + + QStringList items; + items.append(tr("<Select Symbol>")); + + foreach (Declaration decl, m_declarations) + items.append(decl.text); + + m_methodCombo->clear(); + m_methodCombo->addItems(items); + updateMethodBoxIndex(); + } else { QTextEdit::ExtraSelection sel; sel.format.setUnderlineColor(Qt::red); @@ -157,6 +236,46 @@ void ScriptEditor::updateDocumentNow() setExtraSelections(CodeWarningsSelection, selections); } +void ScriptEditor::jumpToMethod(int index) +{ + if (index) { + Declaration d = m_declarations.at(index - 1); + gotoLine(d.startLine, d.startColumn - 1); + setFocus(); + } +} + +void ScriptEditor::updateMethodBoxIndex() +{ + int line = 0, column = 0; + convertPosition(position(), &line, &column); + + int currentSymbolIndex = 0; + + for (int index = 0; index < m_declarations.size(); ++index) { + const Declaration &d = m_declarations.at(index); + + // qDebug() << line << column << d.startLine << d.startColumn << d.endLine << d.endColumn; + + if (line >= d.startLine || (line == d.startLine && column > d.startColumn)) { + if (line < d.endLine || (line == d.endLine && column < d.endColumn)) { + currentSymbolIndex = index + 1; + break; + } + } + } + + m_methodCombo->setCurrentIndex(currentSymbolIndex); +} + +void ScriptEditor::updateMethodBoxToolTip() +{ +} + +void ScriptEditor::updateFileName() +{ +} + void ScriptEditor::setFontSettings(const TextEditor::FontSettings &fs) { TextEditor::BaseTextEditor::setFontSettings(fs); @@ -210,6 +329,36 @@ void ScriptEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typed indentScriptBlock(tabSettings(), block, begin, end, typedChar); } +TextEditor::BaseTextEditorEditable *ScriptEditor::createEditableInterface() +{ + ScriptEditorEditable *editable = new ScriptEditorEditable(this, m_context); + createToolBar(editable); + return editable; +} + +void ScriptEditor::createToolBar(ScriptEditorEditable *editable) +{ + m_methodCombo = new QComboBox; + m_methodCombo->setMinimumContentsLength(22); + //m_methodCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); + + // Make the combo box prefer to expand + QSizePolicy policy = m_methodCombo->sizePolicy(); + policy.setHorizontalPolicy(QSizePolicy::Expanding); + m_methodCombo->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(file(), SIGNAL(changed()), this, SLOT(updateFileName())); + + QToolBar *toolBar = editable->toolBar(); + + QList<QAction*> actions = toolBar->actions(); + toolBar->insertWidget(actions.first(), m_methodCombo); +} + void ScriptEditor::contextMenuEvent(QContextMenuEvent *e) { QMenu *menu = createStandardContextMenu(); diff --git a/src/plugins/qtscripteditor/qtscripteditor.h b/src/plugins/qtscripteditor/qtscripteditor.h index 4371e5873cee596eeeb4e6aff4a7d6084f880be9..eb91a7bdb9e55e5ef0e822915e6a8ada04d38b5d 100644 --- a/src/plugins/qtscripteditor/qtscripteditor.h +++ b/src/plugins/qtscripteditor/qtscripteditor.h @@ -31,7 +31,11 @@ #define QTSCRIPTDITORW_H #include <texteditor/basetexteditor.h> -#include <QTimer> + +QT_BEGIN_NAMESPACE +class QComboBox; +class QTimer; +QT_END_NAMESPACE namespace Core { class ICore; @@ -40,7 +44,7 @@ namespace Core { namespace QtScriptEditor { namespace Internal { -class QtScriptHighlighter; +class QtScriptHighlighter; class ScriptEditor; @@ -53,13 +57,28 @@ public: bool duplicateSupported() const { return true; } Core::IEditor *duplicate(QWidget *parent); const char *kind() const; - QToolBar *toolBar() { return 0; } private: QList<int> m_context; }; +struct Declaration +{ + QString text; + int startLine; + int startColumn; + int endLine; + int endColumn; + + Declaration() + : startLine(0), + startColumn(0), + endLine(0), + endColumn(0) + { } +}; + class ScriptEditor : public TextEditor::BaseTextEditor { Q_OBJECT @@ -77,10 +96,15 @@ public slots: private slots: void updateDocument(); void updateDocumentNow(); + void jumpToMethod(int index); + void updateMethodBoxIndex(); + void updateMethodBoxToolTip(); + void updateFileName(); protected: void contextMenuEvent(QContextMenuEvent *e); - TextEditor::BaseTextEditorEditable *createEditableInterface() { return new ScriptEditorEditable(this, m_context); } + TextEditor::BaseTextEditorEditable *createEditableInterface(); + void createToolBar(ScriptEditorEditable *editable); private: virtual bool isElectricCharacter(const QChar &ch) const; @@ -89,6 +113,8 @@ private: const Context m_context; QTimer *m_updateDocumentTimer; + QComboBox *m_methodCombo; + QList<Declaration> m_declarations; }; } // namespace Internal