From b0b35a356d78210000d62fa8c77669944bc83d19 Mon Sep 17 00:00:00 2001
From: Eike Ziller <eike.ziller@nokia.com>
Date: Tue, 6 Sep 2011 13:03:15 +0200
Subject: [PATCH] Refactor the search result widget to its own class.

To be used for switching between multiple search result lists.

Change-Id: I4cf62f7e5adf71bac7d4fdfed05d74cea4f3ca44
Rubber-stamped-by: Daniel Teske
Reviewed-on: http://codereview.qt.nokia.com/4255
Reviewed-by: Eike Ziller <eike.ziller@nokia.com>
---
 src/plugins/find/find.pro               |   8 +-
 src/plugins/find/searchresultwidget.cpp | 489 +++++++++++++++++++++++
 src/plugins/find/searchresultwidget.h   | 125 ++++++
 src/plugins/find/searchresultwindow.cpp | 506 +++---------------------
 src/plugins/find/searchresultwindow.h   |  25 +-
 5 files changed, 670 insertions(+), 483 deletions(-)
 create mode 100644 src/plugins/find/searchresultwidget.cpp
 create mode 100644 src/plugins/find/searchresultwidget.h

diff --git a/src/plugins/find/find.pro b/src/plugins/find/find.pro
index ba9f99fcf29..ac24d230643 100644
--- a/src/plugins/find/find.pro
+++ b/src/plugins/find/find.pro
@@ -17,7 +17,8 @@ HEADERS += findtoolwindow.h \
     searchresulttreeitems.h \
     searchresulttreemodel.h \
     searchresulttreeview.h \
-    searchresultwindow.h
+    searchresultwindow.h \
+    searchresultwidget.h
 SOURCES += findtoolwindow.cpp \
     currentdocumentfind.cpp \
     basetextfind.cpp \
@@ -29,7 +30,10 @@ SOURCES += findtoolwindow.cpp \
     searchresulttreeview.cpp \
     searchresultwindow.cpp \
     ifindfilter.cpp \
-    ifindsupport.cpp
+    ifindsupport.cpp \
+    searchresultwidget.cpp
 FORMS += findwidget.ui \
     finddialog.ui
 RESOURCES += find.qrc
+
+
diff --git a/src/plugins/find/searchresultwidget.cpp b/src/plugins/find/searchresultwidget.cpp
new file mode 100644
index 00000000000..8bd7f0c0324
--- /dev/null
+++ b/src/plugins/find/searchresultwidget.cpp
@@ -0,0 +1,489 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.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 info@qt.nokia.com.
+**
+**************************************************************************/
+
+#include "searchresultwidget.h"
+#include "searchresulttreeview.h"
+#include "searchresulttreemodel.h"
+#include "searchresulttreeitems.h"
+
+#include "ifindsupport.h"
+
+#include <aggregation/aggregate.h>
+#include <coreplugin/icore.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+#include <QtGui/QVBoxLayout>
+
+namespace Find {
+namespace Internal {
+
+class WideEnoughLineEdit : public QLineEdit {
+    Q_OBJECT
+public:
+    WideEnoughLineEdit(QWidget *parent):QLineEdit(parent){
+        connect(this, SIGNAL(textChanged(QString)),
+                this, SLOT(updateGeometry()));
+    }
+    ~WideEnoughLineEdit(){}
+    QSize sizeHint() const {
+        QSize sh = QLineEdit::minimumSizeHint();
+        sh.rwidth() += qMax(25 * fontMetrics().width(QLatin1Char('x')),
+                            fontMetrics().width(text()));
+        return sh;
+    }
+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, &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, &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 *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),
+                                          wrapped);
+        } else {
+            index = m_view->model()->find(txt,
+                                          m_view->currentIndex(),
+                                          Find::textDocumentFlagsForFindFlags(findFlags),
+                                          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
+
+using namespace Find;
+using namespace Find::Internal;
+
+SearchResultWidget::SearchResultWidget(QWidget *parent) :
+    QWidget(parent),
+    m_count(0),
+    m_isShowingReplaceUI(false)
+{
+    QVBoxLayout *layout = new QVBoxLayout(this);
+    layout->setMargin(0);
+    layout->setSpacing(0);
+    setLayout(layout);
+
+    m_noMatchesFoundDisplay = new QListWidget(this);
+    m_noMatchesFoundDisplay->addItem(tr("No matches found!"));
+    m_noMatchesFoundDisplay->setFrameStyle(QFrame::NoFrame);
+    m_noMatchesFoundDisplay->hide();
+
+    m_searchResultTreeView = new Internal::SearchResultTreeView(this);
+    m_searchResultTreeView->setFrameStyle(QFrame::NoFrame);
+    m_searchResultTreeView->setAttribute(Qt::WA_MacShowFocusRect, false);
+    Aggregation::Aggregate * agg = new Aggregation::Aggregate;
+    agg->add(m_searchResultTreeView);
+    agg->add(new SearchResultFindSupport(m_searchResultTreeView));
+
+    layout->addWidget(m_noMatchesFoundDisplay);
+    layout->addWidget(m_searchResultTreeView);
+
+    m_infoBarDisplay.setTarget(layout, 0);
+    m_infoBarDisplay.setInfoBar(&m_infoBar);
+
+    m_replaceLabel = new QLabel(tr("Replace with:"), parent);
+    m_replaceLabel->setContentsMargins(12, 0, 5, 0);
+    m_replaceTextEdit = new WideEnoughLineEdit(parent);
+    m_replaceButton = new QToolButton(parent);
+    m_replaceButton->setToolTip(tr("Replace all occurrences"));
+    m_replaceButton->setText(tr("Replace"));
+    m_replaceButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
+    m_replaceButton->setAutoRaise(true);
+    m_replaceTextEdit->setTabOrder(m_replaceTextEdit, m_searchResultTreeView);
+    setShowReplaceUI(false);
+
+    connect(m_searchResultTreeView, SIGNAL(jumpToSearchResult(SearchResultItem)),
+            this, SLOT(handleJumpToSearchResult(SearchResultItem)));
+    connect(m_replaceTextEdit, SIGNAL(returnPressed()), this, SLOT(handleReplaceButton()));
+    connect(m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton()));
+}
+
+void SearchResultWidget::addResult(const QString &fileName, int lineNumber, const QString &rowText,
+    int searchTermStart, int searchTermLength, const QVariant &userData)
+{
+    SearchResultItem item;
+    item.path = QStringList() << QDir::toNativeSeparators(fileName);
+    item.lineNumber = lineNumber;
+    item.text = rowText;
+    item.textMarkPos = searchTermStart;
+    item.textMarkLength = searchTermLength;
+    item.useTextEditorFont = true;
+    item.userData = userData;
+    addResults(QList<SearchResultItem>() << item, SearchResult::AddOrdered);
+}
+
+void SearchResultWidget::addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode)
+{
+    bool firstItems = (m_count == 0);
+    m_count += items.size();
+    m_searchResultTreeView->addResults(items, mode);
+    if (firstItems) {
+        if (!m_dontAskAgainGroup.isEmpty() && showWarningMessage()) {
+            Core::InfoBarEntry info("warninglabel", tr("This change cannot be undone."));
+            info.setCustomButtonInfo(tr("Do not warn again"), this, SLOT(hideNoUndoWarning()));
+            m_infoBar.addInfo(info);
+        }
+
+        m_replaceTextEdit->setEnabled(true);
+        // We didn't have an item before, set the focus to the search widget or replace text edit
+        if (m_isShowingReplaceUI) {
+            m_replaceTextEdit->setFocus();
+            m_replaceTextEdit->selectAll();
+        } else {
+            m_searchResultTreeView->setFocus();
+        }
+        m_searchResultTreeView->selectionModel()->select(m_searchResultTreeView->model()->index(0, 0, QModelIndex()), QItemSelectionModel::Select);
+        emit navigateStateChanged();
+    }
+}
+
+int SearchResultWidget::count() const
+{
+    return m_count;
+}
+
+QString SearchResultWidget::dontAskAgainGroup() const
+{
+    return m_dontAskAgainGroup;
+}
+
+void SearchResultWidget::setDontAskAgainGroup(const QString &group)
+{
+    m_dontAskAgainGroup = group;
+}
+
+
+void SearchResultWidget::setTextToReplace(const QString &textToReplace)
+{
+    m_replaceTextEdit->setText(textToReplace);
+}
+
+QString SearchResultWidget::textToReplace() const
+{
+    return m_replaceTextEdit->text();
+}
+
+void SearchResultWidget::setShowReplaceUI(bool visible)
+{
+    m_searchResultTreeView->model()->setShowReplaceUI(visible);
+    m_replaceLabel->setVisible(visible);
+    m_replaceTextEdit->setVisible(visible);
+    m_replaceButton->setVisible(visible);
+    m_isShowingReplaceUI = visible;
+}
+
+bool SearchResultWidget::hasFocusInternally() const
+{
+    return m_searchResultTreeView->hasFocus() || (m_isShowingReplaceUI && m_replaceTextEdit->hasFocus());
+}
+
+void SearchResultWidget::setFocusInternally()
+{
+    if (m_count > 0) {
+        if (m_isShowingReplaceUI) {
+            if (!focusWidget() || focusWidget() == m_replaceTextEdit) {
+                m_replaceTextEdit->setFocus();
+                m_replaceTextEdit->selectAll();
+            } else {
+                m_searchResultTreeView->setFocus();
+            }
+        } else {
+            m_searchResultTreeView->setFocus();
+        }
+    }
+}
+
+bool SearchResultWidget::canFocusInternally() const
+{
+    return m_count > 0;
+}
+
+void SearchResultWidget::notifyVisibilityChanged(bool visible)
+{
+    emit visibilityChanged(visible);
+}
+
+void SearchResultWidget::setTextEditorFont(const QFont &font)
+{
+    m_searchResultTreeView->setTextEditorFont(font);
+}
+
+void SearchResultWidget::setAutoExpandResults(bool expand)
+{
+    m_searchResultTreeView->setAutoExpandResults(expand);
+}
+
+void SearchResultWidget::expandAll()
+{
+    m_searchResultTreeView->expandAll();
+}
+
+void SearchResultWidget::collapseAll()
+{
+    m_searchResultTreeView->collapseAll();
+}
+
+void SearchResultWidget::goToNext()
+{
+    if (m_count == 0)
+        return;
+    QModelIndex idx = m_searchResultTreeView->model()->next(m_searchResultTreeView->currentIndex());
+    if (idx.isValid()) {
+        m_searchResultTreeView->setCurrentIndex(idx);
+        m_searchResultTreeView->emitJumpToSearchResult(idx);
+    }
+}
+
+void SearchResultWidget::goToPrevious()
+{
+    if (!m_searchResultTreeView->model()->rowCount())
+        return;
+    QModelIndex idx = m_searchResultTreeView->model()->prev(m_searchResultTreeView->currentIndex());
+    if (idx.isValid()) {
+        m_searchResultTreeView->setCurrentIndex(idx);
+        m_searchResultTreeView->emitJumpToSearchResult(idx);
+    }
+}
+
+void SearchResultWidget::finishSearch()
+{
+    if (m_count > 0) {
+        m_replaceButton->setEnabled(true);
+    } else {
+        showNoMatchesFound();
+    }
+}
+
+void SearchResultWidget::clear()
+{
+    m_replaceTextEdit->setEnabled(false);
+    m_replaceButton->setEnabled(false);
+    m_replaceTextEdit->clear();
+    m_searchResultTreeView->clear();
+    m_count = 0;
+    m_noMatchesFoundDisplay->hide();
+    m_infoBar.clear();
+}
+
+void SearchResultWidget::showNoMatchesFound()
+{
+    m_replaceTextEdit->setEnabled(false);
+    m_replaceButton->setEnabled(false);
+    m_noMatchesFoundDisplay->show();
+}
+
+void SearchResultWidget::hideNoUndoWarning()
+{
+    setShowWarningMessage(false);
+    m_infoBar.clear();
+}
+
+void SearchResultWidget::handleJumpToSearchResult(const SearchResultItem &item)
+{
+    emit activated(item);
+}
+
+void SearchResultWidget::handleReplaceButton()
+{
+    // check if button is actually enabled, because this is also triggered
+    // by pressing return in replace line edit
+    if (m_replaceButton->isEnabled()) {
+        m_infoBar.clear();
+        emit replaceButtonClicked(m_replaceTextEdit->text(), checkedItems());
+    }
+}
+
+bool SearchResultWidget::showWarningMessage() const
+{
+    // read settings
+    QSettings *settings = Core::ICore::instance()->settings();
+    settings->beginGroup(m_dontAskAgainGroup);
+    settings->beginGroup(QLatin1String("Rename"));
+    const bool showWarningMessage = settings->value(QLatin1String("ShowWarningMessage"), true).toBool();
+    settings->endGroup();
+    settings->endGroup();
+    return showWarningMessage;
+}
+
+void SearchResultWidget::setShowWarningMessage(bool showWarningMessage)
+{
+    // write to settings
+    QSettings *settings = Core::ICore::instance()->settings();
+    settings->beginGroup(m_dontAskAgainGroup);
+    settings->beginGroup(QLatin1String("Rename"));
+    settings->setValue(QLatin1String("ShowWarningMessage"), showWarningMessage);
+    settings->endGroup();
+    settings->endGroup();
+}
+
+QList<SearchResultItem> SearchResultWidget::checkedItems() const
+{
+    QList<SearchResultItem> result;
+    Internal::SearchResultTreeModel *model = m_searchResultTreeView->model();
+    const int fileCount = model->rowCount(QModelIndex());
+    for (int i = 0; i < fileCount; ++i) {
+        QModelIndex fileIndex = model->index(i, 0, QModelIndex());
+        Internal::SearchResultTreeItem *fileItem = static_cast<Internal::SearchResultTreeItem *>(fileIndex.internalPointer());
+        Q_ASSERT(fileItem != 0);
+        for (int rowIndex = 0; rowIndex < fileItem->childrenCount(); ++rowIndex) {
+            QModelIndex textIndex = model->index(rowIndex, 0, fileIndex);
+            Internal::SearchResultTreeItem *rowItem = static_cast<Internal::SearchResultTreeItem *>(textIndex.internalPointer());
+            if (rowItem->checkState())
+                result << rowItem->item;
+        }
+    }
+    return result;
+}
+
+#include "searchresultwidget.moc"
diff --git a/src/plugins/find/searchresultwidget.h b/src/plugins/find/searchresultwidget.h
new file mode 100644
index 00000000000..bd6f1df952a
--- /dev/null
+++ b/src/plugins/find/searchresultwidget.h
@@ -0,0 +1,125 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.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 info@qt.nokia.com.
+**
+**************************************************************************/
+
+#ifndef SEARCHRESULTWIDGET_H
+#define SEARCHRESULTWIDGET_H
+
+#include "searchresultwindow.h"
+
+#include <coreplugin/infobar.h>
+
+#include <QtGui/QLabel>
+#include <QtGui/QLineEdit>
+#include <QtGui/QListWidget>
+#include <QtGui/QToolButton>
+#include <QtGui/QWidget>
+
+namespace Find {
+namespace Internal {
+
+class SearchResultTreeView;
+
+class SearchResultWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit SearchResultWidget(QWidget *parent = 0);
+
+    void addResult(const QString &fileName, int lineNumber, const QString &lineText,
+                   int searchTermStart, int searchTermLength, const QVariant &userData = QVariant());
+    void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode);
+
+    int count() const;
+
+    QString dontAskAgainGroup() const;
+    void setDontAskAgainGroup(const QString &group);
+
+    void setTextToReplace(const QString &textToReplace);
+    QString textToReplace() const;
+    void setShowReplaceUI(bool visible);
+
+    bool hasFocusInternally() const;
+    void setFocusInternally();
+    bool canFocusInternally() const;
+
+    void notifyVisibilityChanged(bool visible);
+
+    void setTextEditorFont(const QFont &font);
+
+    void setAutoExpandResults(bool expand);
+    void expandAll();
+    void collapseAll();
+
+    void goToNext();
+    void goToPrevious();
+
+    // TODO: temporary
+    QList<QWidget*> toolBarWidgets() const { return QList<QWidget*>() << m_replaceLabel << m_replaceTextEdit << m_replaceButton; }
+
+public slots:
+    void finishSearch();
+    void clear();
+    void showNoMatchesFound();
+
+signals:
+    void activated(const Find::SearchResultItem &item);
+    void replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems);
+    void visibilityChanged(bool visible);
+
+    void navigateStateChanged();
+
+private slots:
+    void hideNoUndoWarning();
+    void handleJumpToSearchResult(const SearchResultItem &item);
+    void handleReplaceButton();
+
+private:
+    bool showWarningMessage() const;
+    void setShowWarningMessage(bool showWarningMessage);
+    QList<SearchResultItem> checkedItems() const;
+
+    SearchResultTreeView *m_searchResultTreeView;
+    int m_count;
+    QString m_dontAskAgainGroup;
+    Core::InfoBar m_infoBar;
+    Core::InfoBarDisplay m_infoBarDisplay;
+    QListWidget *m_noMatchesFoundDisplay;
+    bool m_isShowingReplaceUI;
+    QLabel *m_replaceLabel;
+    QLineEdit *m_replaceTextEdit;
+    QToolButton *m_replaceButton;
+};
+
+} // Internal
+} // Find
+
+#endif // SEARCHRESULTWIDGET_H
diff --git a/src/plugins/find/searchresultwindow.cpp b/src/plugins/find/searchresultwindow.cpp
index 73957b9e5d6..0bba9a8bc0d 100644
--- a/src/plugins/find/searchresultwindow.cpp
+++ b/src/plugins/find/searchresultwindow.cpp
@@ -31,31 +31,19 @@
 **************************************************************************/
 
 #include "searchresultwindow.h"
-#include "searchresulttreemodel.h"
-#include "searchresulttreeitems.h"
-#include "searchresulttreeview.h"
-#include "ifindsupport.h"
+#include "searchresultwidget.h"
 
-#include <aggregation/aggregate.h>
 #include <coreplugin/icore.h>
-#include <coreplugin/infobar.h>
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <coreplugin/actionmanager/command.h>
 #include <coreplugin/coreconstants.h>
 #include <coreplugin/icontext.h>
-#include <coreplugin/id.h>
 #include <utils/qtcassert.h>
 
 #include <QtCore/QFile>
-#include <QtCore/QTextStream>
 #include <QtCore/QSettings>
 #include <QtCore/QDebug>
-#include <QtCore/QDir>
-#include <QtGui/QListWidget>
-#include <QtGui/QToolButton>
-#include <QtGui/QLineEdit>
 #include <QtGui/QVBoxLayout>
-#include <QtGui/QLabel>
 #include <QtGui/QFont>
 #include <QtGui/QAction>
 
@@ -66,183 +54,19 @@ namespace Find {
 
 namespace Internal {
 
-    class WideEnoughLineEdit : public QLineEdit {
-        Q_OBJECT
-    public:
-        WideEnoughLineEdit(QWidget *parent):QLineEdit(parent){
-            connect(this, SIGNAL(textChanged(QString)),
-                    this, SLOT(updateGeometry()));
-        }
-        ~WideEnoughLineEdit(){}
-        QSize sizeHint() const {
-            QSize sh = QLineEdit::minimumSizeHint();
-            sh.rwidth() += qMax(25 * fontMetrics().width(QLatin1Char('x')),
-                                fontMetrics().width(text()));
-            return sh;
-        }
-    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, &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, &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 *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),
-                                              wrapped);
-            } else {
-                index = m_view->model()->find(txt,
-                                              m_view->currentIndex(),
-                                              Find::textDocumentFlagsForFindFlags(findFlags),
-                                              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;
-    };
-
     struct SearchResultWindowPrivate {
         SearchResultWindowPrivate();
 
-        Internal::SearchResultTreeView *m_searchResultTreeView;
-        QListWidget *m_noMatchesFoundDisplay;
+        Internal::SearchResultWidget *m_searchResultWidget;
         QToolButton *m_expandCollapseButton;
         QAction *m_expandCollapseAction;
-        QLabel *m_replaceLabel;
-        QLineEdit *m_replaceTextEdit;
-        QToolButton *m_replaceButton;
         static const bool m_initiallyExpand = false;
         QWidget *m_widget;
         SearchResult *m_currentSearch;
-        int m_itemCount;
-        bool m_isShowingReplaceUI;
-        bool m_focusReplaceEdit;
-        QString m_dontAskAgainGroup;
-        Core::InfoBar m_infoBar;
-        Core::InfoBarDisplay m_infoBarDisplay;
     };
 
     SearchResultWindowPrivate::SearchResultWindowPrivate()
-        : m_currentSearch(0),
-        m_itemCount(0),
-        m_isShowingReplaceUI(false),
-        m_focusReplaceEdit(false)
+        : m_currentSearch(0)
     {
     }
 }
@@ -311,7 +135,7 @@ using namespace Find::Internal;
     After the search has finished call finishSearch to inform the search
     result window about it.
 
-    After that you get activated signals via your SearchResult instance when
+    You will get activated signals via your SearchResult instance when
     the user selects a search result item, and, if you started the search
     with the SearchAndReplace option, the replaceButtonClicked signal
     when the user requests a replace.
@@ -334,27 +158,13 @@ SearchResultWindow::SearchResultWindow() : d(new SearchResultWindowPrivate)
     d->m_widget = new QWidget;
     d->m_widget->setWindowTitle(displayName());
 
-    d->m_searchResultTreeView = new Internal::SearchResultTreeView(d->m_widget);
-    d->m_searchResultTreeView->setFrameStyle(QFrame::NoFrame);
-    d->m_searchResultTreeView->setAttribute(Qt::WA_MacShowFocusRect, false);
-    Aggregation::Aggregate * agg = new Aggregation::Aggregate;
-    agg->add(d->m_searchResultTreeView);
-    agg->add(new SearchResultFindSupport(d->m_searchResultTreeView));
-
-    d->m_noMatchesFoundDisplay = new QListWidget(d->m_widget);
-    d->m_noMatchesFoundDisplay->addItem(tr("No matches found!"));
-    d->m_noMatchesFoundDisplay->setFrameStyle(QFrame::NoFrame);
-    d->m_noMatchesFoundDisplay->hide();
+    d->m_searchResultWidget = new Internal::SearchResultWidget(d->m_widget);
 
     QVBoxLayout *vlay = new QVBoxLayout;
     d->m_widget->setLayout(vlay);
     vlay->setMargin(0);
     vlay->setSpacing(0);
-    vlay->addWidget(d->m_noMatchesFoundDisplay);
-    vlay->addWidget(d->m_searchResultTreeView);
-
-    d->m_infoBarDisplay.setTarget(vlay, 0);
-    d->m_infoBarDisplay.setInfoBar(&d->m_infoBar);
+    vlay->addWidget(d->m_searchResultWidget);
 
     d->m_expandCollapseButton = new QToolButton(d->m_widget);
     d->m_expandCollapseButton->setAutoRaise(true);
@@ -368,24 +178,9 @@ SearchResultWindow::SearchResultWindow() : d(new SearchResultWindowPrivate)
     cmd->setAttribute(Core::Command::CA_UpdateText);
     d->m_expandCollapseButton->setDefaultAction(cmd->action());
 
-    d->m_replaceLabel = new QLabel(tr("Replace with:"), d->m_widget);
-    d->m_replaceLabel->setContentsMargins(12, 0, 5, 0);
-    d->m_replaceTextEdit = new WideEnoughLineEdit(d->m_widget);
-    d->m_replaceButton = new QToolButton(d->m_widget);
-    d->m_replaceButton->setToolTip(tr("Replace all occurrences"));
-    d->m_replaceButton->setText(tr("Replace"));
-    d->m_replaceButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
-    d->m_replaceButton->setAutoRaise(true);
-    d->m_replaceTextEdit->setTabOrder(d->m_replaceTextEdit, d->m_searchResultTreeView);
-
-    connect(d->m_searchResultTreeView, SIGNAL(jumpToSearchResult(SearchResultItem)),
-            this, SLOT(handleJumpToSearchResult(SearchResultItem)));
     connect(d->m_expandCollapseAction, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool)));
-    connect(d->m_replaceTextEdit, SIGNAL(returnPressed()), this, SLOT(handleReplaceButton()));
-    connect(d->m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton()));
-
+    connect(d->m_searchResultWidget, SIGNAL(navigateStateChanged()), this, SLOT(navigateStateChanged()));
     readSettings();
-    setShowReplaceUI(false);
 }
 
 /*!
@@ -399,7 +194,6 @@ SearchResultWindow::~SearchResultWindow()
     d->m_currentSearch = 0;
     delete d->m_widget;
     d->m_widget = 0;
-    d->m_itemCount = 0;
     delete d;
 }
 
@@ -412,83 +206,13 @@ SearchResultWindow *SearchResultWindow::instance()
     return m_instance;
 }
 
-/*!
-    \fn void SearchResultWindow::setTextToReplace(const QString &textToReplace)
-    \internal
-*/
-void SearchResultWindow::setTextToReplace(const QString &textToReplace)
-{
-    d->m_replaceTextEdit->setText(textToReplace);
-}
-
-/*!
-    \fn QString SearchResultWindow::textToReplace() const
-    \internal
-*/
-QString SearchResultWindow::textToReplace() const
-{
-    return d->m_replaceTextEdit->text();
-}
-
-/*!
-    \fn void SearchResultWindow::setShowReplaceUI(bool show)
-    \internal
-*/
-void SearchResultWindow::setShowReplaceUI(bool show)
-{
-    d->m_searchResultTreeView->model()->setShowReplaceUI(show);
-    d->m_replaceLabel->setVisible(show);
-    d->m_replaceTextEdit->setVisible(show);
-    d->m_replaceButton->setVisible(show);
-    d->m_isShowingReplaceUI = show;
-}
-
-/*!
-    \fn void SearchResultWindow::handleReplaceButton()
-    \internal
-*/
-void SearchResultWindow::handleReplaceButton()
-{
-    QTC_ASSERT(d->m_currentSearch, return);
-    // check if button is actually enabled, because this is also triggered
-    // by pressing return in replace line edit
-    if (d->m_replaceButton->isEnabled()) {
-        d->m_infoBar.clear();
-        d->m_currentSearch->replaceButtonClicked(d->m_replaceTextEdit->text(), checkedItems());
-    }
-}
-
-/*!
-    \fn QList<SearchResultItem> SearchResultWindow::checkedItems() const
-    \internal
-*/
-QList<SearchResultItem> SearchResultWindow::checkedItems() const
-{
-    QList<SearchResultItem> result;
-    Internal::SearchResultTreeModel *model = d->m_searchResultTreeView->model();
-    const int fileCount = model->rowCount(QModelIndex());
-    for (int i = 0; i < fileCount; ++i) {
-        QModelIndex fileIndex = model->index(i, 0, QModelIndex());
-        Internal::SearchResultTreeItem *fileItem = static_cast<Internal::SearchResultTreeItem *>(fileIndex.internalPointer());
-        Q_ASSERT(fileItem != 0);
-        for (int rowIndex = 0; rowIndex < fileItem->childrenCount(); ++rowIndex) {
-            QModelIndex textIndex = model->index(rowIndex, 0, fileIndex);
-            Internal::SearchResultTreeItem *rowItem = static_cast<Internal::SearchResultTreeItem *>(textIndex.internalPointer());
-            if (rowItem->checkState())
-                result << rowItem->item;
-        }
-    }
-    return result;
-}
-
 /*!
     \fn void SearchResultWindow::visibilityChanged(bool)
     \internal
 */
 void SearchResultWindow::visibilityChanged(bool visible)
 {
-    if (d->m_currentSearch)
-        d->m_currentSearch->visibilityChanged(visible);
+    d->m_searchResultWidget->notifyVisibilityChanged(visible);
 }
 
 /*!
@@ -506,7 +230,7 @@ QWidget *SearchResultWindow::outputWidget(QWidget *)
 */
 QList<QWidget*> SearchResultWindow::toolBarWidgets() const
 {
-    return QList<QWidget*>() << d->m_expandCollapseButton << d->m_replaceLabel << d->m_replaceTextEdit << d->m_replaceButton;
+    return QList<QWidget*>() << d->m_expandCollapseButton << d->m_searchResultWidget->toolBarWidgets();
 }
 
 /*!
@@ -524,69 +248,30 @@ QList<QWidget*> SearchResultWindow::toolBarWidgets() const
 SearchResult *SearchResultWindow::startNewSearch(SearchMode searchOrSearchAndReplace, const QString &cfgGroup)
 {
     clearContents();
-    setShowReplaceUI(searchOrSearchAndReplace != SearchOnly);
-    d->m_dontAskAgainGroup = cfgGroup;
+    d->m_searchResultWidget->setShowReplaceUI(searchOrSearchAndReplace != SearchOnly);
+    d->m_searchResultWidget->setDontAskAgainGroup(cfgGroup);
     delete d->m_currentSearch;
-    d->m_currentSearch = new SearchResult;
+    d->m_currentSearch = new SearchResult(d->m_searchResultWidget);
     return d->m_currentSearch;
 }
 
-/*!
-    \fn void SearchResultWindow::finishSearch()
-    \internal
-*/
-void SearchResultWindow::finishSearch()
-{
-    if (d->m_itemCount > 0) {
-        d->m_replaceButton->setEnabled(true);
-    } else {
-        showNoMatchesFound();
-    }
-}
-
 /*!
     \fn void SearchResultWindow::clearContents()
     \brief Clears the current contents in the search result window.
 */
 void SearchResultWindow::clearContents()
 {
-    d->m_replaceTextEdit->setEnabled(false);
-    d->m_replaceButton->setEnabled(false);
-    d->m_replaceTextEdit->clear();
-    d->m_searchResultTreeView->clear();
-    d->m_itemCount = 0;
-    d->m_noMatchesFoundDisplay->hide();
-    d->m_infoBar.clear();
+    d->m_searchResultWidget->clear();
     navigateStateChanged();
 }
 
-/*!
-    \fn void SearchResultWindow::showNoMatchesFound()
-    \internal
-*/
-void SearchResultWindow::showNoMatchesFound()
-{
-    d->m_replaceTextEdit->setEnabled(false);
-    d->m_replaceButton->setEnabled(false);
-    d->m_noMatchesFoundDisplay->show();
-}
-
-/*!
-    \fn bool SearchResultWindow::isEmpty() const
-    Returns if the search result window currently doesn't show any results.
-*/
-bool SearchResultWindow::isEmpty() const
-{
-    return (d->m_searchResultTreeView->model()->rowCount() < 1);
-}
-
 /*!
     \fn bool SearchResultWindow::hasFocus()
     \internal
 */
 bool SearchResultWindow::hasFocus()
 {
-    return d->m_searchResultTreeView->hasFocus() || (d->m_isShowingReplaceUI && d->m_replaceTextEdit->hasFocus());
+    return d->m_searchResultWidget->hasFocusInternally();
 }
 
 /*!
@@ -595,7 +280,7 @@ bool SearchResultWindow::hasFocus()
 */
 bool SearchResultWindow::canFocus()
 {
-    return d->m_itemCount > 0;
+    return d->m_searchResultWidget->canFocusInternally();
 }
 
 /*!
@@ -604,20 +289,7 @@ bool SearchResultWindow::canFocus()
 */
 void SearchResultWindow::setFocus()
 {
-    if (d->m_itemCount > 0) {
-        if (!d->m_isShowingReplaceUI) {
-            d->m_searchResultTreeView->setFocus();
-        } else {
-            if (!d->m_widget->focusWidget()
-                    || d->m_widget->focusWidget() == d->m_replaceTextEdit
-                    || d->m_focusReplaceEdit) {
-                d->m_replaceTextEdit->setFocus();
-                d->m_replaceTextEdit->selectAll();
-            } else {
-                d->m_searchResultTreeView->setFocus();
-            }
-        }
-    }
+    d->m_searchResultWidget->setFocusInternally();
 }
 
 /*!
@@ -626,90 +298,7 @@ void SearchResultWindow::setFocus()
 */
 void SearchResultWindow::setTextEditorFont(const QFont &font)
 {
-    d->m_searchResultTreeView->setTextEditorFont(font);
-}
-
-/*!
-    \fn void SearchResultWindow::handleJumpToSearchResult(const SearchResultItem &item)
-    \internal
-*/
-void SearchResultWindow::handleJumpToSearchResult(const SearchResultItem &item)
-{
-    QTC_ASSERT(d->m_currentSearch, return);
-    d->m_currentSearch->activated(item);
-}
-
-/*!
-    \fn void SearchResultWindow::addResult(const QString &fileName, int lineNumber, const QString &rowText, int searchTermStart, int searchTermLength, const QVariant &userData)
-    \internal
-*/
-void SearchResultWindow::addResult(const QString &fileName, int lineNumber, const QString &rowText,
-    int searchTermStart, int searchTermLength, const QVariant &userData)
-{
-    SearchResultItem item;
-    item.path = QStringList() << QDir::toNativeSeparators(fileName);
-    item.lineNumber = lineNumber;
-    item.text = rowText;
-    item.textMarkPos = searchTermStart;
-    item.textMarkLength = searchTermLength;
-    item.useTextEditorFont = true;
-    item.userData = userData;
-    addResults(QList<SearchResultItem>() << item, SearchResult::AddOrdered);
-}
-
-/*!
-    \fn void SearchResultWindow::addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode)
-    \internal
-*/
-void SearchResultWindow::addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode)
-{
-    bool firstItems = (d->m_itemCount == 0);
-    d->m_itemCount += items.size();
-    d->m_searchResultTreeView->addResults(items, mode);
-    if (firstItems) {
-        if (!d->m_dontAskAgainGroup.isEmpty() && showWarningMessage()) {
-            Core::InfoBarEntry info("warninglabel", tr("This change cannot be undone."));
-            info.setCustomButtonInfo(tr("Do not warn again"), this, SLOT(hideNoUndoWarning()));
-            d->m_infoBar.addInfo(info);
-        }
-
-        d->m_replaceTextEdit->setEnabled(true);
-        // We didn't have an item before, set the focus to the search widget
-        d->m_focusReplaceEdit = true;
-        setFocus();
-        d->m_focusReplaceEdit = false;
-        d->m_searchResultTreeView->selectionModel()->select(d->m_searchResultTreeView->model()->index(0, 0, QModelIndex()), QItemSelectionModel::Select);
-        emit navigateStateChanged();
-    }
-}
-
-bool SearchResultWindow::showWarningMessage() const
-{
-    // Restore settings
-    QSettings *settings = Core::ICore::instance()->settings();
-    settings->beginGroup(d->m_dontAskAgainGroup);
-    settings->beginGroup(QLatin1String("Rename"));
-    const bool showWarningMessage = settings->value(QLatin1String("ShowWarningMessage"), true).toBool();
-    settings->endGroup();
-    settings->endGroup();
-    return showWarningMessage;
-}
-
-void SearchResultWindow::setShowWarningMessage(bool showWarningMessage)
-{
-    // Restore settings
-    QSettings *settings = Core::ICore::instance()->settings();
-    settings->beginGroup(d->m_dontAskAgainGroup);
-    settings->beginGroup(QLatin1String("Rename"));
-    settings->setValue(QLatin1String("ShowWarningMessage"), showWarningMessage);
-    settings->endGroup();
-    settings->endGroup();
-}
-
-void SearchResultWindow::hideNoUndoWarning()
-{
-    setShowWarningMessage(false);
-    d->m_infoBar.clear();
+    d->m_searchResultWidget->setTextEditorFont(font);
 }
 
 /*!
@@ -718,13 +307,13 @@ void SearchResultWindow::hideNoUndoWarning()
 */
 void SearchResultWindow::handleExpandCollapseToolButton(bool checked)
 {
-    d->m_searchResultTreeView->setAutoExpandResults(checked);
+    d->m_searchResultWidget->setAutoExpandResults(checked);
     if (checked) {
         d->m_expandCollapseAction->setText(tr("Collapse All"));
-        d->m_searchResultTreeView->expandAll();
+        d->m_searchResultWidget->expandAll();
     } else {
         d->m_expandCollapseAction->setText(tr("Expand All"));
-        d->m_searchResultTreeView->collapseAll();
+        d->m_searchResultWidget->collapseAll();
     }
 }
 
@@ -771,7 +360,7 @@ int SearchResultWindow::priorityInStatusBar() const
 */
 bool SearchResultWindow::canNext()
 {
-    return d->m_itemCount > 0;
+    return d->m_searchResultWidget->count() > 0;
 }
 
 /*!
@@ -780,7 +369,7 @@ bool SearchResultWindow::canNext()
 */
 bool SearchResultWindow::canPrevious()
 {
-    return d->m_itemCount > 0;
+    return d->m_searchResultWidget->count() > 0;
 }
 
 /*!
@@ -789,13 +378,7 @@ bool SearchResultWindow::canPrevious()
 */
 void SearchResultWindow::goToNext()
 {
-    if (d->m_itemCount == 0)
-        return;
-    QModelIndex idx = d->m_searchResultTreeView->model()->next(d->m_searchResultTreeView->currentIndex());
-    if (idx.isValid()) {
-        d->m_searchResultTreeView->setCurrentIndex(idx);
-        d->m_searchResultTreeView->emitJumpToSearchResult(idx);
-    }
+    d->m_searchResultWidget->goToNext();
 }
 
 /*!
@@ -804,13 +387,7 @@ void SearchResultWindow::goToNext()
 */
 void SearchResultWindow::goToPrev()
 {
-    if (!d->m_searchResultTreeView->model()->rowCount())
-        return;
-    QModelIndex idx = d->m_searchResultTreeView->model()->prev(d->m_searchResultTreeView->currentIndex());
-    if (idx.isValid()) {
-        d->m_searchResultTreeView->setCurrentIndex(idx);
-        d->m_searchResultTreeView->emitJumpToSearchResult(idx);
-    }
+    d->m_searchResultWidget->goToPrevious();
 }
 
 /*!
@@ -822,6 +399,21 @@ bool SearchResultWindow::canNavigate()
     return true;
 }
 
+/*!
+    \fn SearchResult::SearchResult(SearchResultWidget *widget)
+    \internal
+*/
+SearchResult::SearchResult(SearchResultWidget *widget)
+    : m_widget(widget)
+{
+    connect(widget, SIGNAL(activated(Find::SearchResultItem)),
+            this, SIGNAL(activated(Find::SearchResultItem)));
+    connect(widget, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)),
+            this, SIGNAL(replaceButtonClicked(QString,QList<Find::SearchResultItem>)));
+    connect(widget, SIGNAL(visibilityChanged(bool)),
+            this, SIGNAL(visibilityChanged(bool)));
+}
+
 /*!
     \fn void SearchResult::setUserData(const QVariant &data)
     \brief Attach some random \a data to this search, that you can use later.
@@ -850,8 +442,7 @@ QVariant SearchResult::userData() const
 */
 QString SearchResult::textToReplace() const
 {
-    // TODO: should point to associated SearchResultWidget
-    return SearchResultWindow::instance()->textToReplace();
+    return m_widget->textToReplace();
 }
 
 /*!
@@ -869,9 +460,8 @@ QString SearchResult::textToReplace() const
 void SearchResult::addResult(const QString &fileName, int lineNumber, const QString &lineText,
                              int searchTermStart, int searchTermLength, const QVariant &userData)
 {
-    // TODO: should point to associated SearchResultWidget
-    SearchResultWindow::instance()->addResult(fileName, lineNumber, lineText,
-                                              searchTermStart, searchTermLength, userData);
+    m_widget->addResult(fileName, lineNumber, lineText,
+                        searchTermStart, searchTermLength, userData);
 }
 
 /*!
@@ -883,8 +473,7 @@ void SearchResult::addResult(const QString &fileName, int lineNumber, const QStr
 */
 void SearchResult::addResults(const QList<SearchResultItem> &items, AddMode mode)
 {
-    // TODO: should point to associated SearchResultWidget
-    SearchResultWindow::instance()->addResults(items, mode);
+    m_widget->addResults(items, mode);
 }
 
 /*!
@@ -894,8 +483,7 @@ void SearchResult::addResults(const QList<SearchResultItem> &items, AddMode mode
 */
 void SearchResult::finishSearch()
 {
-    // TODO: should point to associated SearchResultWidget
-    SearchResultWindow::instance()->finishSearch();
+    m_widget->finishSearch();
 }
 
 /*!
@@ -905,11 +493,7 @@ void SearchResult::finishSearch()
 */
 void SearchResult::setTextToReplace(const QString &textToReplace)
 {
-    // TODO: should point to associated SearchResultWidget
-    SearchResultWindow::instance()->setTextToReplace(textToReplace);
+    m_widget->setTextToReplace(textToReplace);
 }
 
 } // namespace Find
-
-
-#include "searchresultwindow.moc"
diff --git a/src/plugins/find/searchresultwindow.h b/src/plugins/find/searchresultwindow.h
index 5203f3cba77..6a17ec5987c 100644
--- a/src/plugins/find/searchresultwindow.h
+++ b/src/plugins/find/searchresultwindow.h
@@ -49,6 +49,7 @@ namespace Find {
 namespace Internal {
     class SearchResultTreeView;
     struct SearchResultWindowPrivate;
+    class SearchResultWidget;
 }
 class SearchResultWindow;
 
@@ -110,9 +111,12 @@ signals:
     void replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems);
     void visibilityChanged(bool visible);
 
-    friend class SearchResultWindow;
+private:
+    SearchResult(Internal::SearchResultWidget *widget);
+    friend class SearchResultWindow; // for the constructor
 
 private:
+    Internal::SearchResultWidget *m_widget;
     QVariant m_userData;
 };
 
@@ -137,7 +141,6 @@ public:
     QString displayName() const { return tr("Search Results"); }
     int priorityInStatusBar() const;
     void visibilityChanged(bool visible);
-    bool isEmpty() const;
     bool hasFocus();
     bool canFocus();
     void setFocus();
@@ -159,31 +162,13 @@ public slots:
 
 private slots:
     void handleExpandCollapseToolButton(bool checked);
-    void handleJumpToSearchResult(const SearchResultItem &item);
-    void handleReplaceButton();
-    void showNoMatchesFound();
-    void hideNoUndoWarning();
 
 private:
-    // TODO: move to the new SearchResultWidget
-    void addResult(const QString &fileName, int lineNumber, const QString &lineText,
-                   int searchTermStart, int searchTermLength, const QVariant &userData);
-    void addResults(const QList<SearchResultItem> &items, SearchResult::AddMode mode); // TODO: move to SearchResultWidget)
-    void finishSearch();
-    void setTextToReplace(const QString &textToReplace);
-    QString textToReplace() const;
-
-
-    void setShowReplaceUI(bool show);
     void readSettings();
     void writeSettings();
-    QList<SearchResultItem> checkedItems() const;
-    bool showWarningMessage() const;
-    void setShowWarningMessage(bool showWarningMessage);
 
     Internal::SearchResultWindowPrivate *d;
     static SearchResultWindow *m_instance;
-    friend class SearchResult;
 };
 
 } // namespace Find
-- 
GitLab