diff --git a/src/plugins/qmljstools/QmlJSTools.pluginspec.in b/src/plugins/qmljstools/QmlJSTools.pluginspec.in
index 0128ca3945b..169376d347e 100644
--- a/src/plugins/qmljstools/QmlJSTools.pluginspec.in
+++ b/src/plugins/qmljstools/QmlJSTools.pluginspec.in
@@ -16,5 +16,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
+
diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp
new file mode 100644
index 00000000000..4f097857f24
--- /dev/null
+++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp
@@ -0,0 +1,115 @@
+/**************************************************************************
+**
+** 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 "qmljsfunctionfilter.h"
+#include "qmljslocatordata.h"
+
+#include
+#include
+
+#include
+
+using namespace QmlJSTools::Internal;
+
+Q_DECLARE_METATYPE(LocatorData::Entry);
+
+FunctionFilter::FunctionFilter(LocatorData *data, QObject *parent)
+ : Locator::ILocatorFilter(parent)
+ , m_data(data)
+{
+ setShortcutString(QString(QLatin1Char('m')));
+ setIncludedByDefault(false);
+}
+
+FunctionFilter::~FunctionFilter()
+{ }
+
+void FunctionFilter::refresh(QFutureInterface &)
+{
+}
+
+static bool compareLexigraphically(const Locator::FilterEntry &a,
+ const Locator::FilterEntry &b)
+{
+ return a.displayName < b.displayName;
+}
+
+QList FunctionFilter::matchesFor(QFutureInterface &future, const QString &origEntry)
+{
+ QString entry = trimWildcards(origEntry);
+ QList goodEntries;
+ QList betterEntries;
+ const QChar asterisk = QLatin1Char('*');
+ QStringMatcher matcher(entry, Qt::CaseInsensitive);
+ const QRegExp regexp(asterisk + entry+ asterisk, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (!regexp.isValid())
+ return goodEntries;
+ bool hasWildcard = (entry.contains(asterisk) || entry.contains('?'));
+
+ QHashIterator > it(m_data->entries());
+ while (it.hasNext()) {
+ if (future.isCanceled())
+ break;
+
+ it.next();
+
+ const QList items = it.value();
+ foreach (const LocatorData::Entry &info, items) {
+ if (info.type != LocatorData::Function)
+ continue;
+ if ((hasWildcard && regexp.exactMatch(info.symbolName))
+ || (!hasWildcard && matcher.indexIn(info.symbolName) != -1)) {
+
+ QVariant id = qVariantFromValue(info);
+ Locator::FilterEntry filterEntry(this, info.displayName, id/*, info.icon*/);
+ filterEntry.extraInfo = info.extraInfo;
+
+ if (info.symbolName.startsWith(entry))
+ betterEntries.append(filterEntry);
+ else
+ goodEntries.append(filterEntry);
+ }
+ }
+ }
+
+ if (goodEntries.size() < 1000)
+ qSort(goodEntries.begin(), goodEntries.end(), compareLexigraphically);
+ if (betterEntries.size() < 1000)
+ qSort(betterEntries.begin(), betterEntries.end(), compareLexigraphically);
+
+ betterEntries += goodEntries;
+ return betterEntries;
+}
+
+void FunctionFilter::accept(Locator::FilterEntry selection) const
+{
+ const LocatorData::Entry entry = qvariant_cast(selection.internalData);
+ TextEditor::BaseTextEditor::openEditorAt(entry.fileName, entry.line, entry.column,
+ QString(), Core::EditorManager::ModeSwitch);
+}
diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.h b/src/plugins/qmljstools/qmljsfunctionfilter.h
new file mode 100644
index 00000000000..d79fed8eb95
--- /dev/null
+++ b/src/plugins/qmljstools/qmljsfunctionfilter.h
@@ -0,0 +1,61 @@
+/**************************************************************************
+**
+** 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 QMLJSFUNCTIONFILTER_H
+#define QMLJSFUNCTIONFILTER_H
+
+#include
+
+namespace QmlJSTools {
+namespace Internal {
+
+class LocatorData;
+
+class FunctionFilter : public Locator::ILocatorFilter
+{
+ Q_OBJECT
+public:
+ explicit FunctionFilter(LocatorData *data, QObject *parent = 0);
+ ~FunctionFilter();
+
+ QString displayName() const { return tr("Functions"); }
+ QString id() const { return QLatin1String("Functions"); }
+ Priority priority() const { return Medium; }
+ QList matchesFor(QFutureInterface &future, const QString &entry);
+ void accept(Locator::FilterEntry selection) const;
+ void refresh(QFutureInterface &future);
+
+private:
+ LocatorData *m_data;
+};
+
+} // namespace Internal
+} // namespace QmlJSTools
+
+#endif // QMLJSFUNCTIONFILTER_H
diff --git a/src/plugins/qmljstools/qmljslocatordata.cpp b/src/plugins/qmljstools/qmljslocatordata.cpp
new file mode 100644
index 00000000000..4b9b45e24ae
--- /dev/null
+++ b/src/plugins/qmljstools/qmljslocatordata.cpp
@@ -0,0 +1,218 @@
+/**************************************************************************
+**
+** 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 "qmljslocatordata.h"
+
+#include
+#include
+#include
+#include
+
+using namespace QmlJSTools::Internal;
+using namespace QmlJS;
+using namespace QmlJS::Interpreter;
+using namespace QmlJS::AST;
+
+LocatorData::LocatorData(QObject *parent)
+ : QObject(parent)
+{
+ QmlJS::ModelManagerInterface *manager = QmlJS::ModelManagerInterface::instance();
+
+ connect(manager, SIGNAL(documentUpdated(QmlJS::Document::Ptr)),
+ this, SLOT(onDocumentUpdated(QmlJS::Document::Ptr)));
+ connect(manager, SIGNAL(aboutToRemoveFiles(QStringList)),
+ this, SLOT(onAboutToRemoveFiles(QStringList)));
+}
+
+LocatorData::~LocatorData()
+{}
+
+namespace {
+static QString findId(UiObjectInitializer *initializer)
+{
+ if (!initializer)
+ return QString();
+ for (UiObjectMemberList *member = initializer->members; member; member = member->next) {
+ if (UiScriptBinding *script = cast(member->member)) {
+ if (!script->qualifiedId || !script->qualifiedId->name || script->qualifiedId->next)
+ continue;
+ if (script->qualifiedId->name->asString() != QLatin1String("id"))
+ continue;
+ if (ExpressionStatement *expStmt = cast(script->statement)) {
+ if (IdentifierExpression *identExp = cast(expStmt->expression)) {
+ if (identExp->name)
+ return identExp->name->asString();
+ }
+ }
+ }
+ }
+ return QString();
+}
+
+class FunctionFinder : protected AST::Visitor
+{
+ QList m_entries;
+ Document::Ptr m_doc;
+ QString m_context;
+ QString m_documentContext;
+
+public:
+ FunctionFinder()
+ {}
+
+ QList run(const Document::Ptr &doc)
+ {
+ m_doc = doc;
+ if (!doc->componentName().isEmpty()) {
+ m_documentContext = doc->componentName();
+ } else {
+ m_documentContext = QFileInfo(doc->fileName()).fileName();
+ }
+ accept(doc->ast(), m_documentContext);
+ return m_entries;
+ }
+
+protected:
+ QString contextString(const QString &extra)
+ {
+ return QString("%1, %2").arg(extra, m_documentContext);
+ }
+
+ LocatorData::Entry basicEntry(SourceLocation loc)
+ {
+ LocatorData::Entry entry;
+ entry.type = LocatorData::Function;
+ entry.extraInfo = m_context;
+ entry.fileName = m_doc->fileName();
+ entry.line = loc.startLine;
+ entry.column = loc.startColumn - 1;
+ return entry;
+ }
+
+ void accept(Node *ast, const QString &context)
+ {
+ const QString old = m_context;
+ m_context = context;
+ Node::accept(ast, this);
+ m_context = old;
+ }
+
+ bool visit(FunctionDeclaration *ast)
+ {
+ return visit(static_cast(ast));
+ }
+
+ bool visit(FunctionExpression *ast)
+ {
+ if (!ast->name)
+ return true;
+
+ LocatorData::Entry entry = basicEntry(ast->identifierToken);
+
+ entry.type = LocatorData::Function;
+ entry.displayName = ast->name->asString();
+ entry.displayName += QLatin1Char('(');
+ for (FormalParameterList *it = ast->formals; it; it = it->next) {
+ if (it != ast->formals)
+ entry.displayName += QLatin1String(", ");
+ if (it->name)
+ entry.displayName += it->name->asString();
+ }
+ entry.displayName += QLatin1Char(')');
+ entry.symbolName = entry.displayName;
+
+ m_entries += entry;
+
+ accept(ast->body, contextString(QString("function %1").arg(entry.displayName)));
+ return false;
+ }
+
+ bool visit(UiScriptBinding *ast)
+ {
+ if (!ast->qualifiedId)
+ return true;
+ const QString qualifiedIdString = Bind::toString(ast->qualifiedId);
+
+ if (cast(ast->statement)) {
+ LocatorData::Entry entry = basicEntry(ast->qualifiedId->identifierToken);
+ entry.displayName = qualifiedIdString;
+ entry.symbolName = qualifiedIdString;
+ m_entries += entry;
+ }
+
+ accept(ast->statement, contextString(Bind::toString(ast->qualifiedId)));
+ return false;
+ }
+
+ bool visit(UiObjectBinding *ast)
+ {
+ if (!ast->qualifiedTypeNameId)
+ return true;
+
+ QString context = Bind::toString(ast->qualifiedTypeNameId);
+ const QString id = findId(ast->initializer);
+ if (!id.isEmpty())
+ context = QString("%1 (%2)").arg(id, context);
+ accept(ast->initializer, contextString(context));
+ return false;
+ }
+
+ bool visit(UiObjectDefinition *ast)
+ {
+ if (!ast->qualifiedTypeNameId)
+ return true;
+
+ QString context = Bind::toString(ast->qualifiedTypeNameId);
+ const QString id = findId(ast->initializer);
+ if (!id.isEmpty())
+ context = QString("%1 (%2)").arg(id, context);
+ accept(ast->initializer, contextString(context));
+ return false;
+ }
+};
+} // anonymous namespace
+
+QHash > LocatorData::entries() const
+{
+ return m_entries;
+}
+
+void LocatorData::onDocumentUpdated(const QmlJS::Document::Ptr &doc)
+{
+ QList entries = FunctionFinder().run(doc);
+ m_entries.insert(doc->fileName(), entries);
+}
+
+void LocatorData::onAboutToRemoveFiles(const QStringList &files)
+{
+ foreach (const QString &file, files) {
+ m_entries.remove(file);
+ }
+}
+
diff --git a/src/plugins/qmljstools/qmljslocatordata.h b/src/plugins/qmljstools/qmljslocatordata.h
new file mode 100644
index 00000000000..9357fca7e95
--- /dev/null
+++ b/src/plugins/qmljstools/qmljslocatordata.h
@@ -0,0 +1,78 @@
+/**************************************************************************
+**
+** 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 QMLJSLOCATORDATA_H
+#define QMLJSLOCATORDATA_H
+
+#include
+
+#include
+#include
+
+namespace QmlJSTools {
+namespace Internal {
+
+class LocatorData : public QObject
+{
+ Q_OBJECT
+public:
+ explicit LocatorData(QObject *parent = 0);
+ ~LocatorData();
+
+ enum EntryType
+ {
+ Function,
+ };
+
+ class Entry
+ {
+ public:
+ EntryType type;
+ QString symbolName;
+ QString displayName;
+ QString extraInfo;
+ QString fileName;
+ int line;
+ int column;
+ };
+
+ QHash > entries() const;
+
+private slots:
+ void onDocumentUpdated(const QmlJS::Document::Ptr &doc);
+ void onAboutToRemoveFiles(const QStringList &files);
+
+private:
+ QHash > m_entries;
+};
+
+} // namespace Internal
+} // namespace QmlJSTools
+
+#endif // QMLJSLOCATORDATA_H
diff --git a/src/plugins/qmljstools/qmljstools-lib.pri b/src/plugins/qmljstools/qmljstools-lib.pri
index ca1997b6c9d..14e1c763de0 100644
--- a/src/plugins/qmljstools/qmljstools-lib.pri
+++ b/src/plugins/qmljstools/qmljstools-lib.pri
@@ -12,11 +12,15 @@ HEADERS += \
$$PWD/qmljsmodelmanager.h \
$$PWD/qmljsqtstylecodeformatter.h \
$$PWD/qmljsrefactoringchanges.h \
- $$PWD/qmljsplugindumper.h
+ $$PWD/qmljsplugindumper.h \
+ $$PWD/qmljsfunctionfilter.h \
+ $$PWD/qmljslocatordata.h
SOURCES += \
$$PWD/qmljstoolsplugin.cpp \
$$PWD/qmljsmodelmanager.cpp \
$$PWD/qmljsqtstylecodeformatter.cpp \
$$PWD/qmljsrefactoringchanges.cpp \
- $$PWD/qmljsplugindumper.cpp
+ $$PWD/qmljsplugindumper.cpp \
+ $$PWD/qmljsfunctionfilter.cpp \
+ $$PWD/qmljslocatordata.cpp
diff --git a/src/plugins/qmljstools/qmljstoolsplugin.cpp b/src/plugins/qmljstools/qmljstoolsplugin.cpp
index b4b13c46fdc..7c6b30584ea 100644
--- a/src/plugins/qmljstools/qmljstoolsplugin.cpp
+++ b/src/plugins/qmljstools/qmljstoolsplugin.cpp
@@ -29,6 +29,8 @@
#include "qmljstoolsplugin.h"
#include "qmljsmodelmanager.h"
+#include "qmljsfunctionfilter.h"
+#include "qmljslocatordata.h"
#include
@@ -74,6 +76,10 @@ bool QmlJSToolsPlugin::initialize(const QStringList &arguments, QString *error)
// m_modelManager, SLOT(updateSourceFiles(QStringList)));
addAutoReleasedObject(m_modelManager);
+ LocatorData *locatorData = new LocatorData;
+ addAutoReleasedObject(locatorData);
+ addAutoReleasedObject(new FunctionFilter(locatorData));
+
return true;
}