Skip to content

Commit

Permalink
feat: improve search in document (KDAB#25)
Browse files Browse the repository at this point in the history
Fixes tasks:
QtUiDocument
QtTsDocument
RCDocument text view
RCDocument central view
RCDocument left tree
  • Loading branch information
mgiroday committed Oct 23, 2024
1 parent 8f54cf5 commit a9473c3
Show file tree
Hide file tree
Showing 12 changed files with 409 additions and 19 deletions.
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ set(PROJECT_SOURCES
gui_constants.h
guisettings.h
guisettings.cpp
highlightsearchdelegate.h
highlightsearchdelegate.cpp
historypanel.h
historypanel.cpp
imageview.h
Expand Down
43 changes: 43 additions & 0 deletions src/gui/findwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
#include "findwidget.h"
#include "core/logger.h"
#include "core/project.h"
#include "core/qttsdocument.h"
#include "core/qtuidocument.h"
#include "core/textdocument.h"
#include "guisettings.h"
#include "qttsview.h"
#include "qtuiview.h"
#include "ui_findwidget.h"

#include <QAction>
Expand Down Expand Up @@ -86,11 +90,35 @@ QString FindWidget::findString()

void FindWidget::findNext()
{
auto qtUiDocument = qobject_cast<Core::QtUiDocument *>(Core::Project::instance()->currentDocument());
if (qtUiDocument) {
Q_EMIT findRequested(ui->findEdit->text(), Core::TextDocument::NoFindFlags);
return;
}

auto qtTsDocument = qobject_cast<Core::QtTsDocument *>(Core::Project::instance()->currentDocument());
if (qtTsDocument) {
Q_EMIT findRequested(ui->findEdit->text(), Core::TextDocument::NoFindFlags); // default is FindForward
return;
}

find(findFlags());
}

void FindWidget::findPrevious()
{
auto qtUiDocument = qobject_cast<Core::QtUiDocument *>(Core::Project::instance()->currentDocument());
if (qtUiDocument) {
Q_EMIT findRequested(ui->findEdit->text(), Core::TextDocument::FindBackward);
return;
}

auto qtTsDocument = qobject_cast<Core::QtTsDocument *>(Core::Project::instance()->currentDocument());
if (qtTsDocument) {
Q_EMIT findRequested(ui->findEdit->text(), Core::TextDocument::FindBackward);
return;
}

find(findFlags() | Core::TextDocument::FindBackward);
}

Expand Down Expand Up @@ -153,4 +181,19 @@ void FindWidget::replace(bool onlyOne)
}
}

void FindWidget::hideEvent(QHideEvent *event)
{
Q_EMIT findWidgetClosed();
QWidget::hideEvent(event);
}

void FindWidget::showReplaceFeature(bool show)
{
// We don't want to use a wrapping frame here due to layouting issues...
ui->replaceWithLabel->setVisible(show);
ui->replaceEdit->setVisible(show);
ui->replaceAllbutton->setVisible(show);
ui->replaceButton->setVisible(show);
}

} // namespace Gui
9 changes: 9 additions & 0 deletions src/gui/findwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ class FindWidget : public QWidget

void open();

void showReplaceFeature(bool show = true);

signals:
void findRequested(const QString &text, int options);
void findWidgetClosed();

protected:
void hideEvent(QHideEvent *event) override;

private:
int findFlags() const;
QString findString();
Expand Down
4 changes: 2 additions & 2 deletions src/gui/findwidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="replaceWithLabel">
<property name="text">
<string>Replace with:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<widget class="QLabel" name="findLabel">
<property name="text">
<string>Find:</string>
</property>
Expand Down
83 changes: 83 additions & 0 deletions src/gui/highlightsearchdelegate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
This file is part of Knut.
SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
SPDX-License-Identifier: GPL-3.0-only
Contact KDAB at <[email protected]> for commercial licensing options.
*/

#include "highlightsearchdelegate.h"
#include <QPainter>

namespace Gui {

HighlightSearchDelegate::HighlightSearchDelegate(QObject *parent)
: QItemDelegate(parent)
{
}

void HighlightSearchDelegate::setSearchText(const QString &searchText, int offset)
{
m_searchText = searchText;
m_offset = offset;
}

void HighlightSearchDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QString text = index.data().toString();
if (m_searchText.isEmpty() || !text.contains(m_searchText, Qt::CaseInsensitive)) {
QItemDelegate::paint(painter, option, index);
return;
}

// Check for multiline strings
QStringList multilineStrings = text.split("\n", Qt::SkipEmptyParts);
bool isMultiline = multilineStrings.count() > 1;
if (isMultiline) {
// Make it a one line text for the search highlight,
// otherwise the painting is error prone (needs too much manipulation).
// That does not impact the model itself.
text = text.replace("\n", " - ");
}
// Find the substring to highlight
const QRegularExpression regex(m_searchText, QRegularExpression::CaseInsensitiveOption);
int start = regex.match(text).capturedStart();
int end = start + regex.match(text).capturedLength();

// Calculate the drawing positions.
// The TreeViews or TableView display its Items excentred in relation to the left side of the cell.
// Correct the x position accordingly using the caller offset value.
int x = option.rect.left() + m_offset;
int y = option.rect.top();
int height = option.rect.height();
int width = painter->fontMetrics().horizontalAdvance(text.left(start));

// Paint the seach result string 'bold'.
QFont highlightFont = option.font;
highlightFont.setBold(true);

painter->save();
// Make sure we don't paint over the selected item highlighted background.
if (option.state & QStyle::State_Selected) {
// Set the background color to the selection color
painter->fillRect(option.rect, option.palette.brush(QPalette::Active, QPalette::Highlight));
}

painter->drawText(x, y, width, height, option.displayAlignment, text.left(start));
// Paint the searched string with bold font.
painter->setFont(highlightFont);
x += width;
width = painter->fontMetrics().horizontalAdvance(text.mid(start, end - start));
painter->drawText(x, y, width, height, option.displayAlignment, text.mid(start, end - start));
// Reset the painter font to original font.
painter->setFont(option.font);
x += width;
width = painter->fontMetrics().horizontalAdvance(text.right(text.length() - end));
painter->drawText(x, y, width, height, option.displayAlignment, text.right(text.length() - end));
painter->restore();
}

} // namespace Gui
34 changes: 34 additions & 0 deletions src/gui/highlightsearchdelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
This file is part of Knut.
SPDX-FileCopyrightText: 2024 Klarälvdalens Datakonsult AB, a KDAB Group company <[email protected]>
SPDX-License-Identifier: GPL-3.0-only
Contact KDAB at <[email protected]> for commercial licensing options.
*/

#pragma once

#include <QItemDelegate>

namespace Gui {

class HighlightSearchDelegate : public QItemDelegate
{
Q_OBJECT

public:
explicit HighlightSearchDelegate(QObject *parent = nullptr);

void setSearchText(const QString &searchText, int offset = 0);

protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;

private:
QString m_searchText;
int m_offset;
};

} // namespace Gui
26 changes: 23 additions & 3 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,12 +572,17 @@ void MainWindow::updateActions()

ui->actionCloseDocument->setEnabled(document != nullptr);

auto *qtTsDocument = qobject_cast<Core::QtTsDocument *>(document);
auto *qtUiDocument = qobject_cast<Core::QtUiDocument *>(document);
auto *textDocument = qobject_cast<Core::TextDocument *>(document);

const bool enableFindWidgetFeatures =
(qtTsDocument != nullptr || qtUiDocument != nullptr || textDocument != nullptr);
ui->actionSelectAll->setEnabled(textDocument != nullptr);
ui->actionFind->setEnabled(textDocument != nullptr);
ui->actionFind->setEnabled(enableFindWidgetFeatures);
ui->actionReplace->setEnabled(textDocument != nullptr);
ui->actionFindNext->setEnabled(textDocument != nullptr);
ui->actionFindPrevious->setEnabled(textDocument != nullptr);
ui->actionFindNext->setEnabled(enableFindWidgetFeatures);
ui->actionFindPrevious->setEnabled(enableFindWidgetFeatures);
ui->actionDeleteLine->setEnabled(textDocument != nullptr);
ui->actionUndo->setEnabled(textDocument != nullptr);
ui->actionRedo->setEnabled(textDocument != nullptr);
Expand Down Expand Up @@ -615,6 +620,18 @@ void MainWindow::updateActions()
ui->actionCreateUi->setEnabled(rcEnabled);
}

void MainWindow::updateFindWidgetDisplay()
{
// Handle the 'FindWidget' display depending on the document type.
auto document = Core::Project::instance()->currentDocument();

auto *qtTsDocument = qobject_cast<Core::QtTsDocument *>(document);
auto *qtUiDocument = qobject_cast<Core::QtUiDocument *>(document);
// Hide the replace widgets.
const bool hideReplaceFeature = (qtTsDocument != nullptr || qtUiDocument != nullptr);
ui->findWidget->showReplaceFeature(!hideReplaceFeature);
}

void MainWindow::updateScriptActions()
{
ui->actionStartRecordingScript->setEnabled(!m_historyPanel->isRecording());
Expand Down Expand Up @@ -694,6 +711,7 @@ QWidget *MainWindow::widgetForDocument(Core::Document *document)
}
case Core::Document::Type::QtUi: {
auto uiview = new QtUiView();
uiview->setFindWidget(ui->findWidget);
uiview->setUiDocument(qobject_cast<Core::QtUiDocument *>(document));
return uiview;
}
Expand All @@ -715,6 +733,7 @@ QWidget *MainWindow::widgetForDocument(Core::Document *document)
}
case Core::Document::Type::QtTs: {
auto tsView = new QtTsView();
tsView->setFindWidget(ui->findWidget);
tsView->setTsDocument(qobject_cast<Core::QtTsDocument *>(document));
return tsView;
}
Expand Down Expand Up @@ -792,6 +811,7 @@ void MainWindow::changeCurrentDocument()
const QModelIndex &index = m_fileModel->index(fileName);
m_projectView->setCurrentIndex(index);
updateActions();
updateFindWidgetDisplay();
}

} // namespace Gui
1 change: 1 addition & 0 deletions src/gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class MainWindow : public QMainWindow

void updateActions();
void updateScriptActions();
void updateFindWidgetDisplay();

void initProject(const QString &path);
void openDocument(const QModelIndex &index);
Expand Down
Loading

0 comments on commit a9473c3

Please sign in to comment.