C++ symbols find filter for advanced find.

Required refactoring of the search result window to show real trees of
search results.

The backend is the backend from the Locator filter, which is a bit
outdated now.
This commit is contained in:
con
2010-07-19 14:46:53 +02:00
parent 80d85e2887
commit 2bda8675e5
37 changed files with 926 additions and 474 deletions

View File

@@ -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="TextEditor" version="2.1.80"/>
<dependency name="ProjectExplorer" version="2.1.80"/> <dependency name="ProjectExplorer" version="2.1.80"/>
<dependency name="Locator" version="2.1.80"/> <dependency name="Locator" version="2.1.80"/>
<dependency name="Find" version="2.1.80"/>
</dependencyList> </dependencyList>
</plugin> </plugin>

View File

@@ -31,8 +31,8 @@
using namespace CppTools::Internal; using namespace CppTools::Internal;
CppClassesFilter::CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager) CppClassesFilter::CppClassesFilter(CppModelManager *manager)
: CppLocatorFilter(manager, editorManager) : CppLocatorFilter(manager)
{ {
setShortcutString("c"); setShortcutString("c");
setIncludedByDefault(false); setIncludedByDefault(false);

View File

@@ -40,7 +40,7 @@ class CppClassesFilter : public CppLocatorFilter
Q_OBJECT Q_OBJECT
public: public:
CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager); CppClassesFilter(CppModelManager *manager);
~CppClassesFilter(); ~CppClassesFilter();
QString displayName() const { return tr("Classes"); } QString displayName() const { return tr("Classes"); }

View File

@@ -313,7 +313,11 @@ void CppFindReferences::searchFinished()
void CppFindReferences::openEditor(const Find::SearchResultItem &item) 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);
}
} }

View File

@@ -31,8 +31,8 @@
using namespace CppTools::Internal; using namespace CppTools::Internal;
CppFunctionsFilter::CppFunctionsFilter(CppModelManager *manager, Core::EditorManager *editorManager) CppFunctionsFilter::CppFunctionsFilter(CppModelManager *manager)
: CppLocatorFilter(manager, editorManager) : CppLocatorFilter(manager)
{ {
setShortcutString(QString(QLatin1Char('m'))); setShortcutString(QString(QLatin1Char('m')));
setIncludedByDefault(false); setIncludedByDefault(false);

View File

@@ -40,7 +40,7 @@ class CppFunctionsFilter : public CppLocatorFilter
Q_OBJECT Q_OBJECT
public: public:
CppFunctionsFilter(CppModelManager *manager, Core::EditorManager *editorManager); CppFunctionsFilter(CppModelManager *manager);
~CppFunctionsFilter(); ~CppFunctionsFilter();
QString displayName() const { return tr("Methods"); } QString displayName() const { return tr("Methods"); }

View File

@@ -30,8 +30,6 @@
#include "cpplocatorfilter.h" #include "cpplocatorfilter.h"
#include "cppmodelmanager.h" #include "cppmodelmanager.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <texteditor/itexteditor.h> #include <texteditor/itexteditor.h>
#include <texteditor/basetexteditor.h> #include <texteditor/basetexteditor.h>
@@ -39,9 +37,8 @@
using namespace CppTools::Internal; using namespace CppTools::Internal;
CppLocatorFilter::CppLocatorFilter(CppModelManager *manager, Core::EditorManager *editorManager) CppLocatorFilter::CppLocatorFilter(CppModelManager *manager)
: m_manager(manager), : m_manager(manager),
m_editorManager(editorManager),
m_forceNewSearchList(true) m_forceNewSearchList(true)
{ {
setShortcutString(QString(QLatin1Char(':'))); setShortcutString(QString(QLatin1Char(':')));

View File

@@ -34,10 +34,6 @@
#include <locator/ilocatorfilter.h> #include <locator/ilocatorfilter.h>
namespace Core {
class EditorManager;
}
namespace CppTools { namespace CppTools {
namespace Internal { namespace Internal {
@@ -47,7 +43,7 @@ class CppLocatorFilter : public Locator::ILocatorFilter
{ {
Q_OBJECT Q_OBJECT
public: public:
CppLocatorFilter(CppModelManager *manager, Core::EditorManager *editorManager); CppLocatorFilter(CppModelManager *manager);
~CppLocatorFilter(); ~CppLocatorFilter();
QString displayName() const { return tr("Classes and Methods"); } QString displayName() const { return tr("Classes and Methods"); }
@@ -66,7 +62,6 @@ private slots:
private: private:
CppModelManager *m_manager; CppModelManager *m_manager;
Core::EditorManager *m_editorManager;
struct Info { struct Info {
Info(): dirty(true) {} Info(): dirty(true) {}

View File

@@ -24,7 +24,8 @@ HEADERS += completionsettingspage.h \
cppdoxygen.h \ cppdoxygen.h \
cppfilesettingspage.h \ cppfilesettingspage.h \
cppfindreferences.h \ cppfindreferences.h \
cppcodeformatter.h cppcodeformatter.h \
symbolsfindfilter.h
SOURCES += completionsettingspage.cpp \ SOURCES += completionsettingspage.cpp \
cppclassesfilter.cpp \ cppclassesfilter.cpp \
@@ -40,7 +41,8 @@ SOURCES += completionsettingspage.cpp \
cppfilesettingspage.cpp \ cppfilesettingspage.cpp \
abstracteditorsupport.cpp \ abstracteditorsupport.cpp \
cppfindreferences.cpp \ cppfindreferences.cpp \
cppcodeformatter.cpp cppcodeformatter.cpp \
symbolsfindfilter.cpp
FORMS += completionsettingspage.ui \ FORMS += completionsettingspage.ui \
cppfilesettingspage.ui cppfilesettingspage.ui

View File

@@ -1,3 +1,4 @@
include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus.pri) include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus.pri)
include($$IDE_SOURCE_TREE/src/plugins/projectexplorer/projectexplorer.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/texteditor/texteditor.pri)
include($$IDE_SOURCE_TREE/src/plugins/find/find.pri)

View File

@@ -37,6 +37,7 @@
#include "cppmodelmanager.h" #include "cppmodelmanager.h"
#include "cpptoolsconstants.h" #include "cpptoolsconstants.h"
#include "cpplocatorfilter.h" #include "cpplocatorfilter.h"
#include "symbolsfindfilter.h"
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
@@ -111,14 +112,13 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
CppCodeCompletion *completion = new CppCodeCompletion(m_modelManager); CppCodeCompletion *completion = new CppCodeCompletion(m_modelManager);
addAutoReleasedObject(completion); addAutoReleasedObject(completion);
CppLocatorFilter *locatorFilter = new CppLocatorFilter(m_modelManager, addAutoReleasedObject(new CppLocatorFilter(m_modelManager));
core->editorManager()); addAutoReleasedObject(new CppClassesFilter(m_modelManager));
addAutoReleasedObject(locatorFilter); addAutoReleasedObject(new CppFunctionsFilter(m_modelManager));
addAutoReleasedObject(new CppClassesFilter(m_modelManager, core->editorManager()));
addAutoReleasedObject(new CppFunctionsFilter(m_modelManager, core->editorManager()));
addAutoReleasedObject(new CppCurrentDocumentFilter(m_modelManager, core->editorManager())); addAutoReleasedObject(new CppCurrentDocumentFilter(m_modelManager, core->editorManager()));
addAutoReleasedObject(new CompletionSettingsPage); addAutoReleasedObject(new CompletionSettingsPage);
addAutoReleasedObject(new CppFileSettingsPage(m_fileSettings)); addAutoReleasedObject(new CppFileSettingsPage(m_fileSettings));
addAutoReleasedObject(new SymbolsFindFilter(m_modelManager));
// Menus // Menus
Core::ActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS); Core::ActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS);

View File

@@ -32,10 +32,17 @@
#include <Literals.h> #include <Literals.h>
#include <Scope.h> #include <Scope.h>
#include <Names.h> #include <Names.h>
#include <cplusplus/LookupContext.h>
using namespace CPlusPlus; using namespace CPlusPlus;
using namespace CppTools::Internal; using namespace CppTools::Internal;
SearchSymbols::SymbolTypes SearchSymbols::AllTypes =
SearchSymbols::Classes
| SearchSymbols::Functions
| SearchSymbols::Enums
| SearchSymbols::Declarations;
SearchSymbols::SearchSymbols(): SearchSymbols::SearchSymbols():
symbolsToSearchFor(Classes | Functions | Enums), symbolsToSearchFor(Classes | Functions | Enums),
separateScope(false) separateScope(false)
@@ -204,13 +211,17 @@ QString SearchSymbols::symbolName(const Symbol *symbol) const
void SearchSymbols::appendItem(const QString &name, void SearchSymbols::appendItem(const QString &name,
const QString &info, const QString &info,
ModelItemInfo::ItemType type, ModelItemInfo::ItemType type,
const Symbol *symbol) Symbol *symbol)
{ {
if (!symbol->name()) if (!symbol->name())
return; return;
QStringList fullyQualifiedName;
foreach (const Name *name, LookupContext::fullyQualifiedName(symbol))
fullyQualifiedName.append(overview.prettyName(name));
const QIcon icon = icons.iconForSymbol(symbol); const QIcon icon = icons.iconForSymbol(symbol);
items.append(ModelItemInfo(name, info, type, items.append(ModelItemInfo(name, info, type,
fullyQualifiedName,
QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()),
symbol->line(), symbol->line(),
symbol->column() - 1, // 1-based vs 0-based column symbol->column() - 1, // 1-based vs 0-based column

View File

@@ -52,12 +52,14 @@ struct ModelItemInfo
ModelItemInfo() ModelItemInfo()
: type(Declaration), : type(Declaration),
line(0) line(0),
column(0)
{ } { }
ModelItemInfo(const QString &symbolName, ModelItemInfo(const QString &symbolName,
const QString &symbolType, const QString &symbolType,
ItemType type, ItemType type,
QStringList fullyQualifiedName,
const QString &fileName, const QString &fileName,
int line, int line,
int column, int column,
@@ -65,15 +67,28 @@ struct ModelItemInfo
: symbolName(symbolName), : symbolName(symbolName),
symbolType(symbolType), symbolType(symbolType),
type(type), type(type),
fullyQualifiedName(fullyQualifiedName),
fileName(fileName), fileName(fileName),
line(line), line(line),
column(column), column(column),
icon(icon) 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 symbolName;
QString symbolType; QString symbolType;
ItemType type; ItemType type;
QStringList fullyQualifiedName;
QString fileName; QString fileName;
int line; int line;
int column; int column;
@@ -90,8 +105,11 @@ public:
Enums = 0x4, Enums = 0x4,
Declarations = 0x8 Declarations = 0x8
}; };
Q_DECLARE_FLAGS(SymbolTypes, SymbolType) Q_DECLARE_FLAGS(SymbolTypes, SymbolType)
static SymbolTypes AllTypes;
SearchSymbols(); SearchSymbols();
void setSymbolsToSearchFor(SymbolTypes types); void setSymbolsToSearchFor(SymbolTypes types);
@@ -121,7 +139,7 @@ protected:
void appendItem(const QString &name, void appendItem(const QString &name,
const QString &info, const QString &info,
ModelItemInfo::ItemType type, ModelItemInfo::ItemType type,
const CPlusPlus::Symbol *symbol); CPlusPlus::Symbol *symbol);
private: private:
QString findOrInsert(const QString &s) QString findOrInsert(const QString &s)

View File

@@ -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);
}

View File

@@ -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

View File

@@ -34,9 +34,9 @@
#include "textfindconstants.h" #include "textfindconstants.h"
#include <QtGui/QTextDocument> #include <QtGui/QTextDocument>
#include <QtGui/QKeySequence>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QKeySequence;
class QWidget; class QWidget;
class QSettings; class QSettings;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -53,7 +53,7 @@ public:
virtual QString id() const = 0; virtual QString id() const = 0;
virtual QString displayName() const = 0; virtual QString displayName() const = 0;
virtual bool isEnabled() 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 bool isReplaceSupported() const { return false; }
virtual FindFlags supportedFindFlags() const; virtual FindFlags supportedFindFlags() const;

View File

@@ -48,9 +48,6 @@ SearchResultTreeItemDelegate::SearchResultTreeItemDelegate(QObject *parent)
void SearchResultTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 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); QStyleOptionViewItemV3 opt = setOptions(index, option);
@@ -58,12 +55,22 @@ void SearchResultTreeItemDelegate::paint(QPainter *painter, const QStyleOptionVi
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));
int lineNumberAreaWidth = drawLineNumber(painter, opt, resultRowRect, index);
resultRowRect.adjust(lineNumberAreaWidth, 0, 0, 0);
QRect resultRowRect(opt.rect.adjusted(lineNumberAreaWidth, 0, 0, 0));
QString displayString = index.model()->data(index, Qt::DisplayRole).toString(); QString displayString = index.model()->data(index, Qt::DisplayRole).toString();
drawMarker(painter, index, displayString, resultRowRect); drawMarker(painter, index, displayString, resultRowRect);
// 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 // Draw the text and focus/selection
QItemDelegate::drawDisplay(painter, opt, resultRowRect, displayString); QItemDelegate::drawDisplay(painter, opt, resultRowRect, displayString);
QItemDelegate::drawFocus(painter, opt, opt.rect); QItemDelegate::drawFocus(painter, opt, opt.rect);
@@ -82,19 +89,36 @@ void SearchResultTreeItemDelegate::paint(QPainter *painter, const QStyleOptionVi
painter->restore(); 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, int SearchResultTreeItemDelegate::drawLineNumber(QPainter *painter, const QStyleOptionViewItemV3 &option,
const QRect &rect,
const QModelIndex &index) const const QModelIndex &index) const
{ {
static const int lineNumberAreaHorizontalPadding = 4; static const int lineNumberAreaHorizontalPadding = 4;
const bool isSelected = option.state & QStyle::State_Selected;
int lineNumber = index.model()->data(index, ItemDataRoles::ResultLineNumberRole).toInt(); 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 lineNumberDigits = (int)floor(log10((double)lineNumber)) + 1;
int minimumLineNumberDigits = qMax((int)m_minimumLineNumberDigits, lineNumberDigits); int minimumLineNumberDigits = qMax((int)m_minimumLineNumberDigits, lineNumberDigits);
int fontWidth = painter->fontMetrics().width(QString(minimumLineNumberDigits, QLatin1Char('0'))); int fontWidth = painter->fontMetrics().width(QString(minimumLineNumberDigits, QLatin1Char('0')));
int lineNumberAreaWidth = lineNumberAreaHorizontalPadding + fontWidth + lineNumberAreaHorizontalPadding; int lineNumberAreaWidth = lineNumberAreaHorizontalPadding + fontWidth + lineNumberAreaHorizontalPadding;
QRect lineNumberAreaRect(option.rect); QRect lineNumberAreaRect(rect);
lineNumberAreaRect.setWidth(lineNumberAreaWidth); lineNumberAreaRect.setWidth(lineNumberAreaWidth);
QPalette::ColorGroup cg = QPalette::Normal; 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, void SearchResultTreeItemDelegate::drawMarker(QPainter *painter, const QModelIndex &index, const QString text,
const QRect &rect) const const QRect &rect) const
{ {
const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
int searchTermStart = index.model()->data(index, ItemDataRoles::SearchTermStartRole).toInt(); 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(); 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)); int searchTermLengthPixels = painter->fontMetrics().width(text.mid(searchTermStart, searchTermLength));
QRect resultHighlightRect(rect); QRect resultHighlightRect(rect);
resultHighlightRect.setLeft(resultHighlightRect.left() + searchTermStartPixels + textMargin - 1); // -1: Cosmetics resultHighlightRect.setLeft(resultHighlightRect.left() + searchTermStartPixels + textMargin - 1); // -1: Cosmetics

View File

@@ -42,7 +42,8 @@ public:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
private: 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; void drawMarker(QPainter *painter, const QModelIndex &index, const QString text, const QRect &rect) const;
static const int m_minimumLineNumberDigits = 6; static const int m_minimumLineNumberDigits = 6;

View File

@@ -30,22 +30,21 @@
#ifndef SEARCHRESULTTREEITEMROLES_H #ifndef SEARCHRESULTTREEITEMROLES_H
#define SEARCHRESULTTREEITEMROLES_H #define SEARCHRESULTTREEITEMROLES_H
#include <QtGui/QAbstractItemView>
namespace Find { namespace Find {
namespace Internal { namespace Internal {
namespace ItemDataRoles { namespace ItemDataRoles {
enum Roles enum Roles
{ {
TypeRole = Qt::UserRole, ResultItemRole = Qt::UserRole,
FileNameRole,
ResultLinesCountRole,
ResultIndexRole,
ResultLineRole, ResultLineRole,
ResultLineNumberRole, ResultLineNumberRole,
ResultIconRole,
SearchTermStartRole, SearchTermStartRole,
SearchTermLengthRole, SearchTermLengthRole,
RowOfItem, // The ?-th child of its parent is this this item RowOfItem // The ?-th child of its parent is this this item
TextRole // for files == FileNameRole, for results == ResultLineRole
}; };
} // namespace Internal } // namespace Internal

View File

@@ -31,8 +31,13 @@
using namespace Find::Internal; using namespace Find::Internal;
SearchResultTreeItem::SearchResultTreeItem(SearchResultTreeItem::ItemType type, const SearchResultTreeItem *parent) SearchResultTreeItem::SearchResultTreeItem(const SearchResultItem &item,
: m_type(type), m_parent(parent), m_isUserCheckable(false), m_checkState(Qt::Unchecked) 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(); clearChildren();
} }
bool SearchResultTreeItem::isLeaf() const
{
return childrenCount() == 0 && parent() != 0;
}
bool SearchResultTreeItem::isUserCheckable() const bool SearchResultTreeItem::isUserCheckable() const
{ {
return m_isUserCheckable; return m_isUserCheckable;
@@ -67,11 +77,6 @@ void SearchResultTreeItem::clearChildren()
m_children.clear(); m_children.clear();
} }
SearchResultTreeItem::ItemType SearchResultTreeItem::itemType() const
{
return m_type;
}
int SearchResultTreeItem::childrenCount() const int SearchResultTreeItem::childrenCount() const
{ {
return m_children.count(); return m_children.count();
@@ -92,16 +97,28 @@ const SearchResultTreeItem *SearchResultTreeItem::parent() const
return m_parent; return m_parent;
} }
static bool compareResultFiles(SearchResultTreeItem *a, SearchResultTreeItem *b) static bool lessThanByText(SearchResultTreeItem *a, const QString &b)
{ {
return static_cast<SearchResultFile *>(a)->fileName() < return a->item.text < b;
static_cast<SearchResultFile *>(b)->fileName();
} }
int SearchResultTreeItem::insertionIndex(SearchResultFile *child) const int SearchResultTreeItem::insertionIndex(const QString &text, SearchResultTreeItem **existingItem) const
{ {
Q_ASSERT(m_type == Root); QList<SearchResultTreeItem *>::const_iterator insertionPosition =
return qLowerBound(m_children.begin(), m_children.end(), child, compareResultFiles) - m_children.begin(); 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();
}
int SearchResultTreeItem::insertionIndex(const SearchResultItem &item, SearchResultTreeItem **existingItem) const
{
return insertionIndex(item.text, existingItem);
} }
void SearchResultTreeItem::insertChild(int index, SearchResultTreeItem *child) void SearchResultTreeItem::insertChild(int index, SearchResultTreeItem *child)
@@ -109,68 +126,17 @@ void SearchResultTreeItem::insertChild(int index, SearchResultTreeItem *child)
m_children.insert(index, child); m_children.insert(index, child);
} }
void SearchResultTreeItem::appendChild(SearchResultTreeItem *child) void SearchResultTreeItem::insertChild(int index, const SearchResultItem &item)
{ {
m_children.append(child); SearchResultTreeItem *child = new SearchResultTreeItem(item, this);
}
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
{
return m_lineNumber;
}
int SearchResultTextRow::searchTermStart() const
{
return m_searchTermStart;
}
int SearchResultTextRow::searchTermLength() const
{
return m_searchTermLength;
}
SearchResultFile::SearchResultFile(const QString &fileName, const SearchResultTreeItem *parent):
SearchResultTreeItem(ResultFile, parent),
m_fileName(fileName)
{
}
QString SearchResultFile::fileName() const
{
return m_fileName;
}
void SearchResultFile::appendResultLine(int index, int lineNumber, const QString &rowText, int searchTermStart,
int searchTermLength)
{
SearchResultTreeItem *child = new SearchResultTextRow(index, lineNumber, rowText,
searchTermStart, searchTermLength, this);
if (isUserCheckable()) { if (isUserCheckable()) {
child->setIsUserCheckable(true); child->setIsUserCheckable(true);
child->setCheckState(Qt::Checked); child->setCheckState(Qt::Checked);
} }
appendChild(child); insertChild(index, child);
}
void SearchResultTreeItem::appendChild(const SearchResultItem &item)
{
insertChild(m_children.count(), item);
} }

View File

@@ -30,35 +30,31 @@
#ifndef SEARCHRESULTTREEITEMS_H #ifndef SEARCHRESULTTREEITEMS_H
#define SEARCHRESULTTREEITEMS_H #define SEARCHRESULTTREEITEMS_H
#include "searchresultwindow.h"
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QList> #include <QtCore/QList>
#include <QtCore/qnamespace.h> #include <QtCore/qnamespace.h>
#include <QtGui/QIcon>
namespace Find { namespace Find {
namespace Internal { namespace Internal {
class SearchResultTreeItem;
class SearchResultFile;
class SearchResultTreeItem class SearchResultTreeItem
{ {
public: public:
enum ItemType SearchResultTreeItem(const SearchResultItem &item = SearchResultItem(),
{ const SearchResultTreeItem *parent = NULL);
Root,
ResultRow,
ResultFile
};
SearchResultTreeItem(ItemType type = Root, const SearchResultTreeItem *parent = NULL);
virtual ~SearchResultTreeItem(); virtual ~SearchResultTreeItem();
ItemType itemType() const; bool isLeaf() const;
const SearchResultTreeItem *parent() const; const SearchResultTreeItem *parent() const;
SearchResultTreeItem *childAt(int index) 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 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 childrenCount() const;
int rowOfItem() const; int rowOfItem() const;
void clearChildren(); void clearChildren();
@@ -69,43 +65,17 @@ public:
Qt::CheckState checkState() const; Qt::CheckState checkState() const;
void setCheckState(Qt::CheckState checkState); void setCheckState(Qt::CheckState checkState);
bool isGenerated() const { return m_isGenerated; }
void setGenerated(bool value) { m_isGenerated = value; }
SearchResultItem item;
private: private:
ItemType m_type;
const SearchResultTreeItem *m_parent; const SearchResultTreeItem *m_parent;
QList<SearchResultTreeItem *> m_children; QList<SearchResultTreeItem *> m_children;
bool m_isUserCheckable; bool m_isUserCheckable;
Qt::CheckState m_checkState; Qt::CheckState m_checkState;
}; bool m_isGenerated;
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;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -46,7 +46,7 @@ using namespace Find::Internal;
SearchResultTreeModel::SearchResultTreeModel(QObject *parent) SearchResultTreeModel::SearchResultTreeModel(QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent)
, m_lastAddedResultFile(0) , m_currentParent(0)
, m_showReplaceUI(false) , m_showReplaceUI(false)
{ {
m_rootItem = new SearchResultTreeItem; m_rootItem = new SearchResultTreeItem;
@@ -70,13 +70,13 @@ void SearchResultTreeModel::setTextEditorFont(const QFont &font)
layoutChanged(); 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 (idx.isValid()) {
if (const SearchResultTreeItem *item = static_cast<const SearchResultTreeItem*>(index.internalPointer())) { if (const SearchResultTreeItem *item = treeItemAtIndex(idx)) {
if (item->itemType() == SearchResultTreeItem::ResultRow && item->isUserCheckable()) { if (item->isLeaf() && item->isUserCheckable()) {
flags |= Qt::ItemIsUserCheckable; flags |= Qt::ItemIsUserCheckable;
} }
} }
@@ -96,7 +96,7 @@ QModelIndex SearchResultTreeModel::index(int row, int column,
if (!parent.isValid()) if (!parent.isValid())
parentItem = m_rootItem; parentItem = m_rootItem;
else else
parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer()); parentItem = treeItemAtIndex(parent);
const SearchResultTreeItem *childItem = parentItem->childAt(row); const SearchResultTreeItem *childItem = parentItem->childAt(row);
if (childItem) if (childItem)
@@ -105,12 +105,17 @@ QModelIndex SearchResultTreeModel::index(int row, int column,
return QModelIndex(); 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(); return QModelIndex();
const SearchResultTreeItem *childItem = static_cast<const SearchResultTreeItem*>(index.internalPointer()); const SearchResultTreeItem *childItem = treeItemAtIndex(idx);
const SearchResultTreeItem *parentItem = childItem->parent(); const SearchResultTreeItem *parentItem = childItem->parent();
if (parentItem == m_rootItem) if (parentItem == m_rootItem)
@@ -129,7 +134,7 @@ int SearchResultTreeModel::rowCount(const QModelIndex &parent) const
if (!parent.isValid()) if (!parent.isValid())
parentItem = m_rootItem; parentItem = m_rootItem;
else else
parentItem = static_cast<const SearchResultTreeItem*>(parent.internalPointer()); parentItem = treeItemAtIndex(parent);
return parentItem->childrenCount(); return parentItem->childrenCount();
} }
@@ -140,48 +145,41 @@ int SearchResultTreeModel::columnCount(const QModelIndex &parent) const
return 1; return 1;
} }
QVariant SearchResultTreeModel::data(const QModelIndex &index, int role) const SearchResultTreeItem *SearchResultTreeModel::treeItemAtIndex(const QModelIndex &idx) const
{ {
if (!index.isValid()) return static_cast<SearchResultTreeItem*>(idx.internalPointer());
return QVariant(); }
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; 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 appFontHeight = QApplication::fontMetrics().height();
const int editorFontHeight = QFontMetrics(m_textEditorFont).height(); const int editorFontHeight = QFontMetrics(m_textEditorFont).height();
result = QSize(0, qMax(appFontHeight, editorFontHeight)); result = QSize(0, qMax(appFontHeight, editorFontHeight));
} } else {
else if (item->itemType() == SearchResultTreeItem::ResultRow) result = data(treeItemAtIndex(idx), role);
{
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);
} }
return result; 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) { 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()); Qt::CheckState checkState = static_cast<Qt::CheckState>(value.toInt());
row->setCheckState(checkState); treeItemAtIndex(idx)->setCheckState(checkState);
return true; 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; QVariant result;
@@ -192,39 +190,40 @@ QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) c
result = row->checkState(); result = row->checkState();
break; break;
case Qt::ToolTipRole: case Qt::ToolTipRole:
result = row->rowText().trimmed(); result = row->item.text.trimmed();
break; break;
case Qt::FontRole: case Qt::FontRole:
if (row->item.useTextEditorFont)
result = m_textEditorFont; result = m_textEditorFont;
else
result = QVariant();
break; break;
case ItemDataRoles::TextRole:
case ItemDataRoles::ResultLineRole: case ItemDataRoles::ResultLineRole:
case Qt::DisplayRole: case Qt::DisplayRole:
result = row->rowText(); result = row->item.text;
break; break;
case ItemDataRoles::ResultIndexRole: case ItemDataRoles::ResultItemRole:
result = row->index(); result = qVariantFromValue(row->item);
break; break;
case ItemDataRoles::ResultLineNumberRole: case ItemDataRoles::ResultLineNumberRole:
result = row->lineNumber(); result = row->item.lineNumber;
break;
case ItemDataRoles::ResultIconRole:
result = row->item.icon;
break; break;
case ItemDataRoles::SearchTermStartRole: case ItemDataRoles::SearchTermStartRole:
result = row->searchTermStart(); result = row->item.textMarkPos;
break; break;
case ItemDataRoles::SearchTermLengthRole: case ItemDataRoles::SearchTermLengthRole:
result = row->searchTermLength(); result = row->item.textMarkLength;
break; break;
case ItemDataRoles::TypeRole: // TODO this looks stupid in case of symbol tree, is it necessary?
result = QLatin1String("row"); // case Qt::BackgroundRole:
break; // if (row->parent() && row->parent()->parent())
case ItemDataRoles::FileNameRole: // result = QVariant();
{ // else
if (row->parent()->itemType() == SearchResultTreeItem::ResultFile) { // result = QApplication::palette().base().color().darker(105);
const SearchResultFile *file = static_cast<const SearchResultFile *>(row->parent()); // break;
result = file->fileName();
}
break;
}
default: default:
result = QVariant(); result = QVariant();
break; break;
@@ -233,42 +232,6 @@ QVariant SearchResultTreeModel::data(const SearchResultTextRow *row, int role) c
return result; 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, QVariant SearchResultTreeModel::headerData(int section, Qt::Orientation orientation,
int role) const 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 QSet<SearchResultTreeItem *> pathNodes;
if (fileName.contains(QLatin1Char('\\'))) SearchResultTreeItem *currentItem = m_rootItem;
qWarning("SearchResultTreeModel::appendResultFile: File name with native separators added %s.\n", qPrintable(fileName)); QModelIndex currentItemIndex = QModelIndex();
#endif SearchResultTreeItem *partItem = 0;
m_lastAddedResultFile = new SearchResultFile(fileName, m_rootItem); 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) { if (m_showReplaceUI) {
m_lastAddedResultFile->setIsUserCheckable(true); partItem->setIsUserCheckable(true);
m_lastAddedResultFile->setCheckState(Qt::Checked); partItem->setCheckState(Qt::Checked);
} }
partItem->setGenerated(true);
const int index = m_rootItem->insertionIndex(m_lastAddedResultFile); beginInsertRows(currentItemIndex, insertionIndex, insertionIndex);
beginInsertRows(QModelIndex(), index, index); currentItem->insertChild(insertionIndex, partItem);
m_rootItem->insertChild(index, m_lastAddedResultFile);
endInsertRows(); endInsertRows();
return index; }
pathNodes << partItem;
currentItemIndex = index(insertionIndex, 0, currentItemIndex);
currentItem = partItem;
currentPath << part;
} }
void SearchResultTreeModel::appendResultLines(const QList<SearchResultItem> &items) m_currentParent = currentItem;
m_currentPath = currentPath;
m_currentIndex = currentItemIndex;
return pathNodes;
}
void SearchResultTreeModel::addResultsToCurrentParent(const QList<SearchResultItem> &items, SearchResultWindow::AddMode mode)
{ {
if (!m_lastAddedResultFile) if (!m_currentParent)
return; return;
QModelIndex lastFile(createIndex(m_lastAddedResultFile->rowOfItem(), 0, m_lastAddedResultFile)); if (mode == SearchResultWindow::AddOrdered) {
// this is the mode for e.g. text search
beginInsertRows(lastFile, m_lastAddedResultFile->childrenCount(), m_lastAddedResultFile->childrenCount() + items.count()); beginInsertRows(m_currentIndex, m_currentParent->childrenCount(), m_currentParent->childrenCount() + items.count());
foreach (const SearchResultItem &item, items) { foreach (const SearchResultItem &item, items) {
m_lastAddedResultFile->appendResultLine(item.index, m_currentParent->appendChild(item);
item.lineNumber,
item.lineText,
item.searchTermStart,
item.searchTermLength);
} }
endInsertRows(); 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();
}
}
}
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 * Adds the search result to the list of results, creating nodes for the path when
* necessary. Returns the insertion index when a new file entry was created. * 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; QList<SearchResultItem> itemSet;
foreach (const SearchResultItem &item, items) { foreach (const SearchResultItem &item, sortedItems) {
if (!m_lastAddedResultFile || (m_lastAddedResultFile->fileName() != item.fileName)) { if (!m_currentParent || (m_currentPath != item.path)) {
// first add all the items from before
if (!itemSet.isEmpty()) { if (!itemSet.isEmpty()) {
appendResultLines(itemSet); addResultsToCurrentParent(itemSet, mode);
itemSet.clear(); itemSet.clear();
} }
insertedFileIndices << addResultFile(item.fileName); // switch parent
pathNodes += addPath(item.path);
} }
itemSet << item; itemSet << item;
} }
if (!itemSet.isEmpty()) { if (!itemSet.isEmpty()) {
appendResultLines(itemSet); addResultsToCurrentParent(itemSet, mode);
itemSet.clear(); itemSet.clear();
} }
return insertedFileIndices; QList<QModelIndex> pathIndices;
foreach (SearchResultTreeItem *item, pathNodes)
pathIndices << index(item);
return pathIndices;
} }
void SearchResultTreeModel::clear() void SearchResultTreeModel::clear()
{ {
m_lastAddedResultFile = NULL; m_currentParent = NULL;
m_rootItem->clearChildren(); m_rootItem->clearChildren();
reset(); reset();
} }
QModelIndex SearchResultTreeModel::next(const QModelIndex &idx, bool includeTopLevel) const QModelIndex SearchResultTreeModel::nextIndex(const QModelIndex &idx) const
{ {
QModelIndex parent = idx.parent(); // pathological
if (parent.isValid()) { if (!idx.isValid())
int row = idx.row(); return index(0, 0);
if (row + 1 < rowCount(parent)) {
// Same parent if (rowCount(idx) > 0) {
return index(row + 1, 0, parent); // node with children
} 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);
}
if (includeTopLevel)
return nextParent;
return nextParent.child(0, 0);
}
} else {
// We are on a top level item
return idx.child(0, 0); return idx.child(0, 0);
} }
return QModelIndex(); // 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 {
// go up one parent
if (!current.isValid()) {
nextIndex = index(0, 0);
}
}
}
return nextIndex;
} }
QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx, bool includeTopLevel) const QModelIndex SearchResultTreeModel::next(const QModelIndex &idx, bool includeGenerated) const
{ {
QModelIndex parent = idx.parent(); QModelIndex value = idx;
if (parent.isValid()) { do {
int row = idx.row(); 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) { if (row > 0) {
// Same parent current = index(row - 1, 0, current.parent());
return index(row - 1, 0, parent);
} else { } else {
if (includeTopLevel) current = current.parent();
return parent; checkForChildren = !current.isValid();
// 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 { if (checkForChildren) {
// We are on a top level item // traverse down the hierarchy
int row = idx.row(); while (int rc = rowCount(current)) {
QModelIndex prevParent; current = index(rc - 1, 0, current);
if (row > 0) {
prevParent = index(row - 1, 0);
} else {
// wrap around
prevParent = index(rowCount() -1, 0);
} }
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) 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 else
currentIndex = next(currentIndex, true); currentIndex = next(currentIndex, true);
if (currentIndex.isValid()) { if (currentIndex.isValid()) {
const QString &text = data(currentIndex, ItemDataRoles::TextRole).toString(); const QString &text = data(currentIndex, ItemDataRoles::ResultLineRole).toString();
if (expr.indexIn(text) != -1) if (expr.indexIn(text) != -1)
resultIndex = currentIndex; resultIndex = currentIndex;
} }
@@ -452,7 +467,7 @@ QModelIndex SearchResultTreeModel::find(const QString &term, const QModelIndex &
else else
currentIndex = next(currentIndex, true); currentIndex = next(currentIndex, true);
if (currentIndex.isValid()) { if (currentIndex.isValid()) {
const QString &text = data(currentIndex, ItemDataRoles::TextRole).toString(); const QString &text = data(currentIndex, ItemDataRoles::ResultLineRole).toString();
QTextDocument doc(text); QTextDocument doc(text);
if (!doc.find(term, 0, flags).isNull()) if (!doc.find(term, 0, flags).isNull())
resultIndex = currentIndex; resultIndex = currentIndex;

View File

@@ -41,8 +41,6 @@ namespace Find {
namespace Internal { namespace Internal {
class SearchResultTreeItem; class SearchResultTreeItem;
class SearchResultTextRow;
class SearchResultFile;
class SearchResultTreeModel : public QAbstractItemModel class SearchResultTreeModel : public QAbstractItemModel
{ {
@@ -64,10 +62,10 @@ public:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
QVariant headerData(int section, Qt::Orientation orientation, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const;
QModelIndex next(const QModelIndex &idx, bool includeTopLevel = false) const; QModelIndex next(const QModelIndex &idx, bool includeGenerated = false) const;
QModelIndex prev(const QModelIndex &idx, bool includeTopLevel = 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 QRegExp &expr, const QModelIndex &index, QTextDocument::FindFlags flags);
QModelIndex find(const QString &term, 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(); void clear();
private: private:
void appendResultLines(const QList<SearchResultItem> &items); QModelIndex index(SearchResultTreeItem *item) const;
int addResultFile(const QString &fileName); void addResultsToCurrentParent(const QList<SearchResultItem> &items, SearchResultWindow::AddMode mode);
QVariant data(const SearchResultTextRow *row, int role) const; QSet<SearchResultTreeItem *> addPath(const QStringList &path);
QVariant data(const SearchResultFile *file, int role) const; QVariant data(const SearchResultTreeItem *row, int role) const;
void initializeData(); QModelIndex nextIndex(const QModelIndex &idx) const;
void disposeData(); QModelIndex prevIndex(const QModelIndex &idx) const;
SearchResultTreeItem *treeItemAtIndex(const QModelIndex &idx) const;
SearchResultTreeItem *m_rootItem; 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; QFont m_textEditorFont;
bool m_showReplaceUI; bool m_showReplaceUI;
}; };

View File

@@ -46,6 +46,7 @@ SearchResultTreeView::SearchResultTreeView(QWidget *parent)
setItemDelegate(new SearchResultTreeItemDelegate(this)); setItemDelegate(new SearchResultTreeItemDelegate(this));
setIndentation(14); setIndentation(14);
setUniformRowHeights(true); setUniformRowHeights(true);
setExpandsOnDoubleClick(false);
header()->hide(); header()->hide();
connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(emitJumpToSearchResult(QModelIndex))); connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(emitJumpToSearchResult(QModelIndex)));
@@ -66,24 +67,20 @@ void SearchResultTreeView::clear()
m_model->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); QList<QModelIndex> addedParents = m_model->addResults(items, mode);
if (m_autoExpandResults && !insertedFileIndices.isEmpty()) { if (m_autoExpandResults && !addedParents.isEmpty()) {
foreach (int index, insertedFileIndices) foreach (const QModelIndex &index, addedParents)
setExpanded(model()->index(index, 0), true); setExpanded(index, true);
} }
} }
void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index) void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index)
{ {
if (model()->data(index, ItemDataRoles::TypeRole).toString().compare(QLatin1String("row")) != 0) SearchResultItem item = model()->data(index, ItemDataRoles::ResultItemRole).value<SearchResultItem>();
return;
int position = model()->data(index, ItemDataRoles::ResultIndexRole).toInt(); emit jumpToSearchResult(item);
int checked = model()->data(index, Qt::CheckStateRole).toBool();
emit jumpToSearchResult(position, checked);
} }
void SearchResultTreeView::keyPressEvent(QKeyEvent *e) void SearchResultTreeView::keyPressEvent(QKeyEvent *e)

View File

@@ -50,10 +50,10 @@ public:
void setTextEditorFont(const QFont &font); void setTextEditorFont(const QFont &font);
SearchResultTreeModel *model() const; SearchResultTreeModel *model() const;
void appendResultLines(const QList<Find::SearchResultItem> &items); void addResults(const QList<Find::SearchResultItem> &items, SearchResultWindow::AddMode mode);
signals: signals:
void jumpToSearchResult(int index, bool checked); void jumpToSearchResult(const SearchResultItem &item);
public slots: public slots:
void clear(); void clear();

View File

@@ -45,6 +45,7 @@
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QSettings> #include <QtCore/QSettings>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtGui/QListWidget> #include <QtGui/QListWidget>
#include <QtGui/QToolButton> #include <QtGui/QToolButton>
#include <QtGui/QLineEdit> #include <QtGui/QLineEdit>
@@ -56,7 +57,6 @@
static const char SETTINGSKEYSECTIONNAME[] = "SearchResults"; static const char SETTINGSKEYSECTIONNAME[] = "SearchResults";
static const char SETTINGSKEYEXPANDRESULTS[] = "ExpandResults"; static const char SETTINGSKEYEXPANDRESULTS[] = "ExpandResults";
namespace Find { namespace Find {
namespace Internal { namespace Internal {
@@ -204,13 +204,14 @@ namespace Internal {
static const bool m_initiallyExpand = false; static const bool m_initiallyExpand = false;
QStackedWidget *m_widget; QStackedWidget *m_widget;
SearchResult *m_currentSearch; SearchResult *m_currentSearch;
QList<SearchResultItem> m_items; int m_itemCount;
bool m_isShowingReplaceUI; bool m_isShowingReplaceUI;
bool m_focusReplaceEdit; bool m_focusReplaceEdit;
}; };
SearchResultWindowPrivate::SearchResultWindowPrivate() SearchResultWindowPrivate::SearchResultWindowPrivate()
: m_currentSearch(0), : m_currentSearch(0),
m_itemCount(0),
m_isShowingReplaceUI(false), m_isShowingReplaceUI(false),
m_focusReplaceEdit(false) m_focusReplaceEdit(false)
{ {
@@ -338,8 +339,8 @@ SearchResultWindow::SearchResultWindow() : d(new SearchResultWindowPrivate)
d->m_replaceButton->setAutoRaise(true); d->m_replaceButton->setAutoRaise(true);
d->m_replaceTextEdit->setTabOrder(d->m_replaceTextEdit, d->m_searchResultTreeView); d->m_replaceTextEdit->setTabOrder(d->m_replaceTextEdit, d->m_searchResultTreeView);
connect(d->m_searchResultTreeView, SIGNAL(jumpToSearchResult(int,bool)), connect(d->m_searchResultTreeView, SIGNAL(jumpToSearchResult(SearchResultItem)),
this, SLOT(handleJumpToSearchResult(int,bool))); this, SLOT(handleJumpToSearchResult(SearchResultItem)));
connect(d->m_expandCollapseAction, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool))); connect(d->m_expandCollapseAction, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool)));
connect(d->m_replaceTextEdit, SIGNAL(returnPressed()), this, SLOT(handleReplaceButton())); connect(d->m_replaceTextEdit, SIGNAL(returnPressed()), this, SLOT(handleReplaceButton()));
connect(d->m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton())); connect(d->m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton()));
@@ -359,7 +360,7 @@ SearchResultWindow::~SearchResultWindow()
d->m_currentSearch = 0; d->m_currentSearch = 0;
delete d->m_widget; delete d->m_widget;
d->m_widget = 0; d->m_widget = 0;
d->m_items.clear(); d->m_itemCount = 0;
delete d; delete d;
} }
@@ -428,13 +429,13 @@ QList<SearchResultItem> SearchResultWindow::checkedItems() const
const int fileCount = model->rowCount(QModelIndex()); const int fileCount = model->rowCount(QModelIndex());
for (int i = 0; i < fileCount; ++i) { for (int i = 0; i < fileCount; ++i) {
QModelIndex fileIndex = model->index(i, 0, QModelIndex()); 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); Q_ASSERT(fileItem != 0);
for (int rowIndex = 0; rowIndex < fileItem->childrenCount(); ++rowIndex) { for (int rowIndex = 0; rowIndex < fileItem->childrenCount(); ++rowIndex) {
QModelIndex textIndex = model->index(rowIndex, 0, fileIndex); 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()) if (rowItem->checkState())
result << d->m_items.at(rowItem->index()); result << rowItem->item;
} }
} }
return result; return result;
@@ -492,7 +493,7 @@ SearchResult *SearchResultWindow::startNewSearch(SearchMode searchOrSearchAndRep
*/ */
void SearchResultWindow::finishSearch() void SearchResultWindow::finishSearch()
{ {
if (d->m_items.count()) { if (d->m_itemCount > 0) {
d->m_replaceButton->setEnabled(true); d->m_replaceButton->setEnabled(true);
} else { } else {
showNoMatchesFound(); showNoMatchesFound();
@@ -509,7 +510,7 @@ void SearchResultWindow::clearContents()
d->m_replaceButton->setEnabled(false); d->m_replaceButton->setEnabled(false);
d->m_replaceTextEdit->clear(); d->m_replaceTextEdit->clear();
d->m_searchResultTreeView->clear(); d->m_searchResultTreeView->clear();
d->m_items.clear(); d->m_itemCount = 0;
d->m_widget->setCurrentWidget(d->m_searchResultTreeView); d->m_widget->setCurrentWidget(d->m_searchResultTreeView);
navigateStateChanged(); navigateStateChanged();
} }
@@ -541,7 +542,7 @@ bool SearchResultWindow::isEmpty() const
*/ */
int SearchResultWindow::numberOfResults() const int SearchResultWindow::numberOfResults() const
{ {
return d->m_items.count(); return d->m_itemCount;
} }
/*! /*!
@@ -559,7 +560,7 @@ bool SearchResultWindow::hasFocus()
*/ */
bool SearchResultWindow::canFocus() bool SearchResultWindow::canFocus()
{ {
return !d->m_items.isEmpty(); return d->m_itemCount > 0;
} }
/*! /*!
@@ -568,7 +569,7 @@ bool SearchResultWindow::canFocus()
*/ */
void SearchResultWindow::setFocus() void SearchResultWindow::setFocus()
{ {
if (!d->m_items.isEmpty()) { if (d->m_itemCount > 0) {
if (!d->m_isShowingReplaceUI) { if (!d->m_isShowingReplaceUI) {
d->m_searchResultTreeView->setFocus(); d->m_searchResultTreeView->setFocus();
} else { } else {
@@ -597,10 +598,10 @@ void SearchResultWindow::setTextEditorFont(const QFont &font)
\fn void SearchResultWindow::handleJumpToSearchResult(int index, bool) \fn void SearchResultWindow::handleJumpToSearchResult(int index, bool)
\internal \internal
*/ */
void SearchResultWindow::handleJumpToSearchResult(int index, bool /* checked */) void SearchResultWindow::handleJumpToSearchResult(const SearchResultItem &item)
{ {
QTC_ASSERT(d->m_currentSearch, return); 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) int searchTermStart, int searchTermLength, const QVariant &userData)
{ {
SearchResultItem item; SearchResultItem item;
item.fileName = fileName; item.path = QStringList() << QDir::toNativeSeparators(fileName);
item.lineNumber = lineNumber; item.lineNumber = lineNumber;
item.lineText = rowText; item.text = rowText;
item.searchTermStart = searchTermStart; item.textMarkPos = searchTermStart;
item.searchTermLength = searchTermLength; item.textMarkLength = searchTermLength;
item.useTextEditorFont = true;
item.userData = userData; 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() \sa addResult()
*/ */
void SearchResultWindow::addResults(QList<SearchResultItem> &items) void SearchResultWindow::addResults(QList<SearchResultItem> &items, AddMode mode)
{ {
int index = d->m_items.size(); bool firstItems = (d->m_itemCount == 0);
bool firstItems = (index == 0); d->m_itemCount += items.size();
for (int i = 0; i < items.size(); ++i) { d->m_searchResultTreeView->addResults(items, mode);
items[i].index = index;
++index;
}
d->m_items << items;
d->m_searchResultTreeView->appendResultLines(items);
if (firstItems) { if (firstItems) {
d->m_replaceTextEdit->setEnabled(true); d->m_replaceTextEdit->setEnabled(true);
// We didn't have an item before, set the focus to the search widget // 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() bool SearchResultWindow::canNext()
{ {
return d->m_items.count() > 0; return d->m_itemCount > 0;
} }
/*! /*!
@@ -722,7 +718,7 @@ bool SearchResultWindow::canNext()
*/ */
bool SearchResultWindow::canPrevious() bool SearchResultWindow::canPrevious()
{ {
return d->m_items.count() > 0; return d->m_itemCount > 0;
} }
/*! /*!
@@ -731,7 +727,7 @@ bool SearchResultWindow::canPrevious()
*/ */
void SearchResultWindow::goToNext() void SearchResultWindow::goToNext()
{ {
if (d->m_items.count() == 0) if (d->m_itemCount == 0)
return; return;
QModelIndex idx = d->m_searchResultTreeView->model()->next(d->m_searchResultTreeView->currentIndex()); QModelIndex idx = d->m_searchResultTreeView->model()->next(d->m_searchResultTreeView->currentIndex());
if (idx.isValid()) { if (idx.isValid()) {

View File

@@ -32,10 +32,12 @@
#include "find_global.h" #include "find_global.h"
#include <QtCore/QVariant>
#include <coreplugin/ioutputpane.h> #include <coreplugin/ioutputpane.h>
#include <QtCore/QVariant>
#include <QtCore/QStringList>
#include <QtGui/QIcon>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QFont; class QFont;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -49,14 +51,34 @@ class SearchResultWindow;
struct FIND_EXPORT SearchResultItem struct FIND_EXPORT SearchResultItem
{ {
QString fileName; SearchResultItem()
int lineNumber; : textMarkPos(-1),
QString lineText; textMarkLength(0),
int searchTermStart; lineNumber(-1),
int searchTermLength; useTextEditorFont(false)
int index; // SearchResultWindow sets the index {
QVariant userData; }
// whatever information we also need here
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 class FIND_EXPORT SearchResult : public QObject
@@ -80,6 +102,11 @@ public:
SearchAndReplace SearchAndReplace
}; };
enum AddMode {
AddSorted,
AddOrdered
};
SearchResultWindow(); SearchResultWindow();
virtual ~SearchResultWindow(); virtual ~SearchResultWindow();
static SearchResultWindow *instance(); static SearchResultWindow *instance();
@@ -110,7 +137,7 @@ public:
// search result object only lives till next startnewsearch call // search result object only lives till next startnewsearch call
SearchResult *startNewSearch(SearchMode searchOrSearchAndReplace = SearchOnly); SearchResult *startNewSearch(SearchMode searchOrSearchAndReplace = SearchOnly);
void addResults(QList<SearchResultItem> &items); void addResults(QList<SearchResultItem> &items, AddMode mode);
public slots: public slots:
void clearContents(); void clearContents();
void addResult(const QString &fileName, int lineNumber, const QString &lineText, void addResult(const QString &fileName, int lineNumber, const QString &lineText,
@@ -119,7 +146,7 @@ public slots:
private slots: private slots:
void handleExpandCollapseToolButton(bool checked); void handleExpandCollapseToolButton(bool checked);
void handleJumpToSearchResult(int index, bool checked); void handleJumpToSearchResult(const SearchResultItem &item);
void handleReplaceButton(); void handleReplaceButton();
void showNoMatchesFound(); void showNoMatchesFound();
@@ -135,4 +162,6 @@ private:
} // namespace Find } // namespace Find
Q_DECLARE_METATYPE(Find::SearchResultItem)
#endif // SEARCHRESULTWINDOW_H #endif // SEARCHRESULTWINDOW_H

View File

@@ -128,6 +128,7 @@ plugin_cpptools.subdir = cpptools
plugin_cpptools.depends = plugin_projectexplorer plugin_cpptools.depends = plugin_projectexplorer
plugin_cpptools.depends += plugin_coreplugin plugin_cpptools.depends += plugin_coreplugin
plugin_cpptools.depends += plugin_texteditor plugin_cpptools.depends += plugin_texteditor
plugin_cpptools.depends += plugin_find
plugin_bookmarks.subdir = bookmarks plugin_bookmarks.subdir = bookmarks
plugin_bookmarks.depends = plugin_projectexplorer plugin_bookmarks.depends = plugin_projectexplorer

View File

@@ -72,11 +72,6 @@ bool AllProjectsFind::isEnabled() const
&& m_plugin->session()->projects().count() > 0; && m_plugin->session()->projects().count() > 0;
} }
QKeySequence AllProjectsFind::defaultShortcut() const
{
return QKeySequence();
}
Utils::FileIterator *AllProjectsFind::files() Utils::FileIterator *AllProjectsFind::files()
{ {
Q_ASSERT(m_plugin->session()); Q_ASSERT(m_plugin->session());

View File

@@ -54,7 +54,6 @@ public:
QString displayName() const; QString displayName() const;
bool isEnabled() const; bool isEnabled() const;
QKeySequence defaultShortcut() const;
QWidget *createConfigWidget(); QWidget *createConfigWidget();
void writeSettings(QSettings *settings); void writeSettings(QSettings *settings);

View File

@@ -70,11 +70,6 @@ bool CurrentProjectFind::isEnabled() const
return m_plugin->currentProject() != 0 && BaseFileFind::isEnabled(); return m_plugin->currentProject() != 0 && BaseFileFind::isEnabled();
} }
QKeySequence CurrentProjectFind::defaultShortcut() const
{
return QKeySequence();
}
Utils::FileIterator *CurrentProjectFind::files() Utils::FileIterator *CurrentProjectFind::files()
{ {
Project *project = m_plugin->currentProject(); Project *project = m_plugin->currentProject();

View File

@@ -57,7 +57,6 @@ public:
QString displayName() const; QString displayName() const;
bool isEnabled() const; bool isEnabled() const;
QKeySequence defaultShortcut() const;
QWidget *createConfigWidget(); QWidget *createConfigWidget();
void writeSettings(QSettings *settings); void writeSettings(QSettings *settings);

View File

@@ -153,15 +153,16 @@ void BaseFileFind::displayResult(int index) {
QList<Find::SearchResultItem> items; // this conversion is stupid... QList<Find::SearchResultItem> items; // this conversion is stupid...
foreach (const Utils::FileSearchResult &result, results) { foreach (const Utils::FileSearchResult &result, results) {
Find::SearchResultItem item; Find::SearchResultItem item;
item.fileName = result.fileName; item.path = QStringList() << QDir::toNativeSeparators(result.fileName);
item.lineNumber = result.lineNumber; item.lineNumber = result.lineNumber;
item.lineText = result.matchingLine; item.text = result.matchingLine;
item.searchTermLength = result.matchLength; item.textMarkLength = result.matchLength;
item.searchTermStart = result.matchStart; item.textMarkPos = result.matchStart;
item.useTextEditorFont = true;
item.userData = result.regexpCapturedTexts; item.userData = result.regexpCapturedTexts;
items << item; items << item;
} }
m_resultWindow->addResults(items); m_resultWindow->addResults(items, Find::SearchResultWindow::AddOrdered);
if (m_resultLabel) if (m_resultLabel)
m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults())); 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) 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 // #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; const int blockNumber = item.lineNumber - 1;
QTextCursor tc(doc->findBlockByNumber(blockNumber)); QTextCursor tc(doc->findBlockByNumber(blockNumber));
const int cursorPosition = tc.position() + item.searchTermStart; const int cursorPosition = tc.position() + item.textMarkPos;
int cursorIndex = 0; int cursorIndex = 0;
for (; cursorIndex < changes.size(); ++cursorIndex) { for (; cursorIndex < changes.size(); ++cursorIndex) {
@@ -277,7 +282,7 @@ static void applyChanges(QTextDocument *doc, const QString &text, const QList<Fi
continue; // skip this change. continue; // skip this change.
tc.setPosition(cursorPosition); tc.setPosition(cursorPosition);
tc.setPosition(tc.position() + item.searchTermLength, tc.setPosition(tc.position() + item.textMarkLength,
QTextCursor::KeepAnchor); QTextCursor::KeepAnchor);
QString substitutionText; QString substitutionText;
if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty()) 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; QHash<QString, QList<Find::SearchResultItem> > changes;
foreach (const Find::SearchResultItem &item, items) foreach (const Find::SearchResultItem &item, items)
changes[item.fileName].append(item); changes[item.path.first()].append(item);
Core::EditorManager *editorManager = Core::EditorManager::instance(); Core::EditorManager *editorManager = Core::EditorManager::instance();

View File

@@ -62,11 +62,6 @@ QString FindInCurrentFile::displayName() const
return tr("Current File"); return tr("Current File");
} }
QKeySequence FindInCurrentFile::defaultShortcut() const
{
return QKeySequence();
}
Utils::FileIterator *FindInCurrentFile::files() Utils::FileIterator *FindInCurrentFile::files()
{ {
QStringList fileList; QStringList fileList;

View File

@@ -55,7 +55,6 @@ public:
QString id() const; QString id() const;
QString displayName() const; QString displayName() const;
QKeySequence defaultShortcut() const;
bool isEnabled() const; bool isEnabled() const;
QWidget *createConfigWidget(); QWidget *createConfigWidget();
void writeSettings(QSettings *settings); void writeSettings(QSettings *settings);

View File

@@ -57,11 +57,6 @@ QString FindInFiles::displayName() const
return tr("Files on File System"); return tr("Files on File System");
} }
QKeySequence FindInFiles::defaultShortcut() const
{
return QKeySequence();
}
void FindInFiles::findAll(const QString &txt, Find::FindFlags findFlags) void FindInFiles::findAll(const QString &txt, Find::FindFlags findFlags)
{ {
updateComboEntries(m_directory, true); updateComboEntries(m_directory, true);

View File

@@ -53,7 +53,6 @@ public:
QString id() const; QString id() const;
QString displayName() const; QString displayName() const;
QKeySequence defaultShortcut() const;
void findAll(const QString &txt, Find::FindFlags findFlags); void findAll(const QString &txt, Find::FindFlags findFlags);
QWidget *createConfigWidget(); QWidget *createConfigWidget();
void writeSettings(QSettings *settings); void writeSettings(QSettings *settings);