diff --git a/src/plugins/cpptools/CppTools.pluginspec b/src/plugins/cpptools/CppTools.pluginspec index bc76520f15dbdda336caa1fc4d654468c4d2d944..35492513f3678549740bb95bd284283ba1bea2b2 100644 --- a/src/plugins/cpptools/CppTools.pluginspec +++ b/src/plugins/cpptools/CppTools.pluginspec @@ -17,5 +17,6 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General <dependency name="TextEditor" version="2.1.80"/> <dependency name="ProjectExplorer" version="2.1.80"/> <dependency name="Locator" version="2.1.80"/> + <dependency name="Find" version="2.1.80"/> </dependencyList> </plugin> diff --git a/src/plugins/cpptools/cppclassesfilter.cpp b/src/plugins/cpptools/cppclassesfilter.cpp index d15901c1207a763931cc5b1fa614b6ccf3b46f69..7609949a74087ed1c5755d17066bd7e2d8eb8486 100644 --- a/src/plugins/cpptools/cppclassesfilter.cpp +++ b/src/plugins/cpptools/cppclassesfilter.cpp @@ -31,8 +31,8 @@ using namespace CppTools::Internal; -CppClassesFilter::CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager) - : CppLocatorFilter(manager, editorManager) +CppClassesFilter::CppClassesFilter(CppModelManager *manager) + : CppLocatorFilter(manager) { setShortcutString("c"); setIncludedByDefault(false); diff --git a/src/plugins/cpptools/cppclassesfilter.h b/src/plugins/cpptools/cppclassesfilter.h index 7fbbe475b07cd6f2ad63339b4c39ed77232c8b0c..417997ada02348313fdfd07d3dbf02f89a5458e1 100644 --- a/src/plugins/cpptools/cppclassesfilter.h +++ b/src/plugins/cpptools/cppclassesfilter.h @@ -40,7 +40,7 @@ class CppClassesFilter : public CppLocatorFilter Q_OBJECT public: - CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager); + CppClassesFilter(CppModelManager *manager); ~CppClassesFilter(); QString displayName() const { return tr("Classes"); } diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index c3c36dcb2ec50d73f3f3c49bc4d1d83a1bc3d4bd..451aef42613c21a85306ba16da48bc28823451d8 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -313,7 +313,11 @@ void CppFindReferences::searchFinished() void CppFindReferences::openEditor(const Find::SearchResultItem &item) { - TextEditor::BaseTextEditor::openEditorAt(item.fileName, item.lineNumber, item.searchTermStart); + if (item.path.size() > 0) { + TextEditor::BaseTextEditor::openEditorAt(item.path.first(), item.lineNumber, item.textMarkPos); + } else { + Core::EditorManager::instance()->openEditor(item.text); + } } diff --git a/src/plugins/cpptools/cppfunctionsfilter.cpp b/src/plugins/cpptools/cppfunctionsfilter.cpp index 300a9f065c8a35a73ccb39054dce3b62fbfde445..bc8f46e6b5c46ef96ea0ce0564bbf7e73859c211 100644 --- a/src/plugins/cpptools/cppfunctionsfilter.cpp +++ b/src/plugins/cpptools/cppfunctionsfilter.cpp @@ -31,8 +31,8 @@ using namespace CppTools::Internal; -CppFunctionsFilter::CppFunctionsFilter(CppModelManager *manager, Core::EditorManager *editorManager) - : CppLocatorFilter(manager, editorManager) +CppFunctionsFilter::CppFunctionsFilter(CppModelManager *manager) + : CppLocatorFilter(manager) { setShortcutString(QString(QLatin1Char('m'))); setIncludedByDefault(false); diff --git a/src/plugins/cpptools/cppfunctionsfilter.h b/src/plugins/cpptools/cppfunctionsfilter.h index 35bf55e39c0f8cd8a26e9895592f0408de22a71f..becae07b033ce4799ec983468eb5f311fec57f0a 100644 --- a/src/plugins/cpptools/cppfunctionsfilter.h +++ b/src/plugins/cpptools/cppfunctionsfilter.h @@ -40,7 +40,7 @@ class CppFunctionsFilter : public CppLocatorFilter Q_OBJECT public: - CppFunctionsFilter(CppModelManager *manager, Core::EditorManager *editorManager); + CppFunctionsFilter(CppModelManager *manager); ~CppFunctionsFilter(); QString displayName() const { return tr("Methods"); } diff --git a/src/plugins/cpptools/cpplocatorfilter.cpp b/src/plugins/cpptools/cpplocatorfilter.cpp index 913a411a7ffee0eee6efd978352fb005a2b334b5..34c696a15d8aa621b9da6d09e546e65dafdf5857 100644 --- a/src/plugins/cpptools/cpplocatorfilter.cpp +++ b/src/plugins/cpptools/cpplocatorfilter.cpp @@ -30,8 +30,6 @@ #include "cpplocatorfilter.h" #include "cppmodelmanager.h" -#include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/editormanager/ieditor.h> #include <texteditor/itexteditor.h> #include <texteditor/basetexteditor.h> @@ -39,9 +37,8 @@ using namespace CppTools::Internal; -CppLocatorFilter::CppLocatorFilter(CppModelManager *manager, Core::EditorManager *editorManager) +CppLocatorFilter::CppLocatorFilter(CppModelManager *manager) : m_manager(manager), - m_editorManager(editorManager), m_forceNewSearchList(true) { setShortcutString(QString(QLatin1Char(':'))); diff --git a/src/plugins/cpptools/cpplocatorfilter.h b/src/plugins/cpptools/cpplocatorfilter.h index 7176f7a0545f31829cab909212b70703bcb2f16e..4c4df83a236f5ad17f990e3eaf69d095b8f06ced 100644 --- a/src/plugins/cpptools/cpplocatorfilter.h +++ b/src/plugins/cpptools/cpplocatorfilter.h @@ -34,10 +34,6 @@ #include <locator/ilocatorfilter.h> -namespace Core { -class EditorManager; -} - namespace CppTools { namespace Internal { @@ -47,7 +43,7 @@ class CppLocatorFilter : public Locator::ILocatorFilter { Q_OBJECT public: - CppLocatorFilter(CppModelManager *manager, Core::EditorManager *editorManager); + CppLocatorFilter(CppModelManager *manager); ~CppLocatorFilter(); QString displayName() const { return tr("Classes and Methods"); } @@ -66,7 +62,6 @@ private slots: private: CppModelManager *m_manager; - Core::EditorManager *m_editorManager; struct Info { Info(): dirty(true) {} diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 9382bcb5cf7f2bb150a6f20f5600f017784e2c28..346d10f86c8c8f3de56f9b1085d36f64a166a6b1 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -24,7 +24,8 @@ HEADERS += completionsettingspage.h \ cppdoxygen.h \ cppfilesettingspage.h \ cppfindreferences.h \ - cppcodeformatter.h + cppcodeformatter.h \ + symbolsfindfilter.h SOURCES += completionsettingspage.cpp \ cppclassesfilter.cpp \ @@ -40,7 +41,8 @@ SOURCES += completionsettingspage.cpp \ cppfilesettingspage.cpp \ abstracteditorsupport.cpp \ cppfindreferences.cpp \ - cppcodeformatter.cpp + cppcodeformatter.cpp \ + symbolsfindfilter.cpp FORMS += completionsettingspage.ui \ cppfilesettingspage.ui diff --git a/src/plugins/cpptools/cpptools_dependencies.pri b/src/plugins/cpptools/cpptools_dependencies.pri index 7ac540da28b664fff0a7323028a79c1c94d675cc..84e655797d483194573bc8e8cade1f709e2ff4b6 100644 --- a/src/plugins/cpptools/cpptools_dependencies.pri +++ b/src/plugins/cpptools/cpptools_dependencies.pri @@ -1,3 +1,4 @@ include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus.pri) include($$IDE_SOURCE_TREE/src/plugins/projectexplorer/projectexplorer.pri) include($$IDE_SOURCE_TREE/src/plugins/texteditor/texteditor.pri) +include($$IDE_SOURCE_TREE/src/plugins/find/find.pri) diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 9b84e8012bad51e9dfde7180bfdfe8f739b3ae6e..1595fd231cda234c4d39854f3e1e265ea0f73ad2 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -37,6 +37,7 @@ #include "cppmodelmanager.h" #include "cpptoolsconstants.h" #include "cpplocatorfilter.h" +#include "symbolsfindfilter.h" #include <extensionsystem/pluginmanager.h> @@ -111,14 +112,13 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error) CppCodeCompletion *completion = new CppCodeCompletion(m_modelManager); addAutoReleasedObject(completion); - CppLocatorFilter *locatorFilter = new CppLocatorFilter(m_modelManager, - core->editorManager()); - addAutoReleasedObject(locatorFilter); - addAutoReleasedObject(new CppClassesFilter(m_modelManager, core->editorManager())); - addAutoReleasedObject(new CppFunctionsFilter(m_modelManager, core->editorManager())); + addAutoReleasedObject(new CppLocatorFilter(m_modelManager)); + addAutoReleasedObject(new CppClassesFilter(m_modelManager)); + addAutoReleasedObject(new CppFunctionsFilter(m_modelManager)); addAutoReleasedObject(new CppCurrentDocumentFilter(m_modelManager, core->editorManager())); addAutoReleasedObject(new CompletionSettingsPage); addAutoReleasedObject(new CppFileSettingsPage(m_fileSettings)); + addAutoReleasedObject(new SymbolsFindFilter(m_modelManager)); // Menus Core::ActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS); diff --git a/src/plugins/cpptools/searchsymbols.cpp b/src/plugins/cpptools/searchsymbols.cpp index ac13d4fd818dc881b470adec4630b0363c55aa62..70cd1452bd07475c70bc924e71de79da21d01c6c 100644 --- a/src/plugins/cpptools/searchsymbols.cpp +++ b/src/plugins/cpptools/searchsymbols.cpp @@ -32,10 +32,17 @@ #include <Literals.h> #include <Scope.h> #include <Names.h> +#include <cplusplus/LookupContext.h> using namespace CPlusPlus; using namespace CppTools::Internal; +SearchSymbols::SymbolTypes SearchSymbols::AllTypes = + SearchSymbols::Classes + | SearchSymbols::Functions + | SearchSymbols::Enums + | SearchSymbols::Declarations; + SearchSymbols::SearchSymbols(): symbolsToSearchFor(Classes | Functions | Enums), separateScope(false) @@ -204,13 +211,17 @@ QString SearchSymbols::symbolName(const Symbol *symbol) const void SearchSymbols::appendItem(const QString &name, const QString &info, ModelItemInfo::ItemType type, - const Symbol *symbol) + Symbol *symbol) { if (!symbol->name()) return; + QStringList fullyQualifiedName; + foreach (const Name *name, LookupContext::fullyQualifiedName(symbol)) + fullyQualifiedName.append(overview.prettyName(name)); const QIcon icon = icons.iconForSymbol(symbol); items.append(ModelItemInfo(name, info, type, + fullyQualifiedName, QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), symbol->line(), symbol->column() - 1, // 1-based vs 0-based column diff --git a/src/plugins/cpptools/searchsymbols.h b/src/plugins/cpptools/searchsymbols.h index 7c3c379e6887ae9cc75f75cc38d90b1258232dce..9a08b4dced29deed3704d8fbf81ae8d9cc113129 100644 --- a/src/plugins/cpptools/searchsymbols.h +++ b/src/plugins/cpptools/searchsymbols.h @@ -52,12 +52,14 @@ struct ModelItemInfo ModelItemInfo() : type(Declaration), - line(0) + line(0), + column(0) { } ModelItemInfo(const QString &symbolName, const QString &symbolType, ItemType type, + QStringList fullyQualifiedName, const QString &fileName, int line, int column, @@ -65,15 +67,28 @@ struct ModelItemInfo : symbolName(symbolName), symbolType(symbolType), type(type), + fullyQualifiedName(fullyQualifiedName), fileName(fileName), line(line), column(column), icon(icon) { } + ModelItemInfo(const ModelItemInfo &otherInfo) + : symbolName(otherInfo.symbolName), + symbolType(otherInfo.symbolType), + type(otherInfo.type), + fullyQualifiedName(otherInfo.fullyQualifiedName), + fileName(otherInfo.fileName), + line(otherInfo.line), + column(otherInfo.column), + icon(otherInfo.icon) + { } + QString symbolName; QString symbolType; ItemType type; + QStringList fullyQualifiedName; QString fileName; int line; int column; @@ -90,8 +105,11 @@ public: Enums = 0x4, Declarations = 0x8 }; + Q_DECLARE_FLAGS(SymbolTypes, SymbolType) + static SymbolTypes AllTypes; + SearchSymbols(); void setSymbolsToSearchFor(SymbolTypes types); @@ -121,7 +139,7 @@ protected: void appendItem(const QString &name, const QString &info, ModelItemInfo::ItemType type, - const CPlusPlus::Symbol *symbol); + CPlusPlus::Symbol *symbol); private: QString findOrInsert(const QString &s) diff --git a/src/plugins/cpptools/symbolsfindfilter.cpp b/src/plugins/cpptools/symbolsfindfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f133831a256013d33e7ec4e638cd025f84d81a1f --- /dev/null +++ b/src/plugins/cpptools/symbolsfindfilter.cpp @@ -0,0 +1,317 @@ +/************************************************************************** +** +** 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 "symbolsfindfilter.h" + +#include "cppmodelmanager.h" +#include "cpptoolsconstants.h" + +#include <coreplugin/progressmanager/progressmanager.h> +#include <coreplugin/icore.h> +#include <find/textfindconstants.h> +#include <qtconcurrent/runextensions.h> +#include <projectexplorer/projectexplorer.h> +#include <projectexplorer/session.h> +#include <projectexplorer/project.h> + +#include <QtCore/QSet> +#include <QtCore/QRegExp> +#include <QtGui/QGridLayout> +#include <QtGui/QLabel> +#include <QtGui/QButtonGroup> + +using namespace CppTools; +using namespace CppTools::Internal; + +namespace { + const char * const SETTINGS_GROUP = "CppSymbols"; + const char * const SETTINGS_SYMBOLTYPES = "SymbolsToSearchFor"; + const char * const SETTINGS_SEARCHSCOPE = "SearchScope"; + + void runSearch(QFutureInterface<Find::SearchResultItem> &future, + QString txt, Find::FindFlags findFlags, CPlusPlus::Snapshot snapshot, + SearchSymbols *search, QSet<QString> fileNames) + { + future.setProgressRange(0, snapshot.size()); + future.setProgressValue(0); + int progress = 0; + + CPlusPlus::Snapshot::const_iterator it = snapshot.begin(); + + QString findString = (findFlags & Find::FindRegularExpression ? txt : QRegExp::escape(txt)); + if (findFlags & Find::FindWholeWords) + findString = QString::fromLatin1("\\b%1\\b").arg(findString); + QRegExp matcher(findString, (findFlags & Find::FindCaseSensitively ? Qt::CaseSensitive : Qt::CaseInsensitive)); + while (it != snapshot.end() && !future.isCanceled()) { + if (fileNames.isEmpty() || fileNames.contains(it.value()->fileName())) { + QVector<Find::SearchResultItem> resultItems; + QList<ModelItemInfo> modelInfos = (*search)(it.value()); + foreach (const ModelItemInfo &info, modelInfos) { + int index = matcher.indexIn(info.symbolName); + if (index != -1) { + QStringList path = info.fullyQualifiedName.mid(0, info.fullyQualifiedName.size() - 1); + Find::SearchResultItem item; + item.path = path; + item.text = info.symbolName; + item.textMarkPos = -1; + item.textMarkLength = 0; + item.icon = info.icon; + item.lineNumber = -1; + item.userData = qVariantFromValue(info); + resultItems << item; + } + } + if (!resultItems.isEmpty()) + future.reportResults(resultItems); + } + ++it; + ++progress; + future.setProgressValue(progress); + } + } +} //namespace + +SymbolsFindFilter::SymbolsFindFilter(CppModelManager *manager) + : m_manager(manager), + m_isRunning(false), + m_enabled(true), + m_symbolsToSearch(SearchSymbols::AllTypes), + m_scope(SearchProjectsOnly) +{ + // for disabling while parser is running + connect(Core::ICore::instance()->progressManager(), SIGNAL(taskStarted(QString)), + this, SLOT(onTaskStarted(QString))); + connect(Core::ICore::instance()->progressManager(), SIGNAL(allTasksFinished(QString)), + this, SLOT(onAllTasksFinished(QString))); + + connect(&m_watcher, SIGNAL(finished()), + this, SLOT(finish())); + connect(&m_watcher, SIGNAL(resultsReadyAt(int,int)), + this, SLOT(addResults(int, int))); +} + +QString SymbolsFindFilter::id() const +{ + return QLatin1String("CppSymbols"); +} + +QString SymbolsFindFilter::displayName() const +{ + return tr("C++ Symbols"); +} + +bool SymbolsFindFilter::isEnabled() const +{ + return !m_isRunning && m_enabled; +} + +Find::FindFlags SymbolsFindFilter::supportedFindFlags() const +{ + return Find::FindCaseSensitively | Find::FindRegularExpression | Find::FindWholeWords; +} + +void SymbolsFindFilter::findAll(const QString &txt, Find::FindFlags findFlags) +{ + m_isRunning = true; + emit changed(); + Find::SearchResultWindow *window = Find::SearchResultWindow::instance(); + Find::SearchResult *result = window->startNewSearch(); + connect(result, SIGNAL(activated(Find::SearchResultItem)), this, SLOT(openEditor(Find::SearchResultItem))); + window->popup(true); + + m_search.setSymbolsToSearchFor(m_symbolsToSearch); + m_search.setSeparateScope(true); + QSet<QString> projectFileNames; + if (m_scope == SymbolsFindFilter::SearchProjectsOnly) { + foreach (ProjectExplorer::Project *project, + ProjectExplorer::ProjectExplorerPlugin::instance()->session()->projects()) { + projectFileNames += project->files(ProjectExplorer::Project::AllFiles).toSet(); + } + } + + m_watcher.setFuture(QtConcurrent::run<Find::SearchResultItem, QString, + Find::FindFlags, CPlusPlus::Snapshot, + SearchSymbols *, QSet<QString> >(runSearch, txt, findFlags, m_manager->snapshot(), + &m_search, projectFileNames)); + Core::ICore::instance()->progressManager()->addTask(m_watcher.future(), + tr("Searching"), + Find::Constants::TASK_SEARCH); +} + +void SymbolsFindFilter::addResults(int begin, int end) +{ + Find::SearchResultWindow *window = Find::SearchResultWindow::instance(); + QList<Find::SearchResultItem> items; + for (int i = begin; i < end; ++i) + items << m_watcher.resultAt(i); + window->addResults(items, Find::SearchResultWindow::AddSorted); +} + +void SymbolsFindFilter::finish() +{ + Find::SearchResultWindow *window = Find::SearchResultWindow::instance(); + window->finishSearch(); + m_isRunning = false; + emit changed(); +} + +void SymbolsFindFilter::openEditor(const Find::SearchResultItem &item) +{ + if (!item.userData.canConvert<ModelItemInfo>()) + return; + ModelItemInfo info = item.userData.value<ModelItemInfo>(); + TextEditor::BaseTextEditor::openEditorAt(info.fileName, + info.line, + info.column); +} + +QWidget *SymbolsFindFilter::createConfigWidget() +{ + return new SymbolsFindFilterConfigWidget(this); +} + +void SymbolsFindFilter::writeSettings(QSettings *settings) +{ + settings->beginGroup(QLatin1String(SETTINGS_GROUP)); + settings->setValue(SETTINGS_SYMBOLTYPES, (int)m_symbolsToSearch); + settings->setValue(SETTINGS_SEARCHSCOPE, (int)m_scope); + settings->endGroup(); +} + +void SymbolsFindFilter::readSettings(QSettings *settings) +{ + settings->beginGroup(QLatin1String(SETTINGS_GROUP)); + m_symbolsToSearch = (SearchSymbols::SymbolTypes)settings->value(SETTINGS_SYMBOLTYPES, + (int)SearchSymbols::AllTypes).toInt(); + m_scope = (SearchScope)settings->value(SETTINGS_SEARCHSCOPE, + (int)SearchProjectsOnly).toInt(); + settings->endGroup(); + emit symbolsToSearchChanged(); +} + +void SymbolsFindFilter::onTaskStarted(const QString &type) +{ + if (type == CppTools::Constants::TASK_INDEX) { + m_enabled = false; + emit changed(); + } +} + +void SymbolsFindFilter::onAllTasksFinished(const QString &type) +{ + if (type == CppTools::Constants::TASK_INDEX) { + m_enabled = true; + emit changed(); + } +} + +// #pragma mark -- SymbolsFindFilterConfigWidget + +SymbolsFindFilterConfigWidget::SymbolsFindFilterConfigWidget(SymbolsFindFilter *filter) + : m_filter(filter) +{ + connect(m_filter, SIGNAL(symbolsToSearchChanged()), this, SLOT(getState())); + + QGridLayout *layout = new QGridLayout(this); + setLayout(layout); + layout->setMargin(0); + + QLabel *typeLabel = new QLabel(tr("Types:")); + layout->addWidget(typeLabel, 0, 0); + + m_typeClasses = new QCheckBox(tr("Classes")); + layout->addWidget(m_typeClasses, 0, 1); + + m_typeMethods = new QCheckBox(tr("Methods")); + layout->addWidget(m_typeMethods, 0, 2); + + m_typeEnums = new QCheckBox(tr("Enums")); + layout->addWidget(m_typeEnums, 1, 1); + + m_typeDeclarations = new QCheckBox(tr("Declarations")); + layout->addWidget(m_typeDeclarations, 1, 2); + + // hacks to fix layouting: + typeLabel->setMinimumWidth(80); + typeLabel->setAlignment(Qt::AlignRight); + m_typeClasses->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_typeMethods->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + connect(m_typeClasses, SIGNAL(clicked(bool)), this, SLOT(setState())); + connect(m_typeMethods, SIGNAL(clicked(bool)), this, SLOT(setState())); + connect(m_typeEnums, SIGNAL(clicked(bool)), this, SLOT(setState())); + connect(m_typeDeclarations, SIGNAL(clicked(bool)), this, SLOT(setState())); + + m_searchProjectsOnly = new QRadioButton(tr("Projects Only")); + layout->addWidget(m_searchProjectsOnly, 2, 1); + + m_searchGlobal = new QRadioButton(tr("Global")); + layout->addWidget(m_searchGlobal, 2, 2); + + m_searchGroup = new QButtonGroup(this); + m_searchGroup->addButton(m_searchProjectsOnly); + m_searchGroup->addButton(m_searchGlobal); + + connect(m_searchProjectsOnly, SIGNAL(clicked(bool)), + this, SLOT(setState())); + connect(m_searchGlobal, SIGNAL(clicked(bool)), + this, SLOT(setState())); +} + +void SymbolsFindFilterConfigWidget::getState() +{ + SearchSymbols::SymbolTypes symbols = m_filter->symbolsToSearch(); + m_typeClasses->setChecked(symbols & SearchSymbols::Classes); + m_typeMethods->setChecked(symbols & SearchSymbols::Functions); + m_typeEnums->setChecked(symbols & SearchSymbols::Enums); + m_typeDeclarations->setChecked(symbols & SearchSymbols::Declarations); + + SymbolsFindFilter::SearchScope scope = m_filter->searchScope(); + m_searchProjectsOnly->setChecked(scope == SymbolsFindFilter::SearchProjectsOnly); + m_searchGlobal->setChecked(scope == SymbolsFindFilter::SearchGlobal); +} + +void SymbolsFindFilterConfigWidget::setState() const +{ + SearchSymbols::SymbolTypes symbols; + if (m_typeClasses->isChecked()) + symbols |= SearchSymbols::Classes; + if (m_typeMethods->isChecked()) + symbols |= SearchSymbols::Functions; + if (m_typeEnums->isChecked()) + symbols |= SearchSymbols::Enums; + if (m_typeDeclarations->isChecked()) + symbols |= SearchSymbols::Declarations; + m_filter->setSymbolsToSearch(symbols); + + if (m_searchProjectsOnly->isChecked()) + m_filter->setSearchScope(SymbolsFindFilter::SearchProjectsOnly); + else + m_filter->setSearchScope(SymbolsFindFilter::SearchGlobal); +} diff --git a/src/plugins/cpptools/symbolsfindfilter.h b/src/plugins/cpptools/symbolsfindfilter.h new file mode 100644 index 0000000000000000000000000000000000000000..420420dc4af7f6a4185cf256c32e56bc1559ab6f --- /dev/null +++ b/src/plugins/cpptools/symbolsfindfilter.h @@ -0,0 +1,124 @@ +/************************************************************************** +** +** 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 SYMBOLSFINDFILTER_H +#define SYMBOLSFINDFILTER_H + +#include "searchsymbols.h" + +#include <find/ifindfilter.h> +#include <find/searchresultwindow.h> + +#include <QtCore/QFutureInterface> +#include <QtCore/QFutureWatcher> +#include <QtGui/QWidget> +#include <QtGui/QCheckBox> +#include <QtGui/QRadioButton> + +namespace CppTools { +namespace Internal { + +class CppModelManager; + +class SymbolsFindFilter : public Find::IFindFilter +{ + Q_OBJECT +public: + enum SearchScope { + SearchProjectsOnly, + SearchGlobal + }; + + explicit SymbolsFindFilter(CppModelManager *manager); + + QString id() const; + QString displayName() const; + bool isEnabled() const; + Find::FindFlags supportedFindFlags() const; + + void findAll(const QString &txt, Find::FindFlags findFlags); + + QWidget *createConfigWidget(); + void writeSettings(QSettings *settings); + void readSettings(QSettings *settings); + + void setSymbolsToSearch(SearchSymbols::SymbolTypes types) { m_symbolsToSearch = types; } + SearchSymbols::SymbolTypes symbolsToSearch() const { return m_symbolsToSearch; } + + void setSearchScope(SearchScope scope) { m_scope = scope; } + SearchScope searchScope() const { return m_scope; } + +signals: + void symbolsToSearchChanged(); + +private slots: + void openEditor(const Find::SearchResultItem &item); + + void addResults(int begin, int end); + void finish(); + void onTaskStarted(const QString &type); + void onAllTasksFinished(const QString &type); + +private: + CppModelManager *m_manager; + bool m_isRunning; + bool m_enabled; + QFutureWatcher<Find::SearchResultItem> m_watcher; + SearchSymbols::SymbolTypes m_symbolsToSearch; + SearchSymbols m_search; + SearchScope m_scope; +}; + +class SymbolsFindFilterConfigWidget : public QWidget +{ + Q_OBJECT +public: + SymbolsFindFilterConfigWidget(SymbolsFindFilter *filter); + +private slots: + void setState() const; + void getState(); + +private: + SymbolsFindFilter *m_filter; + + QCheckBox *m_typeClasses; + QCheckBox *m_typeMethods; + QCheckBox *m_typeEnums; + QCheckBox *m_typeDeclarations; + + QRadioButton *m_searchGlobal; + QRadioButton *m_searchProjectsOnly; + QButtonGroup *m_searchGroup; +}; + +} // Internal +} // CppTools + +#endif // SYMBOLSFINDFILTER_H diff --git a/src/plugins/find/ifindfilter.h b/src/plugins/find/ifindfilter.h index 72d8cacdec8b277052e634171dd1d9d5ebd865fe..d45dc83a7c2fae6d17b0d801fe10219eb03e3b28 100644 --- a/src/plugins/find/ifindfilter.h +++ b/src/plugins/find/ifindfilter.h @@ -34,9 +34,9 @@ #include "textfindconstants.h" #include <QtGui/QTextDocument> +#include <QtGui/QKeySequence> QT_BEGIN_NAMESPACE -class QKeySequence; class QWidget; class QSettings; QT_END_NAMESPACE @@ -53,7 +53,7 @@ public: virtual QString id() const = 0; virtual QString displayName() const = 0; virtual bool isEnabled() const = 0; - virtual QKeySequence defaultShortcut() const = 0; + virtual QKeySequence defaultShortcut() const { return QKeySequence(); } virtual bool isReplaceSupported() const { return false; } virtual FindFlags supportedFindFlags() const; diff --git a/src/plugins/find/searchresulttreeitemdelegate.cpp b/src/plugins/find/searchresulttreeitemdelegate.cpp index d7b1972bc93a3a892a756048700568acc91b6217..379db290b1243556b33fab769d9ac494517e25ca 100644 --- a/src/plugins/find/searchresulttreeitemdelegate.cpp +++ b/src/plugins/find/searchresulttreeitemdelegate.cpp @@ -48,53 +48,77 @@ SearchResultTreeItemDelegate::SearchResultTreeItemDelegate(QObject *parent) void SearchResultTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - if (index.model()->data(index, ItemDataRoles::TypeRole).toString().compare(QLatin1String("file")) == 0) { - QItemDelegate::paint(painter, option, index); - } else { - painter->save(); + painter->save(); - QStyleOptionViewItemV3 opt = setOptions(index, option); - painter->setFont(opt.font); + QStyleOptionViewItemV3 opt = setOptions(index, option); + painter->setFont(opt.font); - QItemDelegate::drawBackground(painter, opt, index); + QItemDelegate::drawBackground(painter, opt, index); - int lineNumberAreaWidth = drawLineNumber(painter, opt, index); + int iconAreaWidth = drawIcon(painter, opt, opt.rect, index); + QRect resultRowRect(opt.rect.adjusted(iconAreaWidth, 0, 0, 0)); - QRect resultRowRect(opt.rect.adjusted(lineNumberAreaWidth, 0, 0, 0)); - QString displayString = index.model()->data(index, Qt::DisplayRole).toString(); - drawMarker(painter, index, displayString, resultRowRect); + int lineNumberAreaWidth = drawLineNumber(painter, opt, resultRowRect, index); + resultRowRect.adjust(lineNumberAreaWidth, 0, 0, 0); - // Draw the text and focus/selection - QItemDelegate::drawDisplay(painter, opt, resultRowRect, displayString); - QItemDelegate::drawFocus(painter, opt, opt.rect); + QString displayString = index.model()->data(index, Qt::DisplayRole).toString(); + drawMarker(painter, index, displayString, resultRowRect); - QVariant value = index.data(Qt::CheckStateRole); - if (value.isValid()) { - Qt::CheckState checkState = Qt::Unchecked; - checkState = static_cast<Qt::CheckState>(value.toInt()); - QRect checkRect = check(opt, opt.rect, value); + // Show number of subresults in displayString + if (index.model()->hasChildren(index)) { + displayString += QString::fromLatin1(" (") + + QString::number(index.model()->rowCount(index)) + + QLatin1Char(')'); + } + + // Draw the text and focus/selection + QItemDelegate::drawDisplay(painter, opt, resultRowRect, displayString); + QItemDelegate::drawFocus(painter, opt, opt.rect); - QRect emptyRect; - doLayout(opt, &checkRect, &emptyRect, &emptyRect, false); + QVariant value = index.data(Qt::CheckStateRole); + if (value.isValid()) { + Qt::CheckState checkState = Qt::Unchecked; + checkState = static_cast<Qt::CheckState>(value.toInt()); + QRect checkRect = check(opt, opt.rect, value); - QItemDelegate::drawCheck(painter, opt, checkRect, checkState); - } + QRect emptyRect; + doLayout(opt, &checkRect, &emptyRect, &emptyRect, false); - painter->restore(); + QItemDelegate::drawCheck(painter, opt, checkRect, checkState); } + + painter->restore(); +} + +int SearchResultTreeItemDelegate::drawIcon(QPainter *painter, const QStyleOptionViewItemV3 &option, + const QRect &rect, + const QModelIndex &index) const +{ + static const int iconWidth = 16; + static const int iconPadding = 4; + QIcon icon = index.model()->data(index, ItemDataRoles::ResultIconRole).value<QIcon>(); + if (icon.isNull()) + return 0; + QRect iconRect = rect.adjusted(iconPadding, 0, /*is set below anyhow*/0, 0); + iconRect.setWidth(iconWidth); + QItemDelegate::drawDecoration(painter, option, iconRect, icon.pixmap(iconWidth)); + return iconWidth + iconPadding; } int SearchResultTreeItemDelegate::drawLineNumber(QPainter *painter, const QStyleOptionViewItemV3 &option, + const QRect &rect, const QModelIndex &index) const { static const int lineNumberAreaHorizontalPadding = 4; - const bool isSelected = option.state & QStyle::State_Selected; int lineNumber = index.model()->data(index, ItemDataRoles::ResultLineNumberRole).toInt(); + if (lineNumber < 1) + return 0; + const bool isSelected = option.state & QStyle::State_Selected; int lineNumberDigits = (int)floor(log10((double)lineNumber)) + 1; int minimumLineNumberDigits = qMax((int)m_minimumLineNumberDigits, lineNumberDigits); int fontWidth = painter->fontMetrics().width(QString(minimumLineNumberDigits, QLatin1Char('0'))); int lineNumberAreaWidth = lineNumberAreaHorizontalPadding + fontWidth + lineNumberAreaHorizontalPadding; - QRect lineNumberAreaRect(option.rect); + QRect lineNumberAreaRect(rect); lineNumberAreaRect.setWidth(lineNumberAreaWidth); QPalette::ColorGroup cg = QPalette::Normal; @@ -123,10 +147,12 @@ int SearchResultTreeItemDelegate::drawLineNumber(QPainter *painter, const QStyle void SearchResultTreeItemDelegate::drawMarker(QPainter *painter, const QModelIndex &index, const QString text, const QRect &rect) const { - const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; int searchTermStart = index.model()->data(index, ItemDataRoles::SearchTermStartRole).toInt(); - int searchTermStartPixels = painter->fontMetrics().width(text.left(searchTermStart)); int searchTermLength = index.model()->data(index, ItemDataRoles::SearchTermLengthRole).toInt(); + if (searchTermStart < 0 || searchTermLength < 1) + return; + const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; + int searchTermStartPixels = painter->fontMetrics().width(text.left(searchTermStart)); int searchTermLengthPixels = painter->fontMetrics().width(text.mid(searchTermStart, searchTermLength)); QRect resultHighlightRect(rect); resultHighlightRect.setLeft(resultHighlightRect.left() + searchTermStartPixels + textMargin - 1); // -1: Cosmetics diff --git a/src/plugins/find/searchresulttreeitemdelegate.h b/src/plugins/find/searchresulttreeitemdelegate.h index f751d336328c18daba2d04ec67e6e893818a5aeb..d9fe62cc7f0dac7c4ef9f4bf50080af0e3562ae6 100644 --- a/src/plugins/find/searchresulttreeitemdelegate.h +++ b/src/plugins/find/searchresulttreeitemdelegate.h @@ -42,7 +42,8 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; private: - int drawLineNumber(QPainter *painter, const QStyleOptionViewItemV3 &option, const QModelIndex &index) const; + int drawIcon(QPainter *painter, const QStyleOptionViewItemV3 &option, const QRect &rect, const QModelIndex &index) const; + int drawLineNumber(QPainter *painter, const QStyleOptionViewItemV3 &option, const QRect &rect, const QModelIndex &index) const; void drawMarker(QPainter *painter, const QModelIndex &index, const QString text, const QRect &rect) const; static const int m_minimumLineNumberDigits = 6; diff --git a/src/plugins/find/searchresulttreeitemroles.h b/src/plugins/find/searchresulttreeitemroles.h index eae775192b3164a61cc768962ffaa5d66ee2c217..d79877e8de511749875ba73d07ec9b713d339333 100644 --- a/src/plugins/find/searchresulttreeitemroles.h +++ b/src/plugins/find/searchresulttreeitemroles.h @@ -30,22 +30,21 @@ #ifndef SEARCHRESULTTREEITEMROLES_H #define SEARCHRESULTTREEITEMROLES_H +#include <QtGui/QAbstractItemView> + namespace Find { namespace Internal { namespace ItemDataRoles { enum Roles { - TypeRole = Qt::UserRole, - FileNameRole, - ResultLinesCountRole, - ResultIndexRole, + ResultItemRole = Qt::UserRole, ResultLineRole, ResultLineNumberRole, + ResultIconRole, SearchTermStartRole, SearchTermLengthRole, - RowOfItem, // The ?-th child of its parent is this this item - TextRole // for files == FileNameRole, for results == ResultLineRole + RowOfItem // The ?-th child of its parent is this this item }; } // namespace Internal diff --git a/src/plugins/find/searchresulttreeitems.cpp b/src/plugins/find/searchresulttreeitems.cpp index e31a83a9827adf3389e35d1b8459607685ee833e..0738e3708250f4d9b8d5dccb79eaad97c0ea2e05 100644 --- a/src/plugins/find/searchresulttreeitems.cpp +++ b/src/plugins/find/searchresulttreeitems.cpp @@ -31,8 +31,13 @@ using namespace Find::Internal; -SearchResultTreeItem::SearchResultTreeItem(SearchResultTreeItem::ItemType type, const SearchResultTreeItem *parent) - : m_type(type), m_parent(parent), m_isUserCheckable(false), m_checkState(Qt::Unchecked) +SearchResultTreeItem::SearchResultTreeItem(const SearchResultItem &item, + const SearchResultTreeItem *parent) + : item(item), + m_parent(parent), + m_isUserCheckable(false), + m_checkState(Qt::Unchecked), + m_isGenerated(false) { } @@ -41,6 +46,11 @@ SearchResultTreeItem::~SearchResultTreeItem() clearChildren(); } +bool SearchResultTreeItem::isLeaf() const +{ + return childrenCount() == 0 && parent() != 0; +} + bool SearchResultTreeItem::isUserCheckable() const { return m_isUserCheckable; @@ -67,11 +77,6 @@ void SearchResultTreeItem::clearChildren() m_children.clear(); } -SearchResultTreeItem::ItemType SearchResultTreeItem::itemType() const -{ - return m_type; -} - int SearchResultTreeItem::childrenCount() const { return m_children.count(); @@ -92,85 +97,46 @@ const SearchResultTreeItem *SearchResultTreeItem::parent() const return m_parent; } -static bool compareResultFiles(SearchResultTreeItem *a, SearchResultTreeItem *b) -{ - return static_cast<SearchResultFile *>(a)->fileName() < - static_cast<SearchResultFile *>(b)->fileName(); -} - -int SearchResultTreeItem::insertionIndex(SearchResultFile *child) const -{ - Q_ASSERT(m_type == Root); - return qLowerBound(m_children.begin(), m_children.end(), child, compareResultFiles) - m_children.begin(); -} - -void SearchResultTreeItem::insertChild(int index, SearchResultTreeItem *child) -{ - m_children.insert(index, child); -} - -void SearchResultTreeItem::appendChild(SearchResultTreeItem *child) -{ - m_children.append(child); -} - -SearchResultTextRow::SearchResultTextRow(int index, int lineNumber, - const QString &rowText, - int searchTermStart, int searchTermLength, - const SearchResultTreeItem *parent): - SearchResultTreeItem(ResultRow, parent), - m_index(index), - m_lineNumber(lineNumber), - m_rowText(rowText), - m_searchTermStart(searchTermStart), - m_searchTermLength(searchTermLength) -{ -} - -int SearchResultTextRow::index() const -{ - return m_index; -} - -QString SearchResultTextRow::rowText() const -{ - return m_rowText; -} - -int SearchResultTextRow::lineNumber() const +static bool lessThanByText(SearchResultTreeItem *a, const QString &b) { - return m_lineNumber; + return a->item.text < b; } -int SearchResultTextRow::searchTermStart() const +int SearchResultTreeItem::insertionIndex(const QString &text, SearchResultTreeItem **existingItem) const { - return m_searchTermStart; -} - -int SearchResultTextRow::searchTermLength() const -{ - return m_searchTermLength; + QList<SearchResultTreeItem *>::const_iterator insertionPosition = + qLowerBound(m_children.begin(), m_children.end(), text, lessThanByText); + if (existingItem) { + if (insertionPosition != m_children.end() && (*insertionPosition)->item.text == text) { + (*existingItem) = (*insertionPosition); + } else { + *existingItem = 0; + } + } + return insertionPosition - m_children.begin(); } -SearchResultFile::SearchResultFile(const QString &fileName, const SearchResultTreeItem *parent): - SearchResultTreeItem(ResultFile, parent), - m_fileName(fileName) +int SearchResultTreeItem::insertionIndex(const SearchResultItem &item, SearchResultTreeItem **existingItem) const { + return insertionIndex(item.text, existingItem); } -QString SearchResultFile::fileName() const +void SearchResultTreeItem::insertChild(int index, SearchResultTreeItem *child) { - return m_fileName; + m_children.insert(index, child); } -void SearchResultFile::appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart, - int searchTermLength) +void SearchResultTreeItem::insertChild(int index, const SearchResultItem &item) { - SearchResultTreeItem *child = new SearchResultTextRow(index, lineNumber, rowText, - searchTermStart, searchTermLength, this); + SearchResultTreeItem *child = new SearchResultTreeItem(item, this); if (isUserCheckable()) { child->setIsUserCheckable(true); child->setCheckState(Qt::Checked); } - appendChild(child); + insertChild(index, child); +} + +void SearchResultTreeItem::appendChild(const SearchResultItem &item) +{ + insertChild(m_children.count(), item); } diff --git a/src/plugins/find/searchresulttreeitems.h b/src/plugins/find/searchresulttreeitems.h index 18ff329a0e082f37bede3d8a062d18eeb6d609d4..ac7fab03d175c335591b1bdda7e512f816964a7a 100644 --- a/src/plugins/find/searchresulttreeitems.h +++ b/src/plugins/find/searchresulttreeitems.h @@ -30,35 +30,31 @@ #ifndef SEARCHRESULTTREEITEMS_H #define SEARCHRESULTTREEITEMS_H +#include "searchresultwindow.h" + #include <QtCore/QString> #include <QtCore/QList> #include <QtCore/qnamespace.h> +#include <QtGui/QIcon> namespace Find { namespace Internal { -class SearchResultTreeItem; -class SearchResultFile; - class SearchResultTreeItem { public: - enum ItemType - { - Root, - ResultRow, - ResultFile - }; - - SearchResultTreeItem(ItemType type = Root, const SearchResultTreeItem *parent = NULL); + SearchResultTreeItem(const SearchResultItem &item = SearchResultItem(), + const SearchResultTreeItem *parent = NULL); virtual ~SearchResultTreeItem(); - ItemType itemType() const; + bool isLeaf() const; const SearchResultTreeItem *parent() const; SearchResultTreeItem *childAt(int index) const; - int insertionIndex(SearchResultFile *child) const; + int insertionIndex(const QString &text, SearchResultTreeItem **existingItem) const; + int insertionIndex(const SearchResultItem &item, SearchResultTreeItem **existingItem) const; void insertChild(int index, SearchResultTreeItem *child); - void appendChild(SearchResultTreeItem *child); + void insertChild(int index, const SearchResultItem &item); + void appendChild(const SearchResultItem &item); int childrenCount() const; int rowOfItem() const; void clearChildren(); @@ -69,43 +65,17 @@ public: Qt::CheckState checkState() const; void setCheckState(Qt::CheckState checkState); + bool isGenerated() const { return m_isGenerated; } + void setGenerated(bool value) { m_isGenerated = value; } + + SearchResultItem item; + private: - ItemType m_type; const SearchResultTreeItem *m_parent; QList<SearchResultTreeItem *> m_children; bool m_isUserCheckable; Qt::CheckState m_checkState; -}; - -class SearchResultTextRow : public SearchResultTreeItem -{ -public: - SearchResultTextRow(int index, int lineNumber, const QString &rowText, int searchTermStart, - int searchTermLength, const SearchResultTreeItem *parent); - int index() const; - QString rowText() const; - int lineNumber() const; - int searchTermStart() const; - int searchTermLength() const; - -private: - int m_index; - int m_lineNumber; - QString m_rowText; - int m_searchTermStart; - int m_searchTermLength; -}; - -class SearchResultFile : public SearchResultTreeItem -{ -public: - SearchResultFile(const QString &fileName, const SearchResultTreeItem *parent); - QString fileName() const; - void appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart, - int searchTermLength); - -private: - QString m_fileName; + bool m_isGenerated; }; } // namespace Internal diff --git a/src/plugins/find/searchresulttreemodel.cpp b/src/plugins/find/searchresulttreemodel.cpp index 080edd5c5851f2e8360e291b66cdab965416d7bd..705dedcf4e678d1a99bf01bc77529880c44c5996 100644 --- a/src/plugins/find/searchresulttreemodel.cpp +++ b/src/plugins/find/searchresulttreemodel.cpp @@ -46,7 +46,7 @@ using namespace Find::Internal; SearchResultTreeModel::SearchResultTreeModel(QObject *parent) : QAbstractItemModel(parent) - , m_lastAddedResultFile(0) + , m_currentParent(0) , m_showReplaceUI(false) { m_rootItem = new SearchResultTreeItem; @@ -70,13 +70,13 @@ void SearchResultTreeModel::setTextEditorFont(const QFont &font) layoutChanged(); } -Qt::ItemFlags SearchResultTreeModel::flags(const QModelIndex &index) const +Qt::ItemFlags SearchResultTreeModel::flags(const QModelIndex &idx) const { - Qt::ItemFlags flags = QAbstractItemModel::flags(index); + Qt::ItemFlags flags = QAbstractItemModel::flags(idx); - if (index.isValid()) { - if (const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer())) { - if (item->itemType() == SearchResultTreeItem::ResultRow && item->isUserCheckable()) { + if (idx.isValid()) { + if (const SearchResultTreeItem *item = treeItemAtIndex(idx)) { + if (item->isLeaf() && item->isUserCheckable()) { flags |= Qt::ItemIsUserCheckable; } } @@ -96,7 +96,7 @@ QModelIndex SearchResultTreeModel::index(int row, int column, if (!parent.isValid()) parentItem = m_rootItem; else - parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer()); + parentItem = treeItemAtIndex(parent); const SearchResultTreeItem *childItem = parentItem->childAt(row); if (childItem) @@ -105,12 +105,17 @@ QModelIndex SearchResultTreeModel::index(int row, int column, return QModelIndex(); } -QModelIndex SearchResultTreeModel::parent(const QModelIndex &index) const +QModelIndex SearchResultTreeModel::index(SearchResultTreeItem *item) const { - if (!index.isValid()) + return createIndex(item->rowOfItem(), 0, (void *)item); +} + +QModelIndex SearchResultTreeModel::parent(const QModelIndex &idx) const +{ + if (!idx.isValid()) return QModelIndex(); - const SearchResultTreeItem *childItem = static_cast<const SearchResultTreeItem*>(index.internalPointer()); + const SearchResultTreeItem *childItem = treeItemAtIndex(idx); const SearchResultTreeItem *parentItem = childItem->parent(); if (parentItem == m_rootItem) @@ -129,7 +134,7 @@ int SearchResultTreeModel::rowCount(const QModelIndex &parent) const if (!parent.isValid()) parentItem = m_rootItem; else - parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer()); + parentItem = treeItemAtIndex(parent); return parentItem->childrenCount(); } @@ -140,48 +145,41 @@ int SearchResultTreeModel::columnCount(const QModelIndex &parent) const return 1; } -QVariant SearchResultTreeModel::data(const QModelIndex &index, int role) const +SearchResultTreeItem *SearchResultTreeModel::treeItemAtIndex(const QModelIndex &idx) const { - if (!index.isValid()) - return QVariant(); + return static_cast<SearchResultTreeItem*>(idx.internalPointer()); +} - const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer()); +QVariant SearchResultTreeModel::data(const QModelIndex &idx, int role) const +{ + if (!idx.isValid()) + return QVariant(); QVariant result; - if (role == Qt::SizeHintRole) - { + if (role == Qt::SizeHintRole) { + // TODO we should not use editor font height if that is not used by any item const int appFontHeight = QApplication::fontMetrics().height(); const int editorFontHeight = QFontMetrics(m_textEditorFont).height(); result = QSize(0, qMax(appFontHeight, editorFontHeight)); - } - else if (item->itemType() == SearchResultTreeItem::ResultRow) - { - const SearchResultTextRow *row = static_cast<const SearchResultTextRow *>(item); - result = data(row, role); - } - else if (item->itemType() == SearchResultTreeItem::ResultFile) - { - const SearchResultFile *file = static_cast<const SearchResultFile *>(item); - result = data(file, role); + } else { + result = data(treeItemAtIndex(idx), role); } return result; } -bool SearchResultTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool SearchResultTreeModel::setData(const QModelIndex &idx, const QVariant &value, int role) { if (role == Qt::CheckStateRole) { - SearchResultTreeItem *item = static_cast<SearchResultTreeItem*>(index.internalPointer()); - SearchResultTextRow *row = static_cast<SearchResultTextRow *>(item); Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt()); - row->setCheckState(checkState); + treeItemAtIndex(idx)->setCheckState(checkState); return true; } - return QAbstractItemModel::setData(index, value, role); + return QAbstractItemModel::setData(idx, value, role); } -QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) const +QVariant SearchResultTreeModel::data(const SearchResultTreeItem *row, int role) const { QVariant result; @@ -192,39 +190,40 @@ QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) c result = row->checkState(); break; case Qt::ToolTipRole: - result = row->rowText().trimmed(); + result = row->item.text.trimmed(); break; case Qt::FontRole: - result = m_textEditorFont; + if (row->item.useTextEditorFont) + result = m_textEditorFont; + else + result = QVariant(); break; - case ItemDataRoles::TextRole: case ItemDataRoles::ResultLineRole: case Qt::DisplayRole: - result = row->rowText(); + result = row->item.text; break; - case ItemDataRoles::ResultIndexRole: - result = row->index(); + case ItemDataRoles::ResultItemRole: + result = qVariantFromValue(row->item); break; case ItemDataRoles::ResultLineNumberRole: - result = row->lineNumber(); + result = row->item.lineNumber; + break; + case ItemDataRoles::ResultIconRole: + result = row->item.icon; break; case ItemDataRoles::SearchTermStartRole: - result = row->searchTermStart(); + result = row->item.textMarkPos; break; case ItemDataRoles::SearchTermLengthRole: - result = row->searchTermLength(); - break; - case ItemDataRoles::TypeRole: - result = QLatin1String("row"); + result = row->item.textMarkLength; break; - case ItemDataRoles::FileNameRole: - { - if (row->parent()->itemType() == SearchResultTreeItem::ResultFile) { - const SearchResultFile *file = static_cast<const SearchResultFile *>(row->parent()); - result = file->fileName(); - } - break; - } +// TODO this looks stupid in case of symbol tree, is it necessary? +// case Qt::BackgroundRole: +// if (row->parent() && row->parent()->parent()) +// result = QVariant(); +// else +// result = QApplication::palette().base().color().darker(105); +// break; default: result = QVariant(); break; @@ -233,42 +232,6 @@ QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) c return result; } -QVariant SearchResultTreeModel::data(const SearchResultFile *file, int role) const -{ - switch (role) - { -#if 0 - case Qt::CheckStateRole: - if (file->isUserCheckable()) - return QVariant(file->checkState()); -#endif - case Qt::BackgroundRole: { - const QColor baseColor = QApplication::palette().base().color(); - return QVariant(baseColor.darker(105)); - break; - } - case Qt::DisplayRole: { - const QString result = - QDir::toNativeSeparators(file->fileName()) - + QString::fromLatin1(" (") - + QString::number(file->childrenCount()) - + QLatin1Char(')'); - return QVariant(result); - } - case ItemDataRoles::TextRole: - case ItemDataRoles::FileNameRole: - case Qt::ToolTipRole: - return QVariant(QDir::toNativeSeparators(file->fileName())); - case ItemDataRoles::ResultLinesCountRole: - return QVariant(file->childrenCount()); - case ItemDataRoles::TypeRole: - return QVariant(QLatin1String("file")); - default: - break; - } - return QVariant(); -} - QVariant SearchResultTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { @@ -279,144 +242,196 @@ QVariant SearchResultTreeModel::headerData(int section, Qt::Orientation orientat } /** - * Adds a file to the list of results and returns the index at which it was inserted. + * Makes sure that the nodes for a specific path exist and sets + * m_currentParent to the last final */ -int SearchResultTreeModel::addResultFile(const QString &fileName) +QSet<SearchResultTreeItem *> SearchResultTreeModel::addPath(const QStringList &path) { -#ifdef Q_OS_WIN - if (fileName.contains(QLatin1Char('\\'))) - qWarning("SearchResultTreeModel::appendResultFile: File name with native separators added %s.\n", qPrintable(fileName)); -#endif - m_lastAddedResultFile = new SearchResultFile(fileName, m_rootItem); - - if (m_showReplaceUI) { - m_lastAddedResultFile->setIsUserCheckable(true); - m_lastAddedResultFile->setCheckState(Qt::Checked); + QSet<SearchResultTreeItem *> pathNodes; + SearchResultTreeItem *currentItem = m_rootItem; + QModelIndex currentItemIndex = QModelIndex(); + SearchResultTreeItem *partItem = 0; + QStringList currentPath; + foreach (const QString &part, path) { + const int insertionIndex = currentItem->insertionIndex(part, &partItem); + if (!partItem) { + SearchResultItem item; + item.path = currentPath; + item.text = part; + partItem = new SearchResultTreeItem(item, currentItem); + if (m_showReplaceUI) { + partItem->setIsUserCheckable(true); + partItem->setCheckState(Qt::Checked); + } + partItem->setGenerated(true); + beginInsertRows(currentItemIndex, insertionIndex, insertionIndex); + currentItem->insertChild(insertionIndex, partItem); + endInsertRows(); + } + pathNodes << partItem; + currentItemIndex = index(insertionIndex, 0, currentItemIndex); + currentItem = partItem; + currentPath << part; } - const int index = m_rootItem->insertionIndex(m_lastAddedResultFile); - beginInsertRows(QModelIndex(), index, index); - m_rootItem->insertChild(index, m_lastAddedResultFile); - endInsertRows(); - return index; + m_currentParent = currentItem; + m_currentPath = currentPath; + m_currentIndex = currentItemIndex; + return pathNodes; } -void SearchResultTreeModel::appendResultLines(const QList<SearchResultItem> &items) +void SearchResultTreeModel::addResultsToCurrentParent(const QList<SearchResultItem> &items, SearchResultWindow::AddMode mode) { - if (!m_lastAddedResultFile) + if (!m_currentParent) return; - QModelIndex lastFile(createIndex(m_lastAddedResultFile->rowOfItem(), 0, m_lastAddedResultFile)); - - beginInsertRows(lastFile, m_lastAddedResultFile->childrenCount(), m_lastAddedResultFile->childrenCount() + items.count()); - foreach (const SearchResultItem &item, items) { - m_lastAddedResultFile->appendResultLine(item.index, - item.lineNumber, - item.lineText, - item.searchTermStart, - item.searchTermLength); + if (mode == SearchResultWindow::AddOrdered) { + // this is the mode for e.g. text search + beginInsertRows(m_currentIndex, m_currentParent->childrenCount(), m_currentParent->childrenCount() + items.count()); + foreach (const SearchResultItem &item, items) { + m_currentParent->appendChild(item); + } + endInsertRows(); + } else if (mode == SearchResultWindow::AddSorted) { + foreach (const SearchResultItem &item, items) { + SearchResultTreeItem *existingItem; + const int insertionIndex = m_currentParent->insertionIndex(item, &existingItem); + if (existingItem) { + existingItem->setGenerated(false); + existingItem->item = item; + QModelIndex itemIndex = m_currentIndex.child(insertionIndex, 0); + dataChanged(itemIndex, itemIndex); + } else { + beginInsertRows(m_currentIndex, insertionIndex, insertionIndex); + m_currentParent->insertChild(insertionIndex, item); + endInsertRows(); + } + } } - endInsertRows(); + dataChanged(m_currentIndex, m_currentIndex); // Make sure that the number after the file name gets updated +} - dataChanged(lastFile, lastFile); // Make sure that the number after the file name gets updated +static bool lessThanByPath(const SearchResultItem &a, const SearchResultItem &b) +{ + if (a.path.size() < b.path.size()) + return true; + if (a.path.size() > b.path.size()) + return false; + for (int i = 0; i < a.path.size(); ++i) { + if (a.path.at(i) < b.path.at(i)) + return true; + if (a.path.at(i) > b.path.at(i)) + return false; + } + return false; } /** - * Adds the search result to the list of results, creating a new file entry when - * necessary. Returns the insertion index when a new file entry was created. + * Adds the search result to the list of results, creating nodes for the path when + * necessary. */ -QList<int> SearchResultTreeModel::addResultLines(const QList<SearchResultItem> &items) +QList<QModelIndex> SearchResultTreeModel::addResults(const QList<SearchResultItem> &items, SearchResultWindow::AddMode mode) { - QList<int> insertedFileIndices; + QSet<SearchResultTreeItem *> pathNodes; + QList<SearchResultItem> sortedItems = items; + qStableSort(sortedItems.begin(), sortedItems.end(), lessThanByPath); QList<SearchResultItem> itemSet; - foreach (const SearchResultItem &item, items) { - if (!m_lastAddedResultFile || (m_lastAddedResultFile->fileName() != item.fileName)) { + foreach (const SearchResultItem &item, sortedItems) { + if (!m_currentParent || (m_currentPath != item.path)) { + // first add all the items from before if (!itemSet.isEmpty()) { - appendResultLines(itemSet); + addResultsToCurrentParent(itemSet, mode); itemSet.clear(); } - insertedFileIndices << addResultFile(item.fileName); + // switch parent + pathNodes += addPath(item.path); } itemSet << item; } if (!itemSet.isEmpty()) { - appendResultLines(itemSet); + addResultsToCurrentParent(itemSet, mode); itemSet.clear(); } - return insertedFileIndices; + QList<QModelIndex> pathIndices; + foreach (SearchResultTreeItem *item, pathNodes) + pathIndices << index(item); + return pathIndices; } void SearchResultTreeModel::clear() { - m_lastAddedResultFile = NULL; + m_currentParent = NULL; m_rootItem->clearChildren(); reset(); } -QModelIndex SearchResultTreeModel::next(const QModelIndex &idx, bool includeTopLevel) const +QModelIndex SearchResultTreeModel::nextIndex(const QModelIndex &idx) const { - QModelIndex parent = idx.parent(); - if (parent.isValid()) { - int row = idx.row(); - if (row + 1 < rowCount(parent)) { - // Same parent - return index(row + 1, 0, parent); + // pathological + if (!idx.isValid()) + return index(0, 0); + + if (rowCount(idx) > 0) { + // node with children + return idx.child(0, 0); + } + // leaf node + QModelIndex nextIndex; + QModelIndex current = idx; + while (!nextIndex.isValid()) { + int row = current.row(); + current = current.parent(); + if (row + 1 < rowCount(current)) { + // Same parent has another child + nextIndex = index(row + 1, 0, current); } else { - // Next parent - int parentRow = parent.row(); - QModelIndex nextParent; - if (parentRow + 1 < rowCount()) { - nextParent = index(parentRow + 1, 0); - } else { - // Wrap around - nextParent = index(0,0); + // go up one parent + if (!current.isValid()) { + nextIndex = index(0, 0); } - if (includeTopLevel) - return nextParent; - return nextParent.child(0, 0); } - } else { - // We are on a top level item - return idx.child(0,0); } - return QModelIndex(); + return nextIndex; } -QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx, bool includeTopLevel) const +QModelIndex SearchResultTreeModel::next(const QModelIndex &idx, bool includeGenerated) const { - QModelIndex parent = idx.parent(); - if (parent.isValid()) { - int row = idx.row(); - if (row > 0) { - // Same parent - return index(row - 1, 0, parent); - } else { - if (includeTopLevel) - return parent; - // Prev parent - int parentRow = parent.row(); - QModelIndex prevParent; - if (parentRow > 0 ) { - prevParent = index(parentRow - 1, 0); - } else { - // Wrap around - prevParent = index(rowCount() - 1, 0); - } - return prevParent.child(rowCount(prevParent) - 1, 0); - } - } else { - // We are on a top level item - int row = idx.row(); - QModelIndex prevParent; + QModelIndex value = idx; + do { + value = nextIndex(value); + } while (value != idx && !includeGenerated && treeItemAtIndex(value)->isGenerated()); + return value; +} + +QModelIndex SearchResultTreeModel::prevIndex(const QModelIndex &idx) const +{ + QModelIndex current = idx; + bool checkForChildren = true; + if (current.isValid()) { + int row = current.row(); if (row > 0) { - prevParent = index(row - 1, 0); + current = index(row - 1, 0, current.parent()); } else { - // wrap around - prevParent = index(rowCount() -1, 0); + current = current.parent(); + checkForChildren = !current.isValid(); + } + } + if (checkForChildren) { + // traverse down the hierarchy + while (int rc = rowCount(current)) { + current = index(rc - 1, 0, current); } - return prevParent.child(rowCount(prevParent) -1,0); } - return QModelIndex(); + return current; +} + +QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx, bool includeGenerated) const +{ + QModelIndex value = idx; + do { + value = prevIndex(value); + } while (value != idx && !includeGenerated && treeItemAtIndex(value)->isGenerated()); + return value; } QModelIndex SearchResultTreeModel::find(const QRegExp &expr, const QModelIndex &index, QTextDocument::FindFlags flags) @@ -431,7 +446,7 @@ QModelIndex SearchResultTreeModel::find(const QRegExp &expr, const QModelIndex & else currentIndex = next(currentIndex, true); if (currentIndex.isValid()) { - const QString &text = data(currentIndex, ItemDataRoles::TextRole).toString(); + const QString &text = data(currentIndex, ItemDataRoles::ResultLineRole).toString(); if (expr.indexIn(text) != -1) resultIndex = currentIndex; } @@ -452,7 +467,7 @@ QModelIndex SearchResultTreeModel::find(const QString &term, const QModelIndex & else currentIndex = next(currentIndex, true); if (currentIndex.isValid()) { - const QString &text = data(currentIndex, ItemDataRoles::TextRole).toString(); + const QString &text = data(currentIndex, ItemDataRoles::ResultLineRole).toString(); QTextDocument doc(text); if (!doc.find(term, 0, flags).isNull()) resultIndex = currentIndex; diff --git a/src/plugins/find/searchresulttreemodel.h b/src/plugins/find/searchresulttreemodel.h index d143c1213a1d8a9003d3c2708110897087bd2b5a..ef0cfefce8e9ef18cfe1cf0acab0924010ef36a3 100644 --- a/src/plugins/find/searchresulttreemodel.h +++ b/src/plugins/find/searchresulttreemodel.h @@ -41,8 +41,6 @@ namespace Find { namespace Internal { class SearchResultTreeItem; -class SearchResultTextRow; -class SearchResultFile; class SearchResultTreeModel : public QAbstractItemModel { @@ -64,10 +62,10 @@ public: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QModelIndex next(const QModelIndex &idx, bool includeTopLevel = false) const; - QModelIndex prev(const QModelIndex &idx, bool includeTopLevel = false) const; + QModelIndex next(const QModelIndex &idx, bool includeGenerated = false) const; + QModelIndex prev(const QModelIndex &idx, bool includeGenerated = false) const; - QList<int> addResultLines(const QList<SearchResultItem> &items); + QList<QModelIndex> addResults(const QList<SearchResultItem> &items, SearchResultWindow::AddMode mode); QModelIndex find(const QRegExp &expr, const QModelIndex &index, QTextDocument::FindFlags flags); QModelIndex find(const QString &term, const QModelIndex &index, QTextDocument::FindFlags flags); @@ -80,15 +78,18 @@ public slots: void clear(); private: - void appendResultLines(const QList<SearchResultItem> &items); - int addResultFile(const QString &fileName); - QVariant data(const SearchResultTextRow *row, int role) const; - QVariant data(const SearchResultFile *file, int role) const; - void initializeData(); - void disposeData(); + QModelIndex index(SearchResultTreeItem *item) const; + void addResultsToCurrentParent(const QList<SearchResultItem> &items, SearchResultWindow::AddMode mode); + QSet<SearchResultTreeItem *> addPath(const QStringList &path); + QVariant data(const SearchResultTreeItem *row, int role) const; + QModelIndex nextIndex(const QModelIndex &idx) const; + QModelIndex prevIndex(const QModelIndex &idx) const; + SearchResultTreeItem *treeItemAtIndex(const QModelIndex &idx) const; SearchResultTreeItem *m_rootItem; - SearchResultFile *m_lastAddedResultFile; + SearchResultTreeItem *m_currentParent; + QModelIndex m_currentIndex; + QStringList m_currentPath; // the path that belongs to the current parent QFont m_textEditorFont; bool m_showReplaceUI; }; diff --git a/src/plugins/find/searchresulttreeview.cpp b/src/plugins/find/searchresulttreeview.cpp index 650cfe0b1a3a70d8bb1fe54723916da99e840689..d97451d1f79294f8359e4574eb66a4a4250b5a67 100644 --- a/src/plugins/find/searchresulttreeview.cpp +++ b/src/plugins/find/searchresulttreeview.cpp @@ -46,6 +46,7 @@ SearchResultTreeView::SearchResultTreeView(QWidget *parent) setItemDelegate(new SearchResultTreeItemDelegate(this)); setIndentation(14); setUniformRowHeights(true); + setExpandsOnDoubleClick(false); header()->hide(); connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(emitJumpToSearchResult(QModelIndex))); @@ -66,24 +67,20 @@ void SearchResultTreeView::clear() m_model->clear(); } -void SearchResultTreeView::appendResultLines(const QList<Find::SearchResultItem> &items) +void SearchResultTreeView::addResults(const QList<Find::SearchResultItem> &items, SearchResultWindow::AddMode mode) { - const QList<int> &insertedFileIndices = m_model->addResultLines(items); - if (m_autoExpandResults && !insertedFileIndices.isEmpty()) { - foreach (int index, insertedFileIndices) - setExpanded(model()->index(index, 0), true); + QList<QModelIndex> addedParents = m_model->addResults(items, mode); + if (m_autoExpandResults && !addedParents.isEmpty()) { + foreach (const QModelIndex &index, addedParents) + setExpanded(index, true); } } void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index) { - if (model()->data(index, ItemDataRoles::TypeRole).toString().compare(QLatin1String("row")) != 0) - return; - - int position = model()->data(index, ItemDataRoles::ResultIndexRole).toInt(); - int checked = model()->data(index, Qt::CheckStateRole).toBool(); + SearchResultItem item = model()->data(index, ItemDataRoles::ResultItemRole).value<SearchResultItem>(); - emit jumpToSearchResult(position, checked); + emit jumpToSearchResult(item); } void SearchResultTreeView::keyPressEvent(QKeyEvent *e) diff --git a/src/plugins/find/searchresulttreeview.h b/src/plugins/find/searchresulttreeview.h index ff9f9984e5844c63d1f57a7fd196f1e8d18da810..64e8ecc86c8d84857dae204294d6af446db01b44 100644 --- a/src/plugins/find/searchresulttreeview.h +++ b/src/plugins/find/searchresulttreeview.h @@ -50,10 +50,10 @@ public: void setTextEditorFont(const QFont &font); SearchResultTreeModel *model() const; - void appendResultLines(const QList<Find::SearchResultItem> &items); + void addResults(const QList<Find::SearchResultItem> &items, SearchResultWindow::AddMode mode); signals: - void jumpToSearchResult(int index, bool checked); + void jumpToSearchResult(const SearchResultItem &item); public slots: void clear(); diff --git a/src/plugins/find/searchresultwindow.cpp b/src/plugins/find/searchresultwindow.cpp index 90b1cc75633f5aad4aa621f524bd6893b8834ed3..2dd2cd6228b5708e902619d9c325c0d006162ba2 100644 --- a/src/plugins/find/searchresultwindow.cpp +++ b/src/plugins/find/searchresultwindow.cpp @@ -45,6 +45,7 @@ #include <QtCore/QTextStream> #include <QtCore/QSettings> #include <QtCore/QDebug> +#include <QtCore/QDir> #include <QtGui/QListWidget> #include <QtGui/QToolButton> #include <QtGui/QLineEdit> @@ -56,7 +57,6 @@ static const char SETTINGSKEYSECTIONNAME[] = "SearchResults"; static const char SETTINGSKEYEXPANDRESULTS[] = "ExpandResults"; - namespace Find { namespace Internal { @@ -204,13 +204,14 @@ namespace Internal { static const bool m_initiallyExpand = false; QStackedWidget *m_widget; SearchResult *m_currentSearch; - QList<SearchResultItem> m_items; + int m_itemCount; bool m_isShowingReplaceUI; bool m_focusReplaceEdit; }; SearchResultWindowPrivate::SearchResultWindowPrivate() : m_currentSearch(0), + m_itemCount(0), m_isShowingReplaceUI(false), m_focusReplaceEdit(false) { @@ -338,8 +339,8 @@ SearchResultWindow::SearchResultWindow() : d(new SearchResultWindowPrivate) d->m_replaceButton->setAutoRaise(true); d->m_replaceTextEdit->setTabOrder(d->m_replaceTextEdit, d->m_searchResultTreeView); - connect(d->m_searchResultTreeView, SIGNAL(jumpToSearchResult(int,bool)), - this, SLOT(handleJumpToSearchResult(int,bool))); + connect(d->m_searchResultTreeView, SIGNAL(jumpToSearchResult(SearchResultItem)), + this, SLOT(handleJumpToSearchResult(SearchResultItem))); connect(d->m_expandCollapseAction, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool))); connect(d->m_replaceTextEdit, SIGNAL(returnPressed()), this, SLOT(handleReplaceButton())); connect(d->m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton())); @@ -359,7 +360,7 @@ SearchResultWindow::~SearchResultWindow() d->m_currentSearch = 0; delete d->m_widget; d->m_widget = 0; - d->m_items.clear(); + d->m_itemCount = 0; delete d; } @@ -428,13 +429,13 @@ QList<SearchResultItem> SearchResultWindow::checkedItems() const const int fileCount = model->rowCount(QModelIndex()); for (int i = 0; i < fileCount; ++i) { QModelIndex fileIndex = model->index(i, 0, QModelIndex()); - Internal::SearchResultFile *fileItem = static_cast<Internal::SearchResultFile *>(fileIndex.internalPointer()); + Internal::SearchResultTreeItem *fileItem = static_cast<Internal::SearchResultTreeItem *>(fileIndex.internalPointer()); Q_ASSERT(fileItem != 0); for (int rowIndex = 0; rowIndex < fileItem->childrenCount(); ++rowIndex) { QModelIndex textIndex = model->index(rowIndex, 0, fileIndex); - Internal::SearchResultTextRow *rowItem = static_cast<Internal::SearchResultTextRow *>(textIndex.internalPointer()); + Internal::SearchResultTreeItem *rowItem = static_cast<Internal::SearchResultTreeItem *>(textIndex.internalPointer()); if (rowItem->checkState()) - result << d->m_items.at(rowItem->index()); + result << rowItem->item; } } return result; @@ -492,7 +493,7 @@ SearchResult *SearchResultWindow::startNewSearch(SearchMode searchOrSearchAndRep */ void SearchResultWindow::finishSearch() { - if (d->m_items.count()) { + if (d->m_itemCount > 0) { d->m_replaceButton->setEnabled(true); } else { showNoMatchesFound(); @@ -509,7 +510,7 @@ void SearchResultWindow::clearContents() d->m_replaceButton->setEnabled(false); d->m_replaceTextEdit->clear(); d->m_searchResultTreeView->clear(); - d->m_items.clear(); + d->m_itemCount = 0; d->m_widget->setCurrentWidget(d->m_searchResultTreeView); navigateStateChanged(); } @@ -541,7 +542,7 @@ bool SearchResultWindow::isEmpty() const */ int SearchResultWindow::numberOfResults() const { - return d->m_items.count(); + return d->m_itemCount; } /*! @@ -559,7 +560,7 @@ bool SearchResultWindow::hasFocus() */ bool SearchResultWindow::canFocus() { - return !d->m_items.isEmpty(); + return d->m_itemCount > 0; } /*! @@ -568,7 +569,7 @@ bool SearchResultWindow::canFocus() */ void SearchResultWindow::setFocus() { - if (!d->m_items.isEmpty()) { + if (d->m_itemCount > 0) { if (!d->m_isShowingReplaceUI) { d->m_searchResultTreeView->setFocus(); } else { @@ -597,10 +598,10 @@ void SearchResultWindow::setTextEditorFont(const QFont &font) \fn void SearchResultWindow::handleJumpToSearchResult(int index, bool) \internal */ -void SearchResultWindow::handleJumpToSearchResult(int index, bool /* checked */) +void SearchResultWindow::handleJumpToSearchResult(const SearchResultItem &item) { QTC_ASSERT(d->m_currentSearch, return); - d->m_currentSearch->activated(d->m_items.at(index)); + d->m_currentSearch->activated(item); } /*! @@ -619,13 +620,14 @@ void SearchResultWindow::addResult(const QString &fileName, int lineNumber, cons int searchTermStart, int searchTermLength, const QVariant &userData) { SearchResultItem item; - item.fileName = fileName; + item.path = QStringList() << QDir::toNativeSeparators(fileName); item.lineNumber = lineNumber; - item.lineText = rowText; - item.searchTermStart = searchTermStart; - item.searchTermLength = searchTermLength; + item.text = rowText; + item.textMarkPos = searchTermStart; + item.textMarkLength = searchTermLength; + item.useTextEditorFont = true; item.userData = userData; - addResults(QList<SearchResultItem>() << item); + addResults(QList<SearchResultItem>() << item, AddOrdered); } /*! @@ -635,17 +637,11 @@ void SearchResultWindow::addResult(const QString &fileName, int lineNumber, cons \sa addResult() */ -void SearchResultWindow::addResults(QList<SearchResultItem> &items) +void SearchResultWindow::addResults(QList<SearchResultItem> &items, AddMode mode) { - int index = d->m_items.size(); - bool firstItems = (index == 0); - for (int i = 0; i < items.size(); ++i) { - items[i].index = index; - ++index; - } - - d->m_items << items; - d->m_searchResultTreeView->appendResultLines(items); + bool firstItems = (d->m_itemCount == 0); + d->m_itemCount += items.size(); + d->m_searchResultTreeView->addResults(items, mode); if (firstItems) { d->m_replaceTextEdit->setEnabled(true); // We didn't have an item before, set the focus to the search widget @@ -713,7 +709,7 @@ int SearchResultWindow::priorityInStatusBar() const */ bool SearchResultWindow::canNext() { - return d->m_items.count() > 0; + return d->m_itemCount > 0; } /*! @@ -722,7 +718,7 @@ bool SearchResultWindow::canNext() */ bool SearchResultWindow::canPrevious() { - return d->m_items.count() > 0; + return d->m_itemCount > 0; } /*! @@ -731,7 +727,7 @@ bool SearchResultWindow::canPrevious() */ void SearchResultWindow::goToNext() { - if (d->m_items.count() == 0) + if (d->m_itemCount == 0) return; QModelIndex idx = d->m_searchResultTreeView->model()->next(d->m_searchResultTreeView->currentIndex()); if (idx.isValid()) { diff --git a/src/plugins/find/searchresultwindow.h b/src/plugins/find/searchresultwindow.h index 92e58cebbb5bf0b6c5bec20e9c98a45f3946f4e0..b085f15f1c3a50f53387d2d4c57bcbd35e42b15e 100644 --- a/src/plugins/find/searchresultwindow.h +++ b/src/plugins/find/searchresultwindow.h @@ -32,10 +32,12 @@ #include "find_global.h" -#include <QtCore/QVariant> - #include <coreplugin/ioutputpane.h> +#include <QtCore/QVariant> +#include <QtCore/QStringList> +#include <QtGui/QIcon> + QT_BEGIN_NAMESPACE class QFont; QT_END_NAMESPACE @@ -49,14 +51,34 @@ class SearchResultWindow; struct FIND_EXPORT SearchResultItem { - QString fileName; - int lineNumber; - QString lineText; - int searchTermStart; - int searchTermLength; - int index; // SearchResultWindow sets the index - QVariant userData; - // whatever information we also need here + SearchResultItem() + : textMarkPos(-1), + textMarkLength(0), + lineNumber(-1), + useTextEditorFont(false) + { + } + + SearchResultItem(const SearchResultItem &other) + : path(other.path), + text(other.text), + textMarkPos(other.textMarkPos), + textMarkLength(other.textMarkLength), + icon(other.icon), + lineNumber(other.lineNumber), + useTextEditorFont(other.useTextEditorFont), + userData(other.userData) + { + } + + QStringList path; // hierarchy to the parent item of this item + QString text; // text to show for the item itself + int textMarkPos; // 0-based starting position for a mark (-1 for no mark) + int textMarkLength; // length of the mark (0 for no mark) + QIcon icon; // icon to show in front of the item (by be null icon to hide) + int lineNumber; // (0 or -1 for no line number) + bool useTextEditorFont; + QVariant userData; // user data for identification of the item }; class FIND_EXPORT SearchResult : public QObject @@ -80,6 +102,11 @@ public: SearchAndReplace }; + enum AddMode { + AddSorted, + AddOrdered + }; + SearchResultWindow(); virtual ~SearchResultWindow(); static SearchResultWindow *instance(); @@ -110,7 +137,7 @@ public: // search result object only lives till next startnewsearch call SearchResult *startNewSearch(SearchMode searchOrSearchAndReplace = SearchOnly); - void addResults(QList<SearchResultItem> &items); + void addResults(QList<SearchResultItem> &items, AddMode mode); public slots: void clearContents(); void addResult(const QString &fileName, int lineNumber, const QString &lineText, @@ -119,7 +146,7 @@ public slots: private slots: void handleExpandCollapseToolButton(bool checked); - void handleJumpToSearchResult(int index, bool checked); + void handleJumpToSearchResult(const SearchResultItem &item); void handleReplaceButton(); void showNoMatchesFound(); @@ -135,4 +162,6 @@ private: } // namespace Find +Q_DECLARE_METATYPE(Find::SearchResultItem) + #endif // SEARCHRESULTWINDOW_H diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 094668d4c0f26059250af95c16b687b94b41eaac..86df657bf196e26252917f7c955aebc286a239f1 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -128,6 +128,7 @@ plugin_cpptools.subdir = cpptools plugin_cpptools.depends = plugin_projectexplorer plugin_cpptools.depends += plugin_coreplugin plugin_cpptools.depends += plugin_texteditor +plugin_cpptools.depends += plugin_find plugin_bookmarks.subdir = bookmarks plugin_bookmarks.depends = plugin_projectexplorer diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index 9bf1c9957905699f25b9f96e81f22f1fb07f699e..89ae73506ce8f84c1dbbd928e74e5ce1ef377221 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -72,11 +72,6 @@ bool AllProjectsFind::isEnabled() const && m_plugin->session()->projects().count() > 0; } -QKeySequence AllProjectsFind::defaultShortcut() const -{ - return QKeySequence(); -} - Utils::FileIterator *AllProjectsFind::files() { Q_ASSERT(m_plugin->session()); diff --git a/src/plugins/projectexplorer/allprojectsfind.h b/src/plugins/projectexplorer/allprojectsfind.h index d4710a7381c781268859b31247c8a2d16e31b850..d6484e5d60b6aae24e89c47fa02c7f0ffbce95c1 100644 --- a/src/plugins/projectexplorer/allprojectsfind.h +++ b/src/plugins/projectexplorer/allprojectsfind.h @@ -54,7 +54,6 @@ public: QString displayName() const; bool isEnabled() const; - QKeySequence defaultShortcut() const; QWidget *createConfigWidget(); void writeSettings(QSettings *settings); diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index 55a2ba6950dd4a57f4a2ead9ba8bed4c07eab4d8..2e929c5cbe5d218379e0eda9edd76b4023338b44 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -70,11 +70,6 @@ bool CurrentProjectFind::isEnabled() const return m_plugin->currentProject() != 0 && BaseFileFind::isEnabled(); } -QKeySequence CurrentProjectFind::defaultShortcut() const -{ - return QKeySequence(); -} - Utils::FileIterator *CurrentProjectFind::files() { Project *project = m_plugin->currentProject(); diff --git a/src/plugins/projectexplorer/currentprojectfind.h b/src/plugins/projectexplorer/currentprojectfind.h index 5ee35a83c8da8bebdf4d8ff8dc4875dc0f2cc1b0..806618959540b01c5e82dc0b2f6e9ca151781bd0 100644 --- a/src/plugins/projectexplorer/currentprojectfind.h +++ b/src/plugins/projectexplorer/currentprojectfind.h @@ -57,7 +57,6 @@ public: QString displayName() const; bool isEnabled() const; - QKeySequence defaultShortcut() const; QWidget *createConfigWidget(); void writeSettings(QSettings *settings); diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 9006e11a73679ad30df973101ffdf5241734868d..7360ade77129f5a8f9ba867571fee91e7519e6a8 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -153,15 +153,16 @@ void BaseFileFind::displayResult(int index) { QList<Find::SearchResultItem> items; // this conversion is stupid... foreach (const Utils::FileSearchResult &result, results) { Find::SearchResultItem item; - item.fileName = result.fileName; + item.path = QStringList() << QDir::toNativeSeparators(result.fileName); item.lineNumber = result.lineNumber; - item.lineText = result.matchingLine; - item.searchTermLength = result.matchLength; - item.searchTermStart = result.matchStart; + item.text = result.matchingLine; + item.textMarkLength = result.matchLength; + item.textMarkPos = result.matchStart; + item.useTextEditorFont = true; item.userData = result.regexpCapturedTexts; items << item; } - m_resultWindow->addResults(items); + m_resultWindow->addResults(items, Find::SearchResultWindow::AddOrdered); if (m_resultLabel) m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults())); } @@ -250,7 +251,11 @@ void BaseFileFind::updateComboEntries(QComboBox *combo, bool onTop) void BaseFileFind::openEditor(const Find::SearchResultItem &item) { - TextEditor::BaseTextEditor::openEditorAt(item.fileName, item.lineNumber, item.searchTermStart); + if (item.path.size() > 0) { + TextEditor::BaseTextEditor::openEditorAt(item.path.first(), item.lineNumber, item.textMarkPos); + } else { + Core::EditorManager::instance()->openEditor(item.text); + } } // #pragma mark Static methods @@ -263,7 +268,7 @@ static void applyChanges(QTextDocument *doc, const QString &text, const QList<Fi const int blockNumber = item.lineNumber - 1; QTextCursor tc(doc->findBlockByNumber(blockNumber)); - const int cursorPosition = tc.position() + item.searchTermStart; + const int cursorPosition = tc.position() + item.textMarkPos; int cursorIndex = 0; for (; cursorIndex < changes.size(); ++cursorIndex) { @@ -277,7 +282,7 @@ static void applyChanges(QTextDocument *doc, const QString &text, const QList<Fi continue; // skip this change. tc.setPosition(cursorPosition); - tc.setPosition(tc.position() + item.searchTermLength, + tc.setPosition(tc.position() + item.textMarkLength, QTextCursor::KeepAnchor); QString substitutionText; if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty()) @@ -302,7 +307,7 @@ QStringList BaseFileFind::replaceAll(const QString &text, QHash<QString, QList<Find::SearchResultItem> > changes; foreach (const Find::SearchResultItem &item, items) - changes[item.fileName].append(item); + changes[item.path.first()].append(item); Core::EditorManager *editorManager = Core::EditorManager::instance(); diff --git a/src/plugins/texteditor/findincurrentfile.cpp b/src/plugins/texteditor/findincurrentfile.cpp index cad56dd7a44977a351163ea8010297d943fa1487..01c060133f9d8746453cd42afc1c2896848b252a 100644 --- a/src/plugins/texteditor/findincurrentfile.cpp +++ b/src/plugins/texteditor/findincurrentfile.cpp @@ -62,11 +62,6 @@ QString FindInCurrentFile::displayName() const return tr("Current File"); } -QKeySequence FindInCurrentFile::defaultShortcut() const -{ - return QKeySequence(); -} - Utils::FileIterator *FindInCurrentFile::files() { QStringList fileList; diff --git a/src/plugins/texteditor/findincurrentfile.h b/src/plugins/texteditor/findincurrentfile.h index b532e4cfa794e5d7433969b209b0c0695cabbd18..b42064d99c8c582cc5fb84fdae6e30e73af42215 100644 --- a/src/plugins/texteditor/findincurrentfile.h +++ b/src/plugins/texteditor/findincurrentfile.h @@ -55,7 +55,6 @@ public: QString id() const; QString displayName() const; - QKeySequence defaultShortcut() const; bool isEnabled() const; QWidget *createConfigWidget(); void writeSettings(QSettings *settings); diff --git a/src/plugins/texteditor/findinfiles.cpp b/src/plugins/texteditor/findinfiles.cpp index f2bbc54300eaad45844ddb9f018642d8c2906128..b6b02ef31b0013efa6a7eb1dcb4cdbfb0e2316d2 100644 --- a/src/plugins/texteditor/findinfiles.cpp +++ b/src/plugins/texteditor/findinfiles.cpp @@ -57,11 +57,6 @@ QString FindInFiles::displayName() const return tr("Files on File System"); } -QKeySequence FindInFiles::defaultShortcut() const -{ - return QKeySequence(); -} - void FindInFiles::findAll(const QString &txt, Find::FindFlags findFlags) { updateComboEntries(m_directory, true); diff --git a/src/plugins/texteditor/findinfiles.h b/src/plugins/texteditor/findinfiles.h index 49172f13b70829156eeee0e99d56d4898b2eb8ea..569e5ce781d71568a6652c258f9611c37da025e3 100644 --- a/src/plugins/texteditor/findinfiles.h +++ b/src/plugins/texteditor/findinfiles.h @@ -53,7 +53,6 @@ public: QString id() const; QString displayName() const; - QKeySequence defaultShortcut() const; void findAll(const QString &txt, Find::FindFlags findFlags); QWidget *createConfigWidget(); void writeSettings(QSettings *settings);