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

feat: improve search in document #215

Merged
merged 1 commit into from
Nov 12, 2024
Merged
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
5 changes: 5 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ set(PROJECT_SOURCES
documentpalette.cpp
fileselector.h
fileselector.cpp
findinterface.h
findwidget.h
findinfilespanel.cpp
findinfilespanel.h
Expand All @@ -28,6 +29,8 @@ set(PROJECT_SOURCES
gui_constants.h
guisettings.h
guisettings.cpp
highlightdelegate.h
highlightdelegate.cpp
historypanel.h
historypanel.cpp
imageview.h
Expand Down Expand Up @@ -68,6 +71,8 @@ set(PROJECT_SOURCES
scriptpanel.cpp
scriptlistpanel.cpp
scriptlistpanel.h
searchabletableview.h
searchabletableview.cpp
shortcutmanager.h
shortcutmanager.cpp
shortcutsettings.h
Expand Down
51 changes: 51 additions & 0 deletions src/gui/findinterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
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 <QString>

namespace Gui {

/**
* @brief Find interface to handle find and replace in views.
*/
class FindInterface
{
public:
enum FindFlag {
NoFind = 0x0,
CanSearch = 0x1,
CanReplace = 0x2,
};
FindInterface(int flags)
: m_findFlags(flags) {};

int findFlags() const { return m_findFlags; }

virtual void find(const QString &text, int options)
{
Q_UNUSED(text);
Q_UNUSED(options);
};
virtual void cancelFind() {};
virtual void replace(const QString &before, const QString &after, int options, bool replaceAll)
{
Q_UNUSED(before);
Q_UNUSED(after);
Q_UNUSED(options);
Q_UNUSED(replaceAll);
};

private:
int m_findFlags = NoFind;
};

} // namespace Gui
37 changes: 24 additions & 13 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 @@ -122,35 +126,42 @@ void FindWidget::find(int options)
{
if (ui->findEdit->text().isEmpty())
return;
auto document = Core::Project::instance()->currentDocument();
if (auto textDocument = qobject_cast<Core::TextDocument *>(document))
textDocument->find(findString(), options);
Q_EMIT findRequested(ui->findEdit->text(), options);
}

void FindWidget::replaceOne()
{
replace(true);
replace(false);
}

void FindWidget::replaceAll()
{
replace(false);
replace(true);
}

void FindWidget::replace(bool onlyOne)
void FindWidget::replace(bool replaceAll)
{
const QString &before = findString();
const QString &after = ui->replaceEdit->text();
if (before.isEmpty())
return;

auto document = Core::Project::instance()->currentDocument();
if (auto textDocument = qobject_cast<Core::TextDocument *>(document)) {
if (onlyOne)
textDocument->replaceOne(before, after, findFlags());
else
textDocument->replaceAll(before, after, findFlags());
}
Q_EMIT replaceRequested(before, after, findFlags(), replaceAll);
}

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

void FindWidget::setReplaceVisible(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
12 changes: 11 additions & 1 deletion src/gui/findwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,24 @@ class FindWidget : public QWidget

void open();

void setReplaceVisible(bool show = true);

signals:
void findRequested(const QString &text, int options);
void replaceRequested(const QString &before, const QString &after, int options, bool replaceAll);
void widgetClosed();

protected:
void hideEvent(QHideEvent *event) override;

private:
int findFlags() const;
QString findString();

void find(int options);
void replaceOne();
void replaceAll();
void replace(bool onlyOne);
void replace(bool replaceAll);

std::unique_ptr<Ui::FindWidget> ui;
QAction *m_matchCase = nullptr;
Expand Down
6 changes: 3 additions & 3 deletions src/gui/findwidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<spacer name="replaceSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
Expand All @@ -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
86 changes: 86 additions & 0 deletions src/gui/highlightdelegate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
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 "highlightdelegate.h"
#include "core/textdocument.h"

#include <QAbstractTextDocumentLayout>
#include <QPainter>
#include <QTextDocument>

namespace Gui {

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

void HighlightDelegate::setHighlightedText(const QString &searchText, int options)
{
m_highlightedText = searchText;
m_options = options;
}

QString HighlightDelegate::transform(QString text, const QString &textColor, const QString &backgroundColor) const
{
if (m_highlightedText.isEmpty())
return text;

if (m_options & Core::TextDocument::FindRegexp) {
const auto re = QRegularExpression {m_highlightedText};
QRegularExpressionMatch match;
int index = text.indexOf(re, 0, &match);
while (index != -1) {
const auto oldText = match.captured(0);
const auto newText = QString("<span style='color: %1; background-color: %2;'>%3</span>")
.arg(textColor, backgroundColor, oldText);
text.replace(index, oldText.size(), newText);
index = text.indexOf(re, index + newText.size(), &match);
}
} else {
const bool caseSensitive = m_options & Core::TextDocument::FindCaseSensitively;
int index = text.indexOf(m_highlightedText, 0, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
while (index != -1) {
const auto oldText = text.mid(index, m_highlightedText.size());
const auto newText = QString("<span style='color: %1; background-color: %2;'>%3</span>")
.arg(textColor, backgroundColor, oldText);
text.replace(index, oldText.size(), newText);
index = text.indexOf(m_highlightedText, index + newText.size(),
caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
}
}
return text;
}

void HighlightDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
const auto textColor = option.palette.color(QPalette::HighlightedText).name();
const auto backgroundColor = option.palette.color(QPalette::Highlight).name();

// Display the text with the search string highlighted.
QString text = transform(index.data(Qt::DisplayRole).toString(), textColor, backgroundColor);
QTextDocument doc;
doc.setHtml(text);

painter->save();

// Adjust the painter's transformation to fit the text within the given rectangle
painter->translate(option.rect.topLeft());
QRect clip(0, 0, option.rect.width(), option.rect.height());
doc.setTextWidth(option.rect.width());

QAbstractTextDocumentLayout::PaintContext ctx;
ctx.clip = clip;
doc.documentLayout()->draw(painter, ctx);

painter->restore();
}

} // namespace Gui
35 changes: 35 additions & 0 deletions src/gui/highlightdelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
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 HighlightDelegate : public QItemDelegate
{
Q_OBJECT

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

void setHighlightedText(const QString &searchText, int options);

protected:
QString transform(QString text, const QString &textColor, const QString &backgroundColor) const;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;

private:
QString m_highlightedText;
int m_options;
};

} // namespace Gui
Loading
Loading