Skip to content

Commit 1734a3f

Browse files
committed
Cleanup code and search widget display
* Make search widget larger * Move regex converter into Tools namespace * Use QSharedPointer for search terms
1 parent 9b5986c commit 1734a3f

File tree

8 files changed

+85
-50
lines changed

8 files changed

+85
-50
lines changed

src/core/EntrySearcher.cpp

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
#include "EntrySearcher.h"
2020

2121
#include "core/Group.h"
22+
#include "core/Tools.h"
2223

23-
EntrySearcher::EntrySearcher(bool caseSensitive) :
24-
m_caseSensitive(caseSensitive)
24+
EntrySearcher::EntrySearcher(bool caseSensitive)
25+
: m_caseSensitive(caseSensitive)
26+
, m_termParser(R"re(([-*+]+)?(?:(\w*):)?(?:(?=")"((?:[^"\\]|\\.)*)"|([^ ]*))( |$))re")
27+
// Group 1 = modifiers, Group 2 = field, Group 3 = quoted string, Group 4 = unquoted string
2528
{
2629
}
2730

@@ -58,16 +61,21 @@ void EntrySearcher::setCaseSensitive(bool state)
5861
m_caseSensitive = state;
5962
}
6063

61-
bool EntrySearcher::searchEntryImpl(const QString& searchString, Entry* entry)
64+
bool EntrySearcher::isCaseSensitive()
6265
{
63-
auto searchTerms = parseSearchTerms(searchString);
64-
bool found;
66+
return m_caseSensitive;
67+
}
6568

69+
bool EntrySearcher::searchEntryImpl(const QString& searchString, Entry* entry)
70+
{
6671
// Pre-load in case they are needed
6772
auto attributes = QStringList(entry->attributes()->keys());
6873
auto attachments = QStringList(entry->attachments()->keys());
6974

70-
for (SearchTerm* term : searchTerms) {
75+
bool found;
76+
auto searchTerms = parseSearchTerms(searchString);
77+
78+
for (const auto& term : searchTerms) {
7179
switch (term->field) {
7280
case Field::Title:
7381
found = term->regex.match(entry->resolvePlaceholder(entry->title())).hasMatch();
@@ -106,18 +114,14 @@ bool EntrySearcher::searchEntryImpl(const QString& searchString, Entry* entry)
106114
return true;
107115
}
108116

109-
QList<EntrySearcher::SearchTerm*> EntrySearcher::parseSearchTerms(const QString& searchString)
117+
QList<QSharedPointer<EntrySearcher::SearchTerm> > EntrySearcher::parseSearchTerms(const QString& searchString)
110118
{
111-
auto terms = QList<SearchTerm*>();
112-
// Group 1 = modifiers, Group 2 = field, Group 3 = quoted string, Group 4 = unquoted string
113-
auto termParser = QRegularExpression(R"re(([-*+]+)?(?:(\w*):)?(?:(?=")"((?:[^"\\]|\\.)*)"|([^ ]*))( |$))re");
114-
// Escape common regex symbols except for *, ?, and |
115-
auto regexEscape = QRegularExpression(R"re(([-[\]{}()+.,\\\/^$#]))re");
119+
auto terms = QList<QSharedPointer<SearchTerm> >();
116120

117-
auto results = termParser.globalMatch(searchString);
121+
auto results = m_termParser.globalMatch(searchString);
118122
while (results.hasNext()) {
119123
auto result = results.next();
120-
auto term = new SearchTerm();
124+
QSharedPointer<SearchTerm> term(new SearchTerm());
121125

122126
// Quoted string group
123127
term->word = result.captured(3);
@@ -129,32 +133,16 @@ QList<EntrySearcher::SearchTerm*> EntrySearcher::parseSearchTerms(const QString&
129133

130134
// If still empty, ignore this match
131135
if (term->word.isEmpty()) {
132-
delete term;
133136
continue;
134137
}
135138

136-
QString regex = term->word;
137-
138-
// Wildcard support (*, ?, |)
139-
if (!result.captured(1).contains("*")) {
140-
regex.replace(regexEscape, "\\\\1");
141-
regex.replace("**", "*");
142-
regex.replace("*", ".*");
143-
regex.replace("?", ".");
144-
}
145-
146-
term->regex = QRegularExpression(regex);
147-
if (!m_caseSensitive) {
148-
term->regex.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
149-
}
139+
auto mods = result.captured(1);
150140

151-
// Exact modifier
152-
if (result.captured(1).contains("+")) {
153-
term->regex.setPattern("^" + term->regex.pattern() + "$");
154-
}
141+
// Convert term to regex
142+
term->regex = Tools::convertToRegex(term->word, !mods.contains("*"), mods.contains("+"), m_caseSensitive);
155143

156144
// Exclude modifier
157-
term->exclude = result.captured(1).contains("-");
145+
term->exclude = mods.contains("-");
158146

159147
// Determine the field to search
160148
QString field = result.captured(2);
@@ -175,7 +163,7 @@ QList<EntrySearcher::SearchTerm*> EntrySearcher::parseSearchTerms(const QString&
175163
} else if (field.startsWith("attach", cs)) {
176164
term->field = Field::Attachment;
177165
} else {
178-
term->field = Field::All;
166+
term->field = Field::Undefined;
179167
}
180168
}
181169

src/core/EntrySearcher.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,19 @@ class Entry;
2828
class EntrySearcher
2929
{
3030
public:
31-
EntrySearcher(bool caseSensitive = false);
31+
explicit EntrySearcher(bool caseSensitive = false);
3232

3333
QList<Entry*> search(const QString& searchString, const Group* group);
3434
QList<Entry*> searchEntries(const QString& searchString, const QList<Entry*>& entries);
3535

3636
void setCaseSensitive(bool state);
37+
bool isCaseSensitive();
3738

3839
private:
3940
bool searchEntryImpl(const QString& searchString, Entry* entry);
4041

4142
enum Field {
42-
All,
43+
Undefined,
4344
Title,
4445
Username,
4546
Password,
@@ -57,9 +58,10 @@ class EntrySearcher
5758
bool exclude;
5859
};
5960

60-
QList<SearchTerm*> parseSearchTerms(const QString& searchString);
61+
QList<QSharedPointer<SearchTerm> > parseSearchTerms(const QString& searchString);
6162

6263
bool m_caseSensitive;
64+
QRegularExpression m_termParser;
6365

6466
friend class TestEntrySearcher;
6567
};

src/core/Tools.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <QImageReader>
2525
#include <QLocale>
2626
#include <QStringList>
27+
#include <QRegularExpression>
2728
#include <cctype>
2829

2930
#include <QElapsedTimer>
@@ -346,4 +347,32 @@ namespace Tools
346347
return bSuccess;
347348
}
348349

350+
// Escape common regex symbols except for *, ?, and |
351+
auto regexEscape = QRegularExpression(R"re(([-[\]{}()+.,\\\/^$#]))re");
352+
353+
QRegularExpression convertToRegex(const QString& string, bool useWildcards, bool exactMatch, bool caseSensitive)
354+
{
355+
QString pattern = string;
356+
357+
// Wildcard support (*, ?, |)
358+
if (useWildcards) {
359+
pattern.replace(regexEscape, "\\\\1");
360+
pattern.replace("**", "*");
361+
pattern.replace("*", ".*");
362+
pattern.replace("?", ".");
363+
}
364+
365+
// Exact modifier
366+
if (exactMatch) {
367+
pattern = "^" + pattern + "$";
368+
}
369+
370+
auto regex = QRegularExpression(pattern);
371+
if (!caseSensitive) {
372+
regex.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
373+
}
374+
375+
return regex;
376+
}
377+
349378
} // namespace Tools

src/core/Tools.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <algorithm>
2929

3030
class QIODevice;
31+
class QRegularExpression;
3132

3233
namespace Tools
3334
{
@@ -44,6 +45,8 @@ namespace Tools
4445
void disableCoreDumps();
4546
void setupSearchPaths();
4647
bool createWindowsDACL();
48+
QRegularExpression convertToRegex(const QString& string, bool useWildcards = false, bool exactMatch = false,
49+
bool caseSensitive = false);
4750

4851
template <typename RandomAccessIterator, typename T>
4952
RandomAccessIterator binaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T& value)

src/gui/DatabaseWidget.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
220220
m_fileWatchUnblockTimer.setSingleShot(true);
221221
m_ignoreAutoReload = false;
222222

223-
m_searchCaseSensitive = false;
223+
m_EntrySearcher = new EntrySearcher(false);
224224
m_searchLimitGroup = config()->get("SearchLimitGroup", false).toBool();
225225

226226
#ifdef WITH_XC_SSHAGENT
@@ -238,6 +238,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
238238

239239
DatabaseWidget::~DatabaseWidget()
240240
{
241+
delete m_EntrySearcher;
241242
}
242243

243244
DatabaseWidget::Mode DatabaseWidget::currentMode() const
@@ -1066,13 +1067,13 @@ void DatabaseWidget::search(const QString& searchtext)
10661067

10671068
Group* searchGroup = m_searchLimitGroup ? currentGroup() : m_db->rootGroup();
10681069

1069-
QList<Entry*> searchResult = EntrySearcher(m_searchCaseSensitive).search(searchtext, searchGroup);
1070+
QList<Entry*> searchResult = m_EntrySearcher->search(searchtext, searchGroup);
10701071

10711072
m_entryView->displaySearch(searchResult);
10721073
m_lastSearchText = searchtext;
10731074

10741075
// Display a label detailing our search results
1075-
if (searchResult.size() > 0) {
1076+
if (!searchResult.isEmpty()) {
10761077
m_searchingLabel->setText(tr("Search Results (%1)").arg(searchResult.size()));
10771078
} else {
10781079
m_searchingLabel->setText(tr("No Results"));
@@ -1085,7 +1086,7 @@ void DatabaseWidget::search(const QString& searchtext)
10851086

10861087
void DatabaseWidget::setSearchCaseSensitive(bool state)
10871088
{
1088-
m_searchCaseSensitive = state;
1089+
m_EntrySearcher->setCaseSensitive(state);
10891090
refreshSearch();
10901091
}
10911092

src/gui/DatabaseWidget.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class EditEntryWidget;
3737
class EditGroupWidget;
3838
class Entry;
3939
class EntryView;
40+
class EntrySearcher;
4041
class Group;
4142
class GroupView;
4243
class KeePass1OpenWidget;
@@ -239,8 +240,8 @@ private slots:
239240
DetailsWidget* m_detailsView;
240241

241242
// Search state
243+
EntrySearcher* m_EntrySearcher;
242244
QString m_lastSearchText;
243-
bool m_searchCaseSensitive;
244245
bool m_searchLimitGroup;
245246

246247
// CSV import state

src/gui/SearchWidget.ui

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
<property name="orientation">
3535
<enum>Qt::Horizontal</enum>
3636
</property>
37+
<property name="sizeType">
38+
<enum>QSizePolicy::Minimum</enum>
39+
</property>
3740
<property name="sizeHint" stdset="0">
3841
<size>
3942
<width>30</width>
@@ -44,6 +47,18 @@
4447
</item>
4548
<item>
4649
<widget class="QLineEdit" name="searchEdit">
50+
<property name="sizePolicy">
51+
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
52+
<horstretch>0</horstretch>
53+
<verstretch>0</verstretch>
54+
</sizepolicy>
55+
</property>
56+
<property name="minimumSize">
57+
<size>
58+
<width>0</width>
59+
<height>0</height>
60+
</size>
61+
</property>
4762
<property name="styleSheet">
4863
<string notr="true">padding:3px</string>
4964
</property>

tests/TestEntrySearcher.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,11 @@ void TestEntrySearcher::testSearchTermParser()
144144

145145
QCOMPARE(terms.length(), 5);
146146

147-
QCOMPARE(terms[0]->field, EntrySearcher::All);
147+
QCOMPARE(terms[0]->field, EntrySearcher::Undefined);
148148
QCOMPARE(terms[0]->word, QString("test"));
149149
QCOMPARE(terms[0]->exclude, true);
150150

151-
QCOMPARE(terms[1]->field, EntrySearcher::All);
151+
QCOMPARE(terms[1]->field, EntrySearcher::Undefined);
152152
QCOMPARE(terms[1]->word, QString("quoted \\\"string\\\""));
153153
QCOMPARE(terms[1]->exclude, false);
154154

@@ -158,11 +158,9 @@ void TestEntrySearcher::testSearchTermParser()
158158
QCOMPARE(terms[3]->field, EntrySearcher::Password);
159159
QCOMPARE(terms[3]->word, QString("test me"));
160160

161-
QCOMPARE(terms[4]->field, EntrySearcher::All);
161+
QCOMPARE(terms[4]->field, EntrySearcher::Undefined);
162162
QCOMPARE(terms[4]->word, QString("noquote"));
163163

164-
qDeleteAll(terms);
165-
166164
// Test wildcard and regex search terms
167165
terms = m_entrySearcher.parseSearchTerms("+url:*.google.com *user:\\d+\\w{2}");
168166

@@ -173,6 +171,4 @@ void TestEntrySearcher::testSearchTermParser()
173171

174172
QCOMPARE(terms[1]->field, EntrySearcher::Username);
175173
QCOMPARE(terms[1]->regex.pattern(), QString("\\d+\\w{2}"));
176-
177-
qDeleteAll(terms);
178174
}

0 commit comments

Comments
 (0)