Commit 2d2dfac8 authored by Aurindam Jana's avatar Aurindam Jana

ScriptConsole: Add Find functionality

SearchResultFindSupport is now renamed as TreeViewFind.
It offers a generic way of searching text in a tree view.
ScriptConsole and SearchResultWidget uses TreeViewFind.

Change-Id: I2672d8fa5f1d20a35a751d8e85f8a8026b949643
Reviewed-by: default avatarEike Ziller <eike.ziller@nokia.com>
parent 44c1a259
......@@ -43,6 +43,10 @@
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/findplaceholder.h>
#include <aggregation/aggregate.h>
#include <find/treeviewfind.h>
#include <QSettings>
#include <QHBoxLayout>
......@@ -168,10 +172,15 @@ QtMessageLogWindow::QtMessageLogWindow(QWidget *parent)
vbox->addWidget(statusbarContainer);
vbox->addWidget(m_treeView);
vbox->addWidget(new Core::FindToolBarPlaceHolder(this));
readSettings();
connect(Core::ICore::instance(),
SIGNAL(saveSettingsRequested()), SLOT(writeSettings()));
Aggregation::Aggregate *aggregate = new Aggregation::Aggregate();
aggregate->add(m_treeView);
aggregate->add(new Find::TreeViewFind(m_treeView));
}
QtMessageLogWindow::~QtMessageLogWindow()
......
......@@ -18,7 +18,8 @@ HEADERS += findtoolwindow.h \
searchresulttreemodel.h \
searchresulttreeview.h \
searchresultwindow.h \
searchresultwidget.h
searchresultwidget.h \
treeviewfind.h
SOURCES += findtoolwindow.cpp \
currentdocumentfind.cpp \
basetextfind.cpp \
......@@ -31,7 +32,8 @@ SOURCES += findtoolwindow.cpp \
searchresultwindow.cpp \
ifindfilter.cpp \
ifindsupport.cpp \
searchresultwidget.cpp
searchresultwidget.cpp \
treeviewfind.cpp
FORMS += findwidget.ui \
finddialog.ui
RESOURCES += find.qrc
......
......@@ -492,13 +492,6 @@ QModelIndex SearchResultTreeModel::prevIndex(const QModelIndex &idx, bool *wrapp
return current;
}
QModelIndex SearchResultTreeModel::followingIndex(const QModelIndex &idx, bool backward, bool includeGenerated, bool *wrapped)
{
if (backward)
return prev(idx, includeGenerated, wrapped);
return next(idx, includeGenerated, wrapped);
}
QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx, bool includeGenerated, bool *wrapped) const
{
QModelIndex value = idx;
......@@ -507,61 +500,3 @@ QModelIndex SearchResultTreeModel::prev(const QModelIndex &idx, bool includeGene
} while (value != idx && !includeGenerated && treeItemAtIndex(value)->isGenerated());
return value;
}
QModelIndex SearchResultTreeModel::find(const QRegExp &expr, const QModelIndex &index,
QTextDocument::FindFlags flags,
bool startWithCurrentIndex, bool *wrapped)
{
QModelIndex resultIndex;
QModelIndex currentIndex = index;
bool backward = (flags & QTextDocument::FindBackward);
if (wrapped)
*wrapped = false;
bool anyWrapped = false;
bool stepWrapped = false;
if (!startWithCurrentIndex)
currentIndex = followingIndex(currentIndex, backward, true, &stepWrapped);
do {
anyWrapped |= stepWrapped; // update wrapped state if we actually stepped to next/prev item
if (currentIndex.isValid()) {
const QString &text = data(currentIndex, ItemDataRoles::ResultLineRole).toString();
if (expr.indexIn(text) != -1)
resultIndex = currentIndex;
}
currentIndex = followingIndex(currentIndex, backward, true, &stepWrapped);
} while (!resultIndex.isValid() && currentIndex.isValid() && currentIndex != index);
if (resultIndex.isValid() && wrapped)
*wrapped = anyWrapped;
return resultIndex;
}
QModelIndex SearchResultTreeModel::find(const QString &term, const QModelIndex &index,
QTextDocument::FindFlags flags,
bool startWithCurrentIndex, bool *wrapped)
{
QModelIndex resultIndex;
QModelIndex currentIndex = index;
bool backward = (flags & QTextDocument::FindBackward);
flags = (flags & (~QTextDocument::FindBackward)); // backward is handled by us ourselves
if (wrapped)
*wrapped = false;
bool anyWrapped = false;
bool stepWrapped = false;
if (!startWithCurrentIndex)
currentIndex = followingIndex(currentIndex, backward, true, &stepWrapped);
do {
anyWrapped |= stepWrapped; // update wrapped state if we actually stepped to next/prev item
if (currentIndex.isValid()) {
const QString &text = data(currentIndex, ItemDataRoles::ResultLineRole).toString();
QTextDocument doc(text);
if (!doc.find(term, 0, flags).isNull())
resultIndex = currentIndex;
}
currentIndex = followingIndex(currentIndex, backward, true, &stepWrapped);
} while (!resultIndex.isValid() && currentIndex.isValid() && currentIndex != index);
if (resultIndex.isValid() && wrapped)
*wrapped = anyWrapped;
return resultIndex;
}
......@@ -70,11 +70,6 @@ public:
QList<QModelIndex> addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
QModelIndex find(const QRegExp &expr, const QModelIndex &index,
QTextDocument::FindFlags flags, bool startWithCurrentIndex, bool *wrapped = 0);
QModelIndex find(const QString &term, const QModelIndex &index,
QTextDocument::FindFlags flags, bool startWithCurrentIndex, bool *wrapped = 0);
signals:
void jumpToSearchResult(const QString &fileName, int lineNumber,
int searchTermStart, int searchTermLength);
......@@ -90,8 +85,6 @@ private:
bool setCheckState(const QModelIndex &idx, Qt::CheckState checkState, bool firstCall = true);
QModelIndex nextIndex(const QModelIndex &idx, bool *wrapped = 0) const;
QModelIndex prevIndex(const QModelIndex &idx, bool *wrapped = 0) const;
QModelIndex followingIndex(const QModelIndex &idx, bool backward, bool includeGenerated = false,
bool *wrapped = 0);
SearchResultTreeItem *treeItemAtIndex(const QModelIndex &idx) const;
SearchResultTreeItem *m_rootItem;
......
......@@ -34,8 +34,10 @@
#include "searchresulttreeview.h"
#include "searchresulttreemodel.h"
#include "searchresulttreeitems.h"
#include "searchresulttreeitemroles.h"
#include "ifindsupport.h"
#include "treeviewfind.h"
#include <aggregation/aggregate.h>
#include <coreplugin/icore.h>
......@@ -66,142 +68,6 @@ public slots:
void updateGeometry() { QLineEdit::updateGeometry(); }
};
class SearchResultFindSupport : public IFindSupport
{
Q_OBJECT
public:
SearchResultFindSupport(SearchResultTreeView *view)
: m_view(view),
m_incrementalWrappedState(false)
{
}
bool supportsReplace() const { return false; }
Find::FindFlags supportedFindFlags() const
{
return Find::FindBackward | Find::FindCaseSensitively
| Find::FindRegularExpression | Find::FindWholeWords;
}
void resetIncrementalSearch()
{
m_incrementalFindStart = QModelIndex();
m_incrementalWrappedState = false;
}
void clearResults() { }
QString currentFindString() const
{
return QString();
}
QString completedFindString() const
{
return QString();
}
void highlightAll(const QString &txt, Find::FindFlags findFlags)
{
Q_UNUSED(txt)
Q_UNUSED(findFlags)
return;
}
IFindSupport::Result findIncremental(const QString &txt, Find::FindFlags findFlags)
{
if (!m_incrementalFindStart.isValid()) {
m_incrementalFindStart = m_view->currentIndex();
m_incrementalWrappedState = false;
}
m_view->setCurrentIndex(m_incrementalFindStart);
bool wrapped = false;
IFindSupport::Result result = find(txt, findFlags, true/*startFromCurrent*/, &wrapped);
if (wrapped != m_incrementalWrappedState) {
m_incrementalWrappedState = wrapped;
showWrapIndicator(m_view);
}
return result;
}
IFindSupport::Result findStep(const QString &txt, Find::FindFlags findFlags)
{
bool wrapped = false;
IFindSupport::Result result = find(txt, findFlags, false/*startFromNext*/, &wrapped);
if (wrapped)
showWrapIndicator(m_view);
if (result == IFindSupport::Found) {
m_incrementalFindStart = m_view->currentIndex();
m_incrementalWrappedState = false;
}
return result;
}
IFindSupport::Result find(const QString &txt, Find::FindFlags findFlags,
bool startFromCurrentIndex, bool *wrapped)
{
if (wrapped)
*wrapped = false;
if (txt.isEmpty())
return IFindSupport::NotFound;
QModelIndex index;
if (findFlags & Find::FindRegularExpression) {
bool sensitive = (findFlags & Find::FindCaseSensitively);
index = m_view->model()->find(QRegExp(txt, (sensitive ? Qt::CaseSensitive : Qt::CaseInsensitive)),
m_view->currentIndex(),
Find::textDocumentFlagsForFindFlags(findFlags),
startFromCurrentIndex,
wrapped);
} else {
index = m_view->model()->find(txt,
m_view->currentIndex(),
Find::textDocumentFlagsForFindFlags(findFlags),
startFromCurrentIndex,
wrapped);
}
if (index.isValid()) {
m_view->setCurrentIndex(index);
m_view->scrollTo(index);
if (index.parent().isValid())
m_view->expand(index.parent());
return IFindSupport::Found;
}
return IFindSupport::NotFound;
}
void replace(const QString &before, const QString &after,
Find::FindFlags findFlags)
{
Q_UNUSED(before)
Q_UNUSED(after)
Q_UNUSED(findFlags)
}
bool replaceStep(const QString &before, const QString &after,
Find::FindFlags findFlags)
{
Q_UNUSED(before)
Q_UNUSED(after)
Q_UNUSED(findFlags)
return false;
}
int replaceAll(const QString &before, const QString &after,
Find::FindFlags findFlags)
{
Q_UNUSED(before)
Q_UNUSED(after)
Q_UNUSED(findFlags)
return 0;
}
private:
SearchResultTreeView *m_view;
QModelIndex m_incrementalFindStart;
bool m_incrementalWrappedState;
};
} // Internal
} // Find
......@@ -236,7 +102,8 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
m_searchResultTreeView->setAttribute(Qt::WA_MacShowFocusRect, false);
Aggregation::Aggregate * agg = new Aggregation::Aggregate;
agg->add(m_searchResultTreeView);
agg->add(new SearchResultFindSupport(m_searchResultTreeView));
agg->add(new TreeViewFind(m_searchResultTreeView,
ItemDataRoles::ResultLineRole));
layout->addWidget(topWidget);
layout->addWidget(m_searchResultTreeView);
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "treeviewfind.h"
#include <QTreeView>
#include <QTextCursor>
namespace Find {
struct ItemModelFindPrivate
{
explicit ItemModelFindPrivate(QTreeView *view, int role, int column)
: m_view(view)
, m_incrementalWrappedState(false),
m_role(role),
m_column(column)
{
}
QTreeView *m_view;
QModelIndex m_incrementalFindStart;
bool m_incrementalWrappedState;
int m_role;
int m_column;
};
TreeViewFind::TreeViewFind(QTreeView *view, int role, int column)
: d(new ItemModelFindPrivate(view, role, column))
{
}
TreeViewFind::~TreeViewFind()
{
delete d;
}
bool TreeViewFind::supportsReplace() const
{
return false;
}
Find::FindFlags TreeViewFind::supportedFindFlags() const
{
return Find::FindBackward | Find::FindCaseSensitively
| Find::FindRegularExpression | Find::FindWholeWords;
}
void TreeViewFind::resetIncrementalSearch()
{
d->m_incrementalFindStart = QModelIndex();
d->m_incrementalWrappedState = false;
}
void TreeViewFind::clearResults()
{
}
QString TreeViewFind::currentFindString() const
{
return QString();
}
QString TreeViewFind::completedFindString() const
{
return QString();
}
void TreeViewFind::highlightAll(const QString &/*txt*/, FindFlags /*findFlags*/)
{
}
IFindSupport::Result TreeViewFind::findIncremental(const QString &txt,
Find::FindFlags findFlags)
{
if (!d->m_incrementalFindStart.isValid()) {
d->m_incrementalFindStart = d->m_view->currentIndex();
d->m_incrementalWrappedState = false;
}
d->m_view->setCurrentIndex(d->m_incrementalFindStart);
bool wrapped = false;
IFindSupport::Result result = find(txt, findFlags, true/*startFromCurrent*/,
&wrapped);
if (wrapped != d->m_incrementalWrappedState) {
d->m_incrementalWrappedState = wrapped;
showWrapIndicator(d->m_view);
}
return result;
}
IFindSupport::Result TreeViewFind::findStep(const QString &txt,
Find::FindFlags findFlags)
{
bool wrapped = false;
IFindSupport::Result result = find(txt, findFlags, false/*startFromNext*/,
&wrapped);
if (wrapped)
showWrapIndicator(d->m_view);
if (result == IFindSupport::Found) {
d->m_incrementalFindStart = d->m_view->currentIndex();
d->m_incrementalWrappedState = false;
}
return result;
}
void TreeViewFind::replace(const QString &/*before*/, const QString &/*after*/,
Find::FindFlags /*findFlags*/)
{
}
bool TreeViewFind::replaceStep(const QString &/*before*/,
const QString &/*after*/,
Find::FindFlags /*findFlags*/)
{
return false;
}
int TreeViewFind::replaceAll(const QString &/*before*/,
const QString &/*after*/,
Find::FindFlags /*findFlags*/)
{
return 0;
}
IFindSupport::Result TreeViewFind::find(const QString &searchTxt,
Find::FindFlags findFlags,
bool startFromCurrentIndex,
bool *wrapped)
{
if (wrapped)
*wrapped = false;
if (searchTxt.isEmpty())
return IFindSupport::NotFound;
QTextDocument::FindFlags flags =
Find::textDocumentFlagsForFindFlags(findFlags);
QModelIndex resultIndex;
QModelIndex currentIndex = d->m_view->currentIndex();
QModelIndex index = currentIndex;
bool backward = (flags & QTextDocument::FindBackward);
if (wrapped)
*wrapped = false;
bool anyWrapped = false;
bool stepWrapped = false;
if (!startFromCurrentIndex)
index = followingIndex(index, backward, &stepWrapped);
do {
anyWrapped |= stepWrapped; // update wrapped state if we actually stepped to next/prev item
if (index.isValid()) {
const QString &text = d->m_view->model()->data(
index, d->m_role).toString();
if (findFlags & Find::FindRegularExpression) {
bool sensitive = (findFlags & Find::FindCaseSensitively);
QRegExp searchExpr = QRegExp(searchTxt,
(sensitive ? Qt::CaseSensitive :
Qt::CaseInsensitive));
if (searchExpr.indexIn(text) != -1)
resultIndex = index;
} else {
QTextDocument doc(text);
if (!doc.find(searchTxt, 0, flags).isNull())
resultIndex = index;
}
}
index = followingIndex(index, backward, &stepWrapped);
} while (!resultIndex.isValid() && index.isValid() && index != currentIndex);
if (resultIndex.isValid()) {
d->m_view->setCurrentIndex(resultIndex);
d->m_view->scrollTo(resultIndex);
if (resultIndex.parent().isValid())
d->m_view->expand(resultIndex.parent());
if (wrapped)
*wrapped = anyWrapped;
return IFindSupport::Found;
}
return IFindSupport::NotFound;
}
QModelIndex TreeViewFind::nextIndex(const QModelIndex &idx, bool *wrapped) const
{
if (wrapped)
*wrapped = false;
QAbstractItemModel *model = d->m_view->model();
// pathological
if (!idx.isValid())
return model->index(0, 0);
if (model->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 < model->rowCount(current)) {
// Same parent has another child
nextIndex = model->index(row + 1, 0, current);
} else {
// go up one parent
if (!current.isValid()) {
// we start from the beginning
if (wrapped)
*wrapped = true;
nextIndex = model->index(0, 0);
}
}
}
return nextIndex;
}
QModelIndex TreeViewFind::prevIndex(const QModelIndex &idx, bool *wrapped) const
{
if (wrapped)
*wrapped = false;
QModelIndex current = idx;
bool checkForChildren = true;
QAbstractItemModel *model = d->m_view->model();
if (current.isValid()) {
int row = current.row();
if (row > 0) {
current = model->index(row - 1, 0, current.parent());
} else {
current = current.parent();
checkForChildren = !current.isValid();
if (checkForChildren && wrapped) {
// we start from the end
*wrapped = true;
}
}
}
if (checkForChildren) {
// traverse down the hierarchy
while (int rc = model->rowCount(current)) {
current = model->index(rc - 1, d->m_column, current);
}
}
return current;
}
QModelIndex TreeViewFind::followingIndex(const QModelIndex &idx, bool backward, bool *wrapped)
{
if (backward)
return prevIndex(idx, wrapped);
return nextIndex(idx, wrapped);
}
} // namespace Find
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef ITEMMODELFIND_H
#define ITEMMODELFIND_H
#include "ifindsupport.h"
#include <QModelIndex>
QT_BEGIN_NAMESPACE
class QTreeView;
QT_END_NAMESPACE
namespace Find {
class ItemModelFindPrivate;
class FIND_EXPORT TreeViewFind : public Find::IFindSupport
{
Q_OBJECT
public:
explicit TreeViewFind(QTreeView *view, int role = Qt::DisplayRole,
int column = 0);
virtual ~TreeViewFind();
bool supportsReplace() const;
Find::FindFlags supportedFindFlags() const;
void resetIncrementalSearch();
void clearResults();
QString currentFindString() const;
QString completedFindString() const;
virtual void highlightAll(const QString &txt, FindFlags findFlags);
Result findIncremental(const QString &txt, Find::FindFlags findFlags);
Result findStep(const QString &txt, Find::FindFlags findFlags);
void replace(const QString &before, const QString &after,
Find::FindFlags findFlags);
bool replaceStep(const QString &before, const QString &after,
Find::FindFlags findFlags);
int replaceAll(const QString &before, const QString &after,
Find::FindFlags findFlags);
private:
Result find(const QString &txt, Find::FindFlags findFlags,
bool startFromCurrentIndex, bool *wrapped);
QModelIndex nextIndex(const QModelIndex &idx, bool *wrapped) const;
QModelIndex prevIndex(const QModelIndex &idx, bool *wrapped) const;
QModelIndex followingIndex(const QModelIndex &idx, bool backward,
bool *wrapped);