Skip to content

Commit

Permalink
Make comment header label searchable
Browse files Browse the repository at this point in the history
  • Loading branch information
joern274 committed Nov 12, 2023
1 parent 782dd5a commit 163f844
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class QToolButton;
namespace hal
{
class CommentEntry;
class SearchableLabel;

class CommentItem : public QFrame
{
Expand Down Expand Up @@ -86,7 +87,7 @@ namespace hal

// header part (perhaps no toolbar but a layout with toolbuttons instead of actions?)
QToolBar* mTopToolbar;
QLabel* mHeader;
SearchableLabel* mHeader;
QLabel* mCreationDate;
QAction* mModifyAction;
QAction* mDeleteAction;
Expand Down
58 changes: 58 additions & 0 deletions plugins/gui/include/gui/searchbar/searchable_label.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// MIT License
//
// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved.
// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved.
// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved.
// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#pragma once

#include <QLabel>
#include <QList>
#include <QPair>
#include <QPainter>

class QFontMetrics;

namespace hal {

class SearchableLabel : public QLabel
{
Q_OBJECT
protected:
void paintEvent(QPaintEvent* ev) override;
public Q_SLOTS:
void handleSearchChanged(const QString& string, int option);
public:
SearchableLabel(QWidget* parent = nullptr);
SearchableLabel(const QString& txt, QWidget* parent = nullptr);
bool hasMatch() const;
private:
void drawSubstring(QPainter& painter, int pos, int len, bool hilite);
bool exactWordMatch(int pos, int len) const;
QList<QPair<int,int> > mMatchPositions;
QFontMetrics* mMetrics;
int xText;
int yText;

static const int sHiliteOffset = 2;
};
}
6 changes: 4 additions & 2 deletions plugins/gui/src/comment_system/widgets/comment_item.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "gui/comment_system/widgets/comment_item.h"
#include "gui/comment_system/comment_entry.h"
#include "gui/comment_system/widgets/comment_dialog.h"
#include "gui/searchbar/searchable_label.h"
#include "gui/gui_globals.h"

#include <QToolBar>
Expand Down Expand Up @@ -52,7 +53,8 @@ namespace hal

bool CommentItem::search(const QString &string, SearchOptions searchOpts)
{
bool found = false;
mHeader->handleSearchChanged(string,searchOpts.toInt());
bool found = mHeader->hasMatch();
QList<QTextEdit::ExtraSelection> extraSelections;

mTextEdit->moveCursor(QTextCursor::Start);
Expand Down Expand Up @@ -125,7 +127,7 @@ namespace hal
mTopLayout->setSpacing(0);
mTopLayout->setMargin(0);

mHeader = new QLabel(this);
mHeader = new SearchableLabel(this);
mHeader->setStyleSheet("font-weight: bold;");
mCreationDate = new QLabel(this);
mCreationDate->setStyleSheet("font-size: 12px;");
Expand Down
134 changes: 134 additions & 0 deletions plugins/gui/src/searchbar/searchable_label.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include "gui/searchbar/searchable_label.h"
#include "gui/searchbar/searchoptions.h"
#include <QPainter>
#include <QFontMetrics>
#include <QDebug>
#include <QRegularExpression>

namespace hal {

SearchableLabel::SearchableLabel(const QString &txt, QWidget *parent)
: QLabel(txt, parent)
{;}

SearchableLabel::SearchableLabel(QWidget *parent)
: QLabel(parent)
{;}

void SearchableLabel::paintEvent(QPaintEvent* ev)
{
if (mMatchPositions.empty())
{
QLabel::paintEvent(ev);
return;
}
QPainter painter(this);
mMetrics = new QFontMetrics(font());
int fw = mMetrics->horizontalAdvance(text());
int fh = mMetrics->height();
int rw = rect().width();
int rh = rect().height();
if (alignment() & Qt::AlignHCenter)
xText = (rw-fw) / 2;
else if (alignment() & Qt::AlignRight)
xText = rw - fw;
else
xText = 0;
if (alignment() & Qt::AlignVCenter)
yText = (rh-fh) / 2;
else if (alignment() & Qt::AlignBottom)
yText = rh - fh;
else
yText = 0;
if (autoFillBackground())
painter.fillRect(rect(),palette().color(QPalette::Background));
int p0 = 0;
for (QPair<int,int> p1 : mMatchPositions)
{
drawSubstring(painter, p0, p1.first-p0, false);
drawSubstring(painter, p1.first, p1.second, true);
p0 = p1.first + p1.second;
}
if (p0 < text().size())
drawSubstring(painter, p0, text().size()-p0, false);
delete mMetrics;
}

void SearchableLabel::drawSubstring(QPainter& painter, int pos, int len, bool hilite)
{
if (len <= 0) return;

QColor storeColor = painter.pen().color();
QString sub = text().mid(pos,len);
int fw = mMetrics->horizontalAdvance(sub);
int fh = mMetrics->height();
if (hilite)
{
painter.setPen(QColor(255, 252, 240));
painter.fillRect(xText,yText-sHiliteOffset,fw,fh+2*sHiliteOffset,QBrush(QColor(33, 66, 133)));
}
painter.drawText(xText,yText,fw,fh,0,sub);
xText += fw;
if (hilite)
{
painter.setPen(storeColor);
}
}

bool SearchableLabel::exactWordMatch(int pos, int len) const
{
if (pos && !text().at(pos-1).isSpace()) return false;
if (pos + len < text().size() && !text().at(pos+len).isSpace()) return false;
return true;
}

bool SearchableLabel::hasMatch() const
{
return !mMatchPositions.isEmpty();
}

void SearchableLabel::handleSearchChanged(const QString& string, int option)
{
mMatchPositions.clear();
SearchOptions opts(option);
Qt::CaseSensitivity cs = opts.isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
if (!string.isEmpty())
{
int pos = 0;
if (opts.isRegularExpression())
{
// Regular expression search
QRegularExpression regexp(opts.isExactMatch() ? "\\b" + string + "\\b" : string,
opts.isCaseSensitive() ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
if (regexp.isValid())
{
QRegularExpressionMatch rmatch;
while (pos >= 0)
{
pos = text().indexOf(regexp,pos,&rmatch);
if (pos >= 0)
{
mMatchPositions.append(qMakePair(pos,rmatch.captured().size()));
++pos;
}
}
}
}
else
{
// String search
while (pos >= 0)
{
pos = text().indexOf(string,pos,cs);
if (pos >= 0)
{
if (!opts.isExactMatch() || exactWordMatch(pos,string.size()))
mMatchPositions.append(qMakePair(pos,string.size()));
++pos;
}
}
}
}
update();
}
}

0 comments on commit 163f844

Please sign in to comment.