Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve search in document #160

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
{
mgiroday marked this conversation as resolved.
Show resolved Hide resolved
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
Loading