Merge pull request #5191
TriKriSta (20): feat: create widget for search settings feat: use search settings feat: add functions for change title and info in LoadHistoryDialog feat: add startButton in SearchForm chore: install sqlite in travis refactor: remove commented code, use QStringLiteral docs: add documentation for some new functions refactor: change QRegExp on QRegularExpression for some search functions feat: add function for generating a filter for search word only refactor: use const and QStringLiteral style: add labels.css refactor: edit generateFilterWordsOnly refactor: delete sqlite in travis, edit some functions chore: install Qt 5.6 in travis refactor: use Settings, add const refactor: add code for work in Qt5.5 refactor: change text and icons in search forms feat: add message if text not found refactor: add SearchDirection Merge branch 'master' into search
@ -103,6 +103,7 @@ qt5_wrap_ui(${PROJECT_NAME}_FORMS
|
|||||||
src/widget/form/loadhistorydialog.ui
|
src/widget/form/loadhistorydialog.ui
|
||||||
src/widget/form/profileform.ui
|
src/widget/form/profileform.ui
|
||||||
src/widget/form/removefrienddialog.ui
|
src/widget/form/removefrienddialog.ui
|
||||||
|
src/widget/form/searchsettingsform.ui
|
||||||
src/widget/form/setpassworddialog.ui
|
src/widget/form/setpassworddialog.ui
|
||||||
src/widget/form/settings/aboutsettings.ui
|
src/widget/form/settings/aboutsettings.ui
|
||||||
src/widget/form/settings/advancedsettings.ui
|
src/widget/form/settings/advancedsettings.ui
|
||||||
@ -360,6 +361,7 @@ set(${PROJECT_NAME}_SOURCES
|
|||||||
src/widget/flowlayout.h
|
src/widget/flowlayout.h
|
||||||
src/widget/searchform.cpp
|
src/widget/searchform.cpp
|
||||||
src/widget/searchform.h
|
src/widget/searchform.h
|
||||||
|
src/widget/searchtypes.h
|
||||||
src/widget/form/addfriendform.cpp
|
src/widget/form/addfriendform.cpp
|
||||||
src/widget/form/addfriendform.h
|
src/widget/form/addfriendform.h
|
||||||
src/widget/form/chatform.cpp
|
src/widget/form/chatform.cpp
|
||||||
@ -378,6 +380,8 @@ set(${PROJECT_NAME}_SOURCES
|
|||||||
src/widget/form/loadhistorydialog.h
|
src/widget/form/loadhistorydialog.h
|
||||||
src/widget/form/profileform.cpp
|
src/widget/form/profileform.cpp
|
||||||
src/widget/form/profileform.h
|
src/widget/form/profileform.h
|
||||||
|
src/widget/form/searchsettingsform.cpp
|
||||||
|
src/widget/form/searchsettingsform.h
|
||||||
src/widget/form/setpassworddialog.cpp
|
src/widget/form/setpassworddialog.cpp
|
||||||
src/widget/form/setpassworddialog.h
|
src/widget/form/setpassworddialog.h
|
||||||
src/widget/form/settings/aboutform.cpp
|
src/widget/form/settings/aboutform.cpp
|
||||||
|
3
res.qrc
@ -55,6 +55,7 @@
|
|||||||
<file>ui/chatForm/buttons.css</file>
|
<file>ui/chatForm/buttons.css</file>
|
||||||
<file>ui/chatForm/fullScreenButtons.css</file>
|
<file>ui/chatForm/fullScreenButtons.css</file>
|
||||||
<file>ui/chatForm/callButton.svg</file>
|
<file>ui/chatForm/callButton.svg</file>
|
||||||
|
<file>ui/chatForm/labels.css</file>
|
||||||
<file>ui/chatForm/micButton.svg</file>
|
<file>ui/chatForm/micButton.svg</file>
|
||||||
<file>ui/chatForm/micButtonRed.svg</file>
|
<file>ui/chatForm/micButtonRed.svg</file>
|
||||||
<file>ui/chatForm/videoButton.svg</file>
|
<file>ui/chatForm/videoButton.svg</file>
|
||||||
@ -66,8 +67,10 @@
|
|||||||
<file>ui/chatForm/emoteButton.svg</file>
|
<file>ui/chatForm/emoteButton.svg</file>
|
||||||
<file>ui/chatForm/fileButton.svg</file>
|
<file>ui/chatForm/fileButton.svg</file>
|
||||||
<file>ui/chatForm/screenshotButton.svg</file>
|
<file>ui/chatForm/screenshotButton.svg</file>
|
||||||
|
<file>ui/chatForm/searchCalendarButton.svg</file>
|
||||||
<file>ui/chatForm/searchDownButton.svg</file>
|
<file>ui/chatForm/searchDownButton.svg</file>
|
||||||
<file>ui/chatForm/searchHideButton.svg</file>
|
<file>ui/chatForm/searchHideButton.svg</file>
|
||||||
|
<file>ui/chatForm/searchSettingsButton.svg</file>
|
||||||
<file>ui/chatForm/searchUpButton.svg</file>
|
<file>ui/chatForm/searchUpButton.svg</file>
|
||||||
<file>ui/chatForm/sendButton.svg</file>
|
<file>ui/chatForm/sendButton.svg</file>
|
||||||
<file>ui/chatForm/exitFullScreenButton.svg</file>
|
<file>ui/chatForm/exitFullScreenButton.svg</file>
|
||||||
|
@ -553,6 +553,14 @@ ChatLine::Ptr ChatLog::getLatestLine() const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatLine::Ptr ChatLog::getFirstLine() const
|
||||||
|
{
|
||||||
|
if (!lines.empty()) {
|
||||||
|
return lines.first();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Finds the chat line object at a position on screen
|
* @brief Finds the chat line object at a position on screen
|
||||||
* @param pos Position on screen in global coordinates
|
* @param pos Position on screen in global coordinates
|
||||||
|
@ -62,6 +62,7 @@ public:
|
|||||||
ChatLine::Ptr getTypingNotification() const;
|
ChatLine::Ptr getTypingNotification() const;
|
||||||
QVector<ChatLine::Ptr> getLines();
|
QVector<ChatLine::Ptr> getLines();
|
||||||
ChatLine::Ptr getLatestLine() const;
|
ChatLine::Ptr getLatestLine() const;
|
||||||
|
ChatLine::Ptr getFirstLine() const;
|
||||||
ChatLineContent* getContentFromGlobalPos(QPoint pos) const;
|
ChatLineContent* getContentFromGlobalPos(QPoint pos) const;
|
||||||
const uint repNameAfter = 5 * 60;
|
const uint repNameAfter = 5 * 60;
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
#include "src/widget/style.h"
|
#include "src/widget/style.h"
|
||||||
|
|
||||||
|
static const QString COLOR_HIGHLIGHT = QStringLiteral("#ff7626");
|
||||||
|
|
||||||
Text::Text(const QString& txt, const QFont& font, bool enableElide, const QString& rwText,
|
Text::Text(const QString& txt, const QFont& font, bool enableElide, const QString& rwText,
|
||||||
const QColor c)
|
const QColor c)
|
||||||
: rawText(rwText)
|
: rawText(rwText)
|
||||||
@ -58,7 +60,7 @@ void Text::setText(const QString& txt)
|
|||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Text::selectText(const QString &txt, const int index)
|
void Text::selectText(const QString& txt, const std::pair<int, int>& point)
|
||||||
{
|
{
|
||||||
regenerate();
|
regenerate();
|
||||||
|
|
||||||
@ -66,21 +68,22 @@ void Text::selectText(const QString &txt, const int index)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cursor = doc->find(txt, index);
|
auto cursor = doc->find(txt, point.first);
|
||||||
|
|
||||||
if (!cursor.isNull()) {
|
selectText(cursor, point);
|
||||||
cursor.beginEditBlock();
|
}
|
||||||
cursor.setPosition(index);
|
|
||||||
cursor.setPosition(index + txt.size(), QTextCursor::KeepAnchor);
|
|
||||||
cursor.endEditBlock();
|
|
||||||
|
|
||||||
QTextCharFormat format;
|
|
||||||
format.setBackground(QBrush(QColor("#ff7626")));
|
|
||||||
cursor.mergeCharFormat(format);
|
|
||||||
|
|
||||||
|
void Text::selectText(const QRegularExpression &exp, const std::pair<int, int>& point)
|
||||||
|
{
|
||||||
regenerate();
|
regenerate();
|
||||||
update();
|
|
||||||
|
if (!doc) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto cursor = doc->find(exp, point.first);
|
||||||
|
|
||||||
|
selectText(cursor, point);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Text::deselectText()
|
void Text::deselectText()
|
||||||
@ -439,3 +442,20 @@ QString Text::extractImgTooltip(int pos) const
|
|||||||
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Text::selectText(QTextCursor& cursor, const std::pair<int, int>& point)
|
||||||
|
{
|
||||||
|
if (!cursor.isNull()) {
|
||||||
|
cursor.beginEditBlock();
|
||||||
|
cursor.setPosition(point.first);
|
||||||
|
cursor.setPosition(point.first + point.second, QTextCursor::KeepAnchor);
|
||||||
|
cursor.endEditBlock();
|
||||||
|
|
||||||
|
QTextCharFormat format;
|
||||||
|
format.setBackground(QBrush(QColor(COLOR_HIGHLIGHT)));
|
||||||
|
cursor.mergeCharFormat(format);
|
||||||
|
|
||||||
|
regenerate();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,7 +36,8 @@ public:
|
|||||||
virtual ~Text();
|
virtual ~Text();
|
||||||
|
|
||||||
void setText(const QString& txt);
|
void setText(const QString& txt);
|
||||||
void selectText(const QString& txt, const int index);
|
void selectText(const QString& txt, const std::pair<int, int>& point);
|
||||||
|
void selectText(const QRegularExpression& exp, const std::pair<int, int>& point);
|
||||||
void deselectText();
|
void deselectText();
|
||||||
|
|
||||||
virtual void setWidth(qreal width) final;
|
virtual void setWidth(qreal width) final;
|
||||||
@ -78,6 +79,8 @@ protected:
|
|||||||
QString extractImgTooltip(int pos) const;
|
QString extractImgTooltip(int pos) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void selectText(QTextCursor& cursor, const std::pair<int, int>& point);
|
||||||
|
|
||||||
QTextDocument* doc = nullptr;
|
QTextDocument* doc = nullptr;
|
||||||
QString text;
|
QString text;
|
||||||
QString rawText;
|
QString rawText;
|
||||||
|
@ -28,14 +28,6 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
/// The two following defines are required to use SQLCipher
|
|
||||||
/// They are used by the sqlite3.h header
|
|
||||||
#define SQLITE_HAS_CODEC
|
|
||||||
#define SQLITE_TEMP_STORE 2
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,6 +163,18 @@ bool RawDatabase::open(const QString& path, const QString& hexKey)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sqlite3_create_function(sqlite, "regexp", 2, SQLITE_UTF8, NULL, &RawDatabase::regexpInsensitive, NULL, NULL)) {
|
||||||
|
qWarning() << "Failed to create function regexp";
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sqlite3_create_function(sqlite, "regexpsensitive", 2, SQLITE_UTF8, NULL, &RawDatabase::regexpSensitive, NULL, NULL)) {
|
||||||
|
qWarning() << "Failed to create function regexpsensitive";
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!hexKey.isEmpty()) {
|
if (!hexKey.isEmpty()) {
|
||||||
if (!execNow("PRAGMA key = \"x'" + hexKey + "'\"")) {
|
if (!execNow("PRAGMA key = \"x'" + hexKey + "'\"")) {
|
||||||
qWarning() << "Failed to set encryption key";
|
qWarning() << "Failed to set encryption key";
|
||||||
@ -705,3 +709,43 @@ QVariant RawDatabase::extractData(sqlite3_stmt* stmt, int col)
|
|||||||
return QByteArray::fromRawData(data, len);
|
return QByteArray::fromRawData(data, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Use for create function in db for search data use regular experessions without case sensitive
|
||||||
|
* @param ctx ctx the context in which an SQL function executes
|
||||||
|
* @param argc number of arguments
|
||||||
|
* @param argv arguments
|
||||||
|
*/
|
||||||
|
void RawDatabase::regexpInsensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv)
|
||||||
|
{
|
||||||
|
regexp(ctx, argc, argv, QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Use for create function in db for search data use regular experessions without case sensitive
|
||||||
|
* @param ctx the context in which an SQL function executes
|
||||||
|
* @param argc number of arguments
|
||||||
|
* @param argv arguments
|
||||||
|
*/
|
||||||
|
void RawDatabase::regexpSensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv)
|
||||||
|
{
|
||||||
|
regexp(ctx, argc, argv, QRegularExpression::UseUnicodePropertiesOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RawDatabase::regexp(sqlite3_context* ctx, int argc, sqlite3_value** argv, const QRegularExpression::PatternOptions cs)
|
||||||
|
{
|
||||||
|
QRegularExpression regex;
|
||||||
|
const QString str1(reinterpret_cast<const char*>(sqlite3_value_text(argv[0])));
|
||||||
|
const QString str2(reinterpret_cast<const char*>(sqlite3_value_text(argv[1])));
|
||||||
|
|
||||||
|
regex.setPattern(str1);
|
||||||
|
regex.setPatternOptions(cs);
|
||||||
|
|
||||||
|
const bool b = str2.contains(regex);
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
sqlite3_result_int(ctx, 1);
|
||||||
|
} else {
|
||||||
|
sqlite3_result_int(ctx, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,12 +9,18 @@
|
|||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
struct sqlite3;
|
/// The two following defines are required to use SQLCipher
|
||||||
struct sqlite3_stmt;
|
/// They are used by the sqlite3.h header
|
||||||
|
#define SQLITE_HAS_CODEC
|
||||||
|
#define SQLITE_TEMP_STORE 2
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
|
||||||
class RawDatabase : QObject
|
class RawDatabase : QObject
|
||||||
{
|
{
|
||||||
@ -85,8 +91,12 @@ protected:
|
|||||||
static QString deriveKey(const QString& password, const QByteArray& salt);
|
static QString deriveKey(const QString& password, const QByteArray& salt);
|
||||||
static QString deriveKey(const QString& password);
|
static QString deriveKey(const QString& password);
|
||||||
static QVariant extractData(sqlite3_stmt* stmt, int col);
|
static QVariant extractData(sqlite3_stmt* stmt, int col);
|
||||||
|
static void regexpInsensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv);
|
||||||
|
static void regexpSensitive(sqlite3_context* ctx, int argc, sqlite3_value** argv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void regexp(sqlite3_context* ctx, int argc, sqlite3_value** argv, const QRegularExpression::PatternOptions cs);
|
||||||
|
|
||||||
struct Transaction
|
struct Transaction
|
||||||
{
|
{
|
||||||
QVector<Query> queries;
|
QVector<Query> queries;
|
||||||
|
@ -315,35 +315,107 @@ QList<History::DateMessages> History::getChatHistoryCounts(const ToxPk& friendPk
|
|||||||
return counts;
|
return counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime History::getDateWhereFindPhrase(const QString& friendPk, const QDateTime& from, QString phrase)
|
/**
|
||||||
|
* @brief Search phrase in chat messages
|
||||||
|
* @param friendPk Friend public key
|
||||||
|
* @param from a date message where need to start a search
|
||||||
|
* @param phrase what need to find
|
||||||
|
* @param parameter for search
|
||||||
|
* @return date of the message where the phrase was found
|
||||||
|
*/
|
||||||
|
QDateTime History::getDateWhereFindPhrase(const QString& friendPk, const QDateTime& from, QString phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
QList<QDateTime> counts;
|
QDateTime result;
|
||||||
auto rowCallback = [&counts](const QVector<QVariant>& row) {
|
auto rowCallback = [&result](const QVector<QVariant>& row) {
|
||||||
counts.append(QDateTime::fromMSecsSinceEpoch(row[0].toLongLong()));
|
result = QDateTime::fromMSecsSinceEpoch(row[0].toLongLong());
|
||||||
};
|
};
|
||||||
|
|
||||||
phrase.replace("'", "''");
|
phrase.replace("'", "''");
|
||||||
|
|
||||||
|
QString message;
|
||||||
|
|
||||||
|
switch (parameter.filter) {
|
||||||
|
case FilterSearch::Register:
|
||||||
|
message = QStringLiteral("message LIKE '%%1%'").arg(phrase);
|
||||||
|
break;
|
||||||
|
case FilterSearch::WordsOnly:
|
||||||
|
message = QStringLiteral("message REGEXP '%1'").arg(SearchExtraFunctions::generateFilterWordsOnly(phrase).toLower());
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndWordsOnly:
|
||||||
|
message = QStringLiteral("REGEXPSENSITIVE(message, '%1')").arg(SearchExtraFunctions::generateFilterWordsOnly(phrase));
|
||||||
|
break;
|
||||||
|
case FilterSearch::Regular:
|
||||||
|
message = QStringLiteral("message REGEXP '%1'").arg(phrase);
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndRegular:
|
||||||
|
message = QStringLiteral("REGEXPSENSITIVE(message '%1')").arg(phrase);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = QStringLiteral("LOWER(message) LIKE '%%1%'").arg(phrase.toLower());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime date = from;
|
||||||
|
if (parameter.period == PeriodSearch::AfterDate || parameter.period == PeriodSearch::BeforeDate) {
|
||||||
|
date = QDateTime(parameter.date);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString period;
|
||||||
|
switch (parameter.period) {
|
||||||
|
case PeriodSearch::WithTheFirst:
|
||||||
|
period = QStringLiteral("ORDER BY timestamp ASC LIMIT 1;");
|
||||||
|
break;
|
||||||
|
case PeriodSearch::AfterDate:
|
||||||
|
period = QStringLiteral("AND timestamp > '%1' ORDER BY timestamp ASC LIMIT 1;").arg(date.toMSecsSinceEpoch());
|
||||||
|
break;
|
||||||
|
case PeriodSearch::BeforeDate:
|
||||||
|
period = QStringLiteral("AND timestamp < '%1' ORDER BY timestamp DESC LIMIT 1;").arg(date.toMSecsSinceEpoch());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
period = QStringLiteral("AND timestamp < '%1' ORDER BY timestamp DESC LIMIT 1;").arg(date.toMSecsSinceEpoch());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
QString queryText =
|
QString queryText =
|
||||||
QString("SELECT timestamp "
|
QStringLiteral("SELECT timestamp "
|
||||||
"FROM history "
|
"FROM history "
|
||||||
"LEFT JOIN faux_offline_pending ON history.id = faux_offline_pending.id "
|
"LEFT JOIN faux_offline_pending ON history.id = faux_offline_pending.id "
|
||||||
"JOIN peers chat ON chat_id = chat.id "
|
"JOIN peers chat ON chat_id = chat.id "
|
||||||
"WHERE chat.public_key='%1' "
|
"WHERE chat.public_key='%1' "
|
||||||
"AND message LIKE '%%2%' "
|
"AND %2 "
|
||||||
"AND timestamp < '%3' ORDER BY timestamp DESC LIMIT 1;")
|
"%3")
|
||||||
.arg(friendPk)
|
.arg(friendPk)
|
||||||
.arg(phrase)
|
.arg(message)
|
||||||
.arg(from.toMSecsSinceEpoch());
|
.arg(period);
|
||||||
|
|
||||||
|
|
||||||
db->execNow({queryText, rowCallback});
|
db->execNow({queryText, rowCallback});
|
||||||
|
|
||||||
if (!counts.isEmpty()) {
|
return result;
|
||||||
return counts[0];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return QDateTime();
|
/**
|
||||||
|
* @brief get start date of correspondence
|
||||||
|
* @param friendPk Friend public key
|
||||||
|
* @return start date of correspondence
|
||||||
|
*/
|
||||||
|
QDateTime History::getStartDateChatHistory(const QString &friendPk)
|
||||||
|
{
|
||||||
|
QDateTime result;
|
||||||
|
auto rowCallback = [&result](const QVector<QVariant>& row) {
|
||||||
|
result = QDateTime::fromMSecsSinceEpoch(row[0].toLongLong());
|
||||||
|
};
|
||||||
|
|
||||||
|
QString queryText =
|
||||||
|
QStringLiteral("SELECT timestamp "
|
||||||
|
"FROM history "
|
||||||
|
"LEFT JOIN faux_offline_pending ON history.id = faux_offline_pending.id "
|
||||||
|
"JOIN peers chat ON chat_id = chat.id "
|
||||||
|
"WHERE chat.public_key='%1' ORDER BY timestamp ASC LIMIT 1;")
|
||||||
|
.arg(friendPk);
|
||||||
|
|
||||||
|
db->execNow({queryText, rowCallback});
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "src/core/toxpk.h"
|
#include "src/core/toxpk.h"
|
||||||
#include "src/persistence/db/rawdatabase.h"
|
#include "src/persistence/db/rawdatabase.h"
|
||||||
|
#include "src/widget/searchtypes.h"
|
||||||
|
|
||||||
class Profile;
|
class Profile;
|
||||||
class HistoryKeeper;
|
class HistoryKeeper;
|
||||||
@ -82,7 +83,8 @@ public:
|
|||||||
const QDateTime& to);
|
const QDateTime& to);
|
||||||
QList<HistMessage> getChatHistoryDefaultNum(const QString& friendPk);
|
QList<HistMessage> getChatHistoryDefaultNum(const QString& friendPk);
|
||||||
QList<DateMessages> getChatHistoryCounts(const ToxPk& friendPk, const QDate& from, const QDate& to);
|
QList<DateMessages> getChatHistoryCounts(const ToxPk& friendPk, const QDate& from, const QDate& to);
|
||||||
QDateTime getDateWhereFindPhrase(const QString& friendPk, const QDateTime& from, QString phrase);
|
QDateTime getDateWhereFindPhrase(const QString& friendPk, const QDateTime& from, QString phrase, const ParameterSearch ¶meter);
|
||||||
|
QDateTime getStartDateChatHistory(const QString& friendPk);
|
||||||
|
|
||||||
void markAsSent(qint64 messageId);
|
void markAsSent(qint64 messageId);
|
||||||
|
|
||||||
|
@ -502,7 +502,38 @@ void ChatForm::onVolMuteToggle()
|
|||||||
updateMuteVolButton();
|
updateMuteVolButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::onSearchUp(const QString& phrase)
|
void ChatForm::searchInBegin(const QString& phrase, const ParameterSearch& parameter)
|
||||||
|
{
|
||||||
|
disableSearchText();
|
||||||
|
|
||||||
|
searchPoint = QPoint(1, -1);
|
||||||
|
|
||||||
|
const bool isFirst = (parameter.period == PeriodSearch::WithTheFirst);
|
||||||
|
const bool isAfter = (parameter.period == PeriodSearch::AfterDate);
|
||||||
|
if (isFirst || isAfter) {
|
||||||
|
if (isFirst || (isAfter && parameter.date < getFirstDate())) {
|
||||||
|
const QString pk = f->getPublicKey().toString();
|
||||||
|
if ((isFirst || parameter.date >= history->getStartDateChatHistory(pk).date()) &&
|
||||||
|
loadHistory(phrase, parameter)) {
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearchDown(phrase, parameter);
|
||||||
|
} else {
|
||||||
|
if (parameter.period == PeriodSearch::BeforeDate && parameter.date < getFirstDate()) {
|
||||||
|
const QString pk = f->getPublicKey().toString();
|
||||||
|
if (parameter.date >= history->getStartDateChatHistory(pk).date() && loadHistory(phrase, parameter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearchUp(phrase, parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatForm::onSearchUp(const QString& phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
if (phrase.isEmpty()) {
|
if (phrase.isEmpty()) {
|
||||||
disableSearchText();
|
disableSearchText();
|
||||||
@ -511,29 +542,27 @@ void ChatForm::onSearchUp(const QString& phrase)
|
|||||||
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
|
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
|
||||||
int numLines = lines.size();
|
int numLines = lines.size();
|
||||||
|
|
||||||
int startLine = numLines - searchPoint.x();
|
int startLine;
|
||||||
|
|
||||||
if (startLine == 0) {
|
if (searchAfterLoadHistory) {
|
||||||
QString pk = f->getPublicKey().toString();
|
startLine = 1;
|
||||||
QDateTime newBaseDate = history->getDateWhereFindPhrase(pk, earliestMessage, phrase);
|
searchAfterLoadHistory = false;
|
||||||
|
} else {
|
||||||
|
startLine = numLines - searchPoint.x();
|
||||||
|
}
|
||||||
|
|
||||||
if (!newBaseDate.isValid()) {
|
if (startLine == 0 && loadHistory(phrase, parameter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchAfterLoadHistory = true;
|
const bool isSearch = searchInText(phrase, parameter, SearchDirection::Up);
|
||||||
loadHistoryByDateRange(newBaseDate);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSearch = searchInText(phrase, true);
|
|
||||||
|
|
||||||
if (!isSearch) {
|
if (!isSearch) {
|
||||||
QString pk = f->getPublicKey().toString();
|
const QString pk = f->getPublicKey().toString();
|
||||||
QDateTime newBaseDate = history->getDateWhereFindPhrase(pk, earliestMessage, phrase);
|
const QDateTime newBaseDate = history->getDateWhereFindPhrase(pk, earliestMessage, phrase, parameter);
|
||||||
|
|
||||||
if (!newBaseDate.isValid()) {
|
if (!newBaseDate.isValid()) {
|
||||||
|
emit messageNotFoundShow(SearchDirection::Up);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,9 +572,11 @@ void ChatForm::onSearchUp(const QString& phrase)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::onSearchDown(const QString& phrase)
|
void ChatForm::onSearchDown(const QString& phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
searchInText(phrase, false);
|
if (!searchInText(phrase, parameter, SearchDirection::Down)) {
|
||||||
|
emit messageNotFoundShow(SearchDirection::Down);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::onFileSendFailed(uint32_t friendId, const QString& fname)
|
void ChatForm::onFileSendFailed(uint32_t friendId, const QString& fname)
|
||||||
@ -728,10 +759,10 @@ QString getMsgAuthorDispName(const ToxPk& authorPk, const QString& dispName)
|
|||||||
|
|
||||||
void ChatForm::loadHistoryDefaultNum(bool processUndelivered)
|
void ChatForm::loadHistoryDefaultNum(bool processUndelivered)
|
||||||
{
|
{
|
||||||
QString pk = f->getPublicKey().toString();
|
const QString pk = f->getPublicKey().toString();
|
||||||
QList<History::HistMessage> msgs = history->getChatHistoryDefaultNum(pk);
|
QList<History::HistMessage> msgs = history->getChatHistoryDefaultNum(pk);
|
||||||
if (!msgs.isEmpty()) {
|
if (!msgs.isEmpty()) {
|
||||||
earliestMessage = msgs.back().timestamp;
|
earliestMessage = msgs.first().timestamp;
|
||||||
}
|
}
|
||||||
handleLoadedMessages(msgs, processUndelivered);
|
handleLoadedMessages(msgs, processUndelivered);
|
||||||
}
|
}
|
||||||
@ -1054,6 +1085,21 @@ void ChatForm::SendMessageStr(QString msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChatForm::loadHistory(const QString& phrase, const ParameterSearch& parameter)
|
||||||
|
{
|
||||||
|
const QString pk = f->getPublicKey().toString();
|
||||||
|
const QDateTime newBaseDate = history->getDateWhereFindPhrase(pk, earliestMessage, phrase, parameter);
|
||||||
|
|
||||||
|
if (newBaseDate.isValid() && getFirstDate().isValid() && newBaseDate.date() < getFirstDate()) {
|
||||||
|
searchAfterLoadHistory = true;
|
||||||
|
loadHistoryByDateRange(newBaseDate);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void ChatForm::retranslateUi()
|
void ChatForm::retranslateUi()
|
||||||
{
|
{
|
||||||
loadHistoryAction->setText(tr("Load chat history..."));
|
loadHistoryAction->setText(tr("Load chat history..."));
|
||||||
|
@ -77,8 +77,9 @@ public slots:
|
|||||||
void onFileNameChanged(const ToxPk& friendPk);
|
void onFileNameChanged(const ToxPk& friendPk);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void onSearchUp(const QString& phrase) override;
|
void searchInBegin(const QString& phrase, const ParameterSearch& parameter) override;
|
||||||
void onSearchDown(const QString& phrase) override;
|
void onSearchUp(const QString& phrase, const ParameterSearch& parameter) override;
|
||||||
|
void onSearchDown(const QString& phrase, const ParameterSearch& parameter) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void clearChatArea(bool notInForm) override final;
|
void clearChatArea(bool notInForm) override final;
|
||||||
@ -143,6 +144,7 @@ private:
|
|||||||
void stopCounter(bool error = false);
|
void stopCounter(bool error = false);
|
||||||
void updateCallButtons();
|
void updateCallButtons();
|
||||||
void SendMessageStr(QString msg);
|
void SendMessageStr(QString msg);
|
||||||
|
bool loadHistory(const QString& phrase, const ParameterSearch& parameter);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GenericNetCamView* createNetcam() final override;
|
GenericNetCamView* createNetcam() final override;
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QStringBuilder>
|
#include <QStringBuilder>
|
||||||
|
|
||||||
#ifdef SPELL_CHECKING
|
#ifdef SPELL_CHECKING
|
||||||
@ -233,6 +234,7 @@ GenericChatForm::GenericChatForm(const Contact* contact, QWidget* parent)
|
|||||||
connect(searchForm, &SearchForm::searchUp, this, &GenericChatForm::onSearchUp);
|
connect(searchForm, &SearchForm::searchUp, this, &GenericChatForm::onSearchUp);
|
||||||
connect(searchForm, &SearchForm::searchDown, this, &GenericChatForm::onSearchDown);
|
connect(searchForm, &SearchForm::searchDown, this, &GenericChatForm::onSearchDown);
|
||||||
connect(searchForm, &SearchForm::visibleChanged, this, &GenericChatForm::onSearchTriggered);
|
connect(searchForm, &SearchForm::visibleChanged, this, &GenericChatForm::onSearchTriggered);
|
||||||
|
connect(this, &GenericChatForm::messageNotFoundShow, searchForm, &SearchForm::showMessageNotFound);
|
||||||
|
|
||||||
connect(chatWidget, &ChatLog::workerTimeoutFinished, this, &GenericChatForm::onContinueSearch);
|
connect(chatWidget, &ChatLog::workerTimeoutFinished, this, &GenericChatForm::onContinueSearch);
|
||||||
|
|
||||||
@ -283,18 +285,12 @@ void GenericChatForm::hideFileMenu()
|
|||||||
|
|
||||||
QDate GenericChatForm::getLatestDate() const
|
QDate GenericChatForm::getLatestDate() const
|
||||||
{
|
{
|
||||||
ChatLine::Ptr chatLine = chatWidget->getLatestLine();
|
return getDate(chatWidget->getLatestLine());
|
||||||
|
}
|
||||||
|
|
||||||
if (chatLine) {
|
QDate GenericChatForm::getFirstDate() const
|
||||||
Timestamp* timestamp = qobject_cast<Timestamp*>(chatLine->getContent(2));
|
{
|
||||||
|
return getDate(chatWidget->getFirstLine());
|
||||||
if (timestamp)
|
|
||||||
return timestamp->getTime().date();
|
|
||||||
else
|
|
||||||
return QDate::currentDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
return QDate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::setName(const QString& newName)
|
void GenericChatForm::setName(const QString& newName)
|
||||||
@ -551,6 +547,21 @@ void GenericChatForm::addSystemDateMessage()
|
|||||||
insertChatMessage(ChatMessage::createChatInfoMessage(dateText, ChatMessage::INFO, QDateTime()));
|
insertChatMessage(ChatMessage::createChatInfoMessage(dateText, ChatMessage::INFO, QDateTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDate GenericChatForm::getDate(const ChatLine::Ptr &chatLine) const
|
||||||
|
{
|
||||||
|
if (chatLine) {
|
||||||
|
Timestamp* const timestamp = qobject_cast<Timestamp*>(chatLine->getContent(2));
|
||||||
|
|
||||||
|
if (timestamp) {
|
||||||
|
return timestamp->getTime().date();
|
||||||
|
} else {
|
||||||
|
return QDate::currentDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QDate();
|
||||||
|
}
|
||||||
|
|
||||||
void GenericChatForm::disableSearchText()
|
void GenericChatForm::disableSearchText()
|
||||||
{
|
{
|
||||||
if (searchPoint != QPoint(1, -1)) {
|
if (searchPoint != QPoint(1, -1)) {
|
||||||
@ -568,7 +579,7 @@ void GenericChatForm::disableSearchText()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
|
bool GenericChatForm::searchInText(const QString& phrase, const ParameterSearch& parameter, SearchDirection direction)
|
||||||
{
|
{
|
||||||
bool isSearch = false;
|
bool isSearch = false;
|
||||||
|
|
||||||
@ -576,19 +587,59 @@ bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
|
|||||||
disableSearchText();
|
disableSearchText();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
|
auto lines = chatWidget->getLines();
|
||||||
|
|
||||||
if (lines.isEmpty()) {
|
if (lines.isEmpty()) {
|
||||||
return isSearch;
|
return isSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
int numLines = lines.size();
|
int numLines = lines.size();
|
||||||
int startLine = numLines - searchPoint.x();
|
|
||||||
|
int startLine = -1;
|
||||||
|
|
||||||
|
if (parameter.period == PeriodSearch::WithTheEnd || parameter.period == PeriodSearch::None) {
|
||||||
|
startLine = numLines - searchPoint.x();
|
||||||
|
} else if (parameter.period == PeriodSearch::WithTheFirst) {
|
||||||
|
startLine = 0;
|
||||||
|
} else if (parameter.period == PeriodSearch::AfterDate) {
|
||||||
|
const auto lambda = [=](const ChatLine::Ptr& item) {
|
||||||
|
const auto d = getDate(item);
|
||||||
|
return d.isValid() && parameter.date <= d;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto find = std::find_if(lines.begin(), lines.end(), lambda);
|
||||||
|
|
||||||
|
if (find != lines.end()) {
|
||||||
|
startLine = static_cast<int>(std::distance(lines.begin(), find));
|
||||||
|
}
|
||||||
|
} else if (parameter.period == PeriodSearch::BeforeDate) {
|
||||||
|
#if QT_VERSION > QT_VERSION_CHECK(5, 6, 0)
|
||||||
|
const auto lambda = [=](const ChatLine::Ptr& item) {
|
||||||
|
const auto d = getDate(item);
|
||||||
|
return d.isValid() && parameter.date >= d;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto find = std::find_if(lines.rbegin(), lines.rend(), lambda);
|
||||||
|
|
||||||
|
if (find != lines.rend()) {
|
||||||
|
startLine = static_cast<int>(std::distance(find, lines.rend())) - 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (int i = lines.size() - 1; i >= 0; --i) {
|
||||||
|
auto d = getDate(lines[i]);
|
||||||
|
if (d.isValid() && parameter.date >= d) {
|
||||||
|
startLine = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (startLine < 0 || startLine >= numLines) {
|
if (startLine < 0 || startLine >= numLines) {
|
||||||
return isSearch;
|
return isSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool searchUp = (direction == SearchDirection::Up);
|
||||||
for (int i = startLine; searchUp ? i >= 0 : i < numLines; searchUp ? --i : ++i) {
|
for (int i = startLine; searchUp ? i >= 0 : i < numLines; searchUp ? --i : ++i) {
|
||||||
ChatLine::Ptr l = lines[i];
|
ChatLine::Ptr l = lines[i];
|
||||||
|
|
||||||
@ -608,19 +659,56 @@ bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
|
|||||||
|
|
||||||
QString txt = content->getText();
|
QString txt = content->getText();
|
||||||
|
|
||||||
if (!txt.contains(phrase, Qt::CaseInsensitive)) {
|
bool find = false;
|
||||||
|
QRegularExpression exp;
|
||||||
|
QRegularExpressionMatch match;
|
||||||
|
|
||||||
|
auto flagIns = QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption;
|
||||||
|
auto flag = QRegularExpression::UseUnicodePropertiesOption;
|
||||||
|
switch (parameter.filter) {
|
||||||
|
case FilterSearch::Register:
|
||||||
|
find = txt.contains(phrase, Qt::CaseSensitive);
|
||||||
|
break;
|
||||||
|
case FilterSearch::WordsOnly:
|
||||||
|
exp = QRegularExpression(SearchExtraFunctions::generateFilterWordsOnly(phrase), flagIns);
|
||||||
|
find = txt.contains(exp);
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndWordsOnly:
|
||||||
|
exp = QRegularExpression(SearchExtraFunctions::generateFilterWordsOnly(phrase), flag);
|
||||||
|
find = txt.contains(exp);
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndRegular:
|
||||||
|
exp = QRegularExpression(phrase, flag);
|
||||||
|
find = txt.contains(exp);
|
||||||
|
break;
|
||||||
|
case FilterSearch::Regular:
|
||||||
|
exp = QRegularExpression(phrase, flagIns);
|
||||||
|
find = txt.contains(exp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
find = txt.contains(phrase, Qt::CaseInsensitive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!find) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = indexForSearchInLine(txt, phrase, searchUp);
|
auto point = indexForSearchInLine(txt, phrase, parameter, direction);
|
||||||
if ((index == -1 && searchPoint.y() > -1)) {
|
if ((point.first == -1 && searchPoint.y() > -1)) {
|
||||||
text->deselectText();
|
text->deselectText();
|
||||||
searchPoint.setY(-1);
|
searchPoint.setY(-1);
|
||||||
} else {
|
} else {
|
||||||
chatWidget->scrollToLine(l);
|
chatWidget->scrollToLine(l);
|
||||||
text->deselectText();
|
text->deselectText();
|
||||||
text->selectText(phrase, index);
|
|
||||||
searchPoint = QPoint(numLines - i, index);
|
if (exp.pattern().isEmpty()) {
|
||||||
|
text->selectText(phrase, point);
|
||||||
|
} else {
|
||||||
|
text->selectText(exp, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPoint = QPoint(numLines - i, point.first);
|
||||||
isSearch = true;
|
isSearch = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -630,27 +718,100 @@ bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
|
|||||||
return isSearch;
|
return isSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GenericChatForm::indexForSearchInLine(const QString& txt, const QString& phrase, bool searchUp)
|
std::pair<int, int> GenericChatForm::indexForSearchInLine(const QString& txt, const QString& phrase, const ParameterSearch& parameter, SearchDirection direction)
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = -1;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
if (searchUp) {
|
QRegularExpression exp;
|
||||||
|
auto flagIns = QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption;
|
||||||
|
auto flag = QRegularExpression::UseUnicodePropertiesOption;
|
||||||
|
if (direction == SearchDirection::Up) {
|
||||||
int startIndex = -1;
|
int startIndex = -1;
|
||||||
if (searchPoint.y() > -1) {
|
if (searchPoint.y() > -1) {
|
||||||
startIndex = searchPoint.y() - 1;
|
startIndex = searchPoint.y() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (parameter.filter) {
|
||||||
|
case FilterSearch::Register:
|
||||||
|
index = txt.lastIndexOf(phrase, startIndex, Qt::CaseSensitive);
|
||||||
|
break;
|
||||||
|
case FilterSearch::WordsOnly:
|
||||||
|
exp = QRegularExpression(SearchExtraFunctions::generateFilterWordsOnly(phrase), flagIns);
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndWordsOnly:
|
||||||
|
exp = QRegularExpression(SearchExtraFunctions::generateFilterWordsOnly(phrase), flag);
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndRegular:
|
||||||
|
exp = QRegularExpression(phrase, flag);
|
||||||
|
break;
|
||||||
|
case FilterSearch::Regular:
|
||||||
|
exp = QRegularExpression(phrase, flagIns);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
index = txt.lastIndexOf(phrase, startIndex, Qt::CaseInsensitive);
|
index = txt.lastIndexOf(phrase, startIndex, Qt::CaseInsensitive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exp.pattern().isEmpty()) {
|
||||||
|
auto matchIt = exp.globalMatch(txt);
|
||||||
|
|
||||||
|
while (matchIt.hasNext()) {
|
||||||
|
const auto match = matchIt.next();
|
||||||
|
|
||||||
|
int sizeItem = match.capturedLength();
|
||||||
|
int indexItem = match.capturedStart();
|
||||||
|
|
||||||
|
if (startIndex == -1 || indexItem < startIndex) {
|
||||||
|
index = indexItem;
|
||||||
|
size = sizeItem;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size = phrase.size();
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int startIndex = 0;
|
int startIndex = 0;
|
||||||
if (searchPoint.y() > -1) {
|
if (searchPoint.y() > -1) {
|
||||||
startIndex = searchPoint.y() + 1;
|
startIndex = searchPoint.y() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (parameter.filter) {
|
||||||
|
case FilterSearch::Register:
|
||||||
|
index = txt.indexOf(phrase, startIndex, Qt::CaseSensitive);
|
||||||
|
break;
|
||||||
|
case FilterSearch::WordsOnly:
|
||||||
|
exp = QRegularExpression(SearchExtraFunctions::generateFilterWordsOnly(phrase), flagIns);
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndWordsOnly:
|
||||||
|
exp = QRegularExpression(SearchExtraFunctions::generateFilterWordsOnly(phrase), flag);
|
||||||
|
break;
|
||||||
|
case FilterSearch::RegisterAndRegular:
|
||||||
|
exp = QRegularExpression(phrase, flag);
|
||||||
|
break;
|
||||||
|
case FilterSearch::Regular:
|
||||||
|
exp = QRegularExpression(phrase, flagIns);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
index = txt.indexOf(phrase, startIndex, Qt::CaseInsensitive);
|
index = txt.indexOf(phrase, startIndex, Qt::CaseInsensitive);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
if (!exp.pattern().isEmpty()) {
|
||||||
|
const auto match = exp.match(txt, startIndex);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
size = match.capturedLength(0);
|
||||||
|
index = match.capturedEnd() - size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size = phrase.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(index, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::clearChatArea()
|
void GenericChatForm::clearChatArea()
|
||||||
@ -815,20 +976,17 @@ void GenericChatForm::onSearchTriggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericChatForm::searchInBegin(const QString& phrase)
|
|
||||||
{
|
|
||||||
disableSearchText();
|
|
||||||
|
|
||||||
searchPoint = QPoint(1, -1);
|
|
||||||
onSearchUp(phrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenericChatForm::onContinueSearch()
|
void GenericChatForm::onContinueSearch()
|
||||||
{
|
{
|
||||||
QString phrase = searchForm->getSearchPhrase();
|
const QString phrase = searchForm->getSearchPhrase();
|
||||||
|
const ParameterSearch parameter = searchForm->getParameterSearch();
|
||||||
if (!phrase.isEmpty() && searchAfterLoadHistory) {
|
if (!phrase.isEmpty() && searchAfterLoadHistory) {
|
||||||
|
if (parameter.period == PeriodSearch::WithTheFirst || parameter.period == PeriodSearch::AfterDate) {
|
||||||
searchAfterLoadHistory = false;
|
searchAfterLoadHistory = false;
|
||||||
onSearchUp(phrase);
|
onSearchDown(phrase, parameter);
|
||||||
|
} else {
|
||||||
|
onSearchUp(phrase, parameter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "src/chatlog/chatmessage.h"
|
#include "src/chatlog/chatmessage.h"
|
||||||
#include "src/core/toxpk.h"
|
#include "src/core/toxpk.h"
|
||||||
|
#include "src/widget/searchtypes.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@ -81,12 +82,14 @@ public:
|
|||||||
void addAlertMessage(const ToxPk& author, const QString& message, const QDateTime& datetime);
|
void addAlertMessage(const ToxPk& author, const QString& message, const QDateTime& datetime);
|
||||||
static QString resolveToxPk(const ToxPk& pk);
|
static QString resolveToxPk(const ToxPk& pk);
|
||||||
QDate getLatestDate() const;
|
QDate getLatestDate() const;
|
||||||
|
QDate getFirstDate() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sendMessage(uint32_t, QString);
|
void sendMessage(uint32_t, QString);
|
||||||
void sendAction(uint32_t, QString);
|
void sendAction(uint32_t, QString);
|
||||||
void chatAreaCleared();
|
void chatAreaCleared();
|
||||||
void messageInserted();
|
void messageInserted();
|
||||||
|
void messageNotFoundShow(SearchDirection direction);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void focusInput();
|
void focusInput();
|
||||||
@ -113,14 +116,15 @@ protected slots:
|
|||||||
void searchFormShow();
|
void searchFormShow();
|
||||||
void onSearchTriggered();
|
void onSearchTriggered();
|
||||||
|
|
||||||
void searchInBegin(const QString& phrase);
|
virtual void searchInBegin(const QString& phrase, const ParameterSearch& parameter) = 0;
|
||||||
virtual void onSearchUp(const QString& phrase) = 0;
|
virtual void onSearchUp(const QString& phrase, const ParameterSearch& parameter) = 0;
|
||||||
virtual void onSearchDown(const QString& phrase) = 0;
|
virtual void onSearchDown(const QString& phrase, const ParameterSearch& parameter) = 0;
|
||||||
void onContinueSearch();
|
void onContinueSearch();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
void addSystemDateMessage();
|
void addSystemDateMessage();
|
||||||
|
QDate getDate(const ChatLine::Ptr& chatLine) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ChatMessage::Ptr createMessage(const ToxPk& author, const QString& message,
|
ChatMessage::Ptr createMessage(const ToxPk& author, const QString& message,
|
||||||
@ -139,8 +143,8 @@ protected:
|
|||||||
virtual void resizeEvent(QResizeEvent* event) final override;
|
virtual void resizeEvent(QResizeEvent* event) final override;
|
||||||
virtual bool eventFilter(QObject* object, QEvent* event) final override;
|
virtual bool eventFilter(QObject* object, QEvent* event) final override;
|
||||||
void disableSearchText();
|
void disableSearchText();
|
||||||
bool searchInText(const QString& phrase, bool searchUp);
|
bool searchInText(const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
||||||
int indexForSearchInLine(const QString& txt, const QString& phrase, bool searchUp);
|
std::pair<int, int> indexForSearchInLine(const QString& txt, const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool audioInputFlag;
|
bool audioInputFlag;
|
||||||
|
@ -199,14 +199,31 @@ void GroupChatForm::onTitleChanged(uint32_t groupId, const QString& author, cons
|
|||||||
addSystemInfoMessage(message, ChatMessage::INFO, curTime);
|
addSystemInfoMessage(message, ChatMessage::INFO, curTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupChatForm::onSearchUp(const QString& phrase)
|
void GroupChatForm::searchInBegin(const QString& phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
searchInText(phrase, true);
|
disableSearchText();
|
||||||
|
|
||||||
|
searchPoint = QPoint(1, -1);
|
||||||
|
|
||||||
|
if (parameter.period == PeriodSearch::WithTheFirst || parameter.period == PeriodSearch::AfterDate) {
|
||||||
|
onSearchDown(phrase, parameter);
|
||||||
|
} else {
|
||||||
|
onSearchUp(phrase, parameter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupChatForm::onSearchDown(const QString& phrase)
|
void GroupChatForm::onSearchUp(const QString& phrase, const ParameterSearch& parameter)
|
||||||
{
|
{
|
||||||
searchInText(phrase, false);
|
if (!searchInText(phrase, parameter, SearchDirection::Up)) {
|
||||||
|
emit messageNotFoundShow(SearchDirection::Up);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupChatForm::onSearchDown(const QString& phrase, const ParameterSearch& parameter)
|
||||||
|
{
|
||||||
|
if (!searchInText(phrase, parameter, SearchDirection::Down)) {
|
||||||
|
emit messageNotFoundShow(SearchDirection::Down);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupChatForm::onScreenshotClicked()
|
void GroupChatForm::onScreenshotClicked()
|
||||||
|
@ -50,8 +50,9 @@ private slots:
|
|||||||
void onCallClicked();
|
void onCallClicked();
|
||||||
void onUserListChanged();
|
void onUserListChanged();
|
||||||
void onTitleChanged(uint32_t groupId, const QString& author, const QString& title);
|
void onTitleChanged(uint32_t groupId, const QString& author, const QString& title);
|
||||||
void onSearchUp(const QString& phrase) override;
|
void searchInBegin(const QString& phrase, const ParameterSearch& parameter) override;
|
||||||
void onSearchDown(const QString& phrase) override;
|
void onSearchUp(const QString& phrase, const ParameterSearch& parameter) override;
|
||||||
|
void onSearchDown(const QString& phrase, const ParameterSearch& parameter) override;
|
||||||
void onLabelContextMenuRequested(const QPoint& localPos);
|
void onLabelContextMenuRequested(const QPoint& localPos);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -37,6 +37,13 @@ LoadHistoryDialog::LoadHistoryDialog(const ToxPk& friendPk, QWidget* parent)
|
|||||||
&LoadHistoryDialog::highlightDates);
|
&LoadHistoryDialog::highlightDates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadHistoryDialog::LoadHistoryDialog(QWidget* parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
, ui(new Ui::LoadHistoryDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
LoadHistoryDialog::~LoadHistoryDialog()
|
LoadHistoryDialog::~LoadHistoryDialog()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
@ -54,6 +61,16 @@ QDateTime LoadHistoryDialog::getFromDate()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoadHistoryDialog::setTitle(const QString& title)
|
||||||
|
{
|
||||||
|
setWindowTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadHistoryDialog::setInfoLabel(const QString& info)
|
||||||
|
{
|
||||||
|
ui->fromLabel->setText(info);
|
||||||
|
}
|
||||||
|
|
||||||
void LoadHistoryDialog::highlightDates(int year, int month)
|
void LoadHistoryDialog::highlightDates(int year, int month)
|
||||||
{
|
{
|
||||||
History* history = Nexus::getProfile()->getHistory();
|
History* history = Nexus::getProfile()->getHistory();
|
||||||
|
@ -34,9 +34,12 @@ class LoadHistoryDialog : public QDialog
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LoadHistoryDialog(const ToxPk& friendPk, QWidget* parent = 0);
|
explicit LoadHistoryDialog(const ToxPk& friendPk, QWidget* parent = 0);
|
||||||
|
explicit LoadHistoryDialog(QWidget* parent = 0);
|
||||||
~LoadHistoryDialog();
|
~LoadHistoryDialog();
|
||||||
|
|
||||||
QDateTime getFromDate();
|
QDateTime getFromDate();
|
||||||
|
void setTitle(const QString& title);
|
||||||
|
void setInfoLabel(const QString& info);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void highlightDates(int year, int month);
|
void highlightDates(int year, int month);
|
||||||
|
149
src/widget/form/searchsettingsform.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include "searchsettingsform.h"
|
||||||
|
#include "ui_searchsettingsform.h"
|
||||||
|
#include "src/persistence/settings.h"
|
||||||
|
#include "src/widget/style.h"
|
||||||
|
#include "src/widget/form/loadhistorydialog.h"
|
||||||
|
|
||||||
|
SearchSettingsForm::SearchSettingsForm(QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
ui(new Ui::SearchSettingsForm)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->choiceDateButton->setEnabled(false);
|
||||||
|
ui->startDateLabel->setEnabled(false);
|
||||||
|
|
||||||
|
ui->choiceDateButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||||
|
ui->choiceDateButton->setObjectName(QStringLiteral("choiceDateButton"));
|
||||||
|
ui->choiceDateButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
|
||||||
|
|
||||||
|
ui->startDateLabel->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/labels.css")));
|
||||||
|
|
||||||
|
connect(ui->startSearchComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
||||||
|
this, &SearchSettingsForm::onStartSearchSelected);
|
||||||
|
connect(ui->registerCheckBox, &QCheckBox::clicked, this, &SearchSettingsForm::onRegisterClicked);
|
||||||
|
connect(ui->wordsOnlyRadioButton, &QCheckBox::clicked, this, &SearchSettingsForm::onWordsOnlyClicked);
|
||||||
|
connect(ui->regularRadioButton, &QCheckBox::clicked, this, &SearchSettingsForm::onRegularClicked);
|
||||||
|
connect(ui->choiceDateButton, &QPushButton::clicked, this, &SearchSettingsForm::onChoiceDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchSettingsForm::~SearchSettingsForm()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterSearch SearchSettingsForm::getParameterSearch()
|
||||||
|
{
|
||||||
|
ParameterSearch ps;
|
||||||
|
|
||||||
|
if (ui->regularRadioButton->isChecked()) {
|
||||||
|
ps.filter = FilterSearch::Regular;
|
||||||
|
} else if (ui->registerCheckBox->isChecked() && ui->wordsOnlyRadioButton->isChecked()) {
|
||||||
|
ps.filter = FilterSearch::RegisterAndWordsOnly;
|
||||||
|
} else if (ui->registerCheckBox->isChecked() && ui->regularRadioButton->isChecked()) {
|
||||||
|
ps.filter = FilterSearch::RegisterAndRegular;
|
||||||
|
} else if (ui->registerCheckBox->isChecked()) {
|
||||||
|
ps.filter = FilterSearch::Register;
|
||||||
|
} else if (ui->wordsOnlyRadioButton->isChecked()) {
|
||||||
|
ps.filter = FilterSearch::WordsOnly;
|
||||||
|
} else {
|
||||||
|
ps.filter = FilterSearch::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ui->startSearchComboBox->currentIndex()) {
|
||||||
|
case 0:
|
||||||
|
ps.period = PeriodSearch::WithTheEnd;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ps.period = PeriodSearch::WithTheFirst;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ps.period = PeriodSearch::AfterDate;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ps.period = PeriodSearch::BeforeDate;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ps.period = PeriodSearch::WithTheEnd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.date = startDate;
|
||||||
|
ps.isUpdate = isUpdate;
|
||||||
|
isUpdate = false;
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSettingsForm::updateStartDateLabel()
|
||||||
|
{
|
||||||
|
ui->startDateLabel->setText(startDate.toString(Settings::getInstance().getDateFormat()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSettingsForm::setUpdate(const bool isUpdate)
|
||||||
|
{
|
||||||
|
this->isUpdate = isUpdate;
|
||||||
|
emit updateSettings(isUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSettingsForm::onStartSearchSelected(const int index)
|
||||||
|
{
|
||||||
|
if (index > 1) {
|
||||||
|
ui->choiceDateButton->setEnabled(true);
|
||||||
|
ui->startDateLabel->setEnabled(true);
|
||||||
|
|
||||||
|
ui->choiceDateButton->setProperty("state", QStringLiteral("green"));
|
||||||
|
ui->choiceDateButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
|
||||||
|
|
||||||
|
if (startDate.isNull()) {
|
||||||
|
startDate = QDate::currentDate();
|
||||||
|
updateStartDateLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ui->choiceDateButton->setEnabled(false);
|
||||||
|
ui->startDateLabel->setEnabled(false);
|
||||||
|
|
||||||
|
ui->choiceDateButton->setProperty("state", QString());
|
||||||
|
ui->choiceDateButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpdate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSettingsForm::onRegisterClicked(const bool checked)
|
||||||
|
{
|
||||||
|
Q_UNUSED(checked)
|
||||||
|
setUpdate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSettingsForm::onWordsOnlyClicked(const bool checked)
|
||||||
|
{
|
||||||
|
if (checked) {
|
||||||
|
ui->regularRadioButton->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpdate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSettingsForm::onRegularClicked(const bool checked)
|
||||||
|
{
|
||||||
|
if (checked) {
|
||||||
|
ui->wordsOnlyRadioButton->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpdate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchSettingsForm::onChoiceDate()
|
||||||
|
{
|
||||||
|
LoadHistoryDialog dlg;
|
||||||
|
dlg.setTitle(tr("Select Date Dialog"));
|
||||||
|
dlg.setInfoLabel(tr("Select a date"));
|
||||||
|
if (dlg.exec()) {
|
||||||
|
startDate = dlg.getFromDate().date();
|
||||||
|
updateStartDateLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
setUpdate(true);
|
||||||
|
}
|
40
src/widget/form/searchsettingsform.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef SEARCHSETTINGSFORM_H
|
||||||
|
#define SEARCHSETTINGSFORM_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include "src/widget/searchtypes.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class SearchSettingsForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchSettingsForm : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SearchSettingsForm(QWidget *parent = nullptr);
|
||||||
|
~SearchSettingsForm();
|
||||||
|
|
||||||
|
ParameterSearch getParameterSearch();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::SearchSettingsForm *ui;
|
||||||
|
QDate startDate;
|
||||||
|
bool isUpdate{false};
|
||||||
|
|
||||||
|
void updateStartDateLabel();
|
||||||
|
void setUpdate(const bool isUpdate);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onStartSearchSelected(const int index);
|
||||||
|
void onRegisterClicked(const bool checked);
|
||||||
|
void onWordsOnlyClicked(const bool checked);
|
||||||
|
void onRegularClicked(const bool checked);
|
||||||
|
void onChoiceDate();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void updateSettings(const bool isUpdate);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCHSETTINGSFORM_H
|
173
src/widget/form/searchsettingsform.ui
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>SearchSettingsForm</class>
|
||||||
|
<widget class="QWidget" name="SearchSettingsForm">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>473</width>
|
||||||
|
<height>84</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start search:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="startSearchComboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>from the end</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>from the beginning</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>after date</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>before date</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="startDateLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>00.00.0000</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="choiceDateButton">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="registerCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Case sensitive</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="wordsOnlyRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Whole words only</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoRepeat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoExclusive">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="regularRadioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use regular expressions</string>
|
||||||
|
</property>
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoRepeat">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoExclusive">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Plain</enum>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -18,25 +18,64 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "searchform.h"
|
#include "searchform.h"
|
||||||
|
#include "form/searchsettingsform.h"
|
||||||
#include "src/widget/style.h"
|
#include "src/widget/style.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QLabel>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
static std::array<QString, 3> STATE_NAME = {
|
||||||
|
QString{},
|
||||||
|
QStringLiteral("green"),
|
||||||
|
QStringLiteral("red"),
|
||||||
|
};
|
||||||
|
|
||||||
SearchForm::SearchForm(QWidget* parent) : QWidget(parent)
|
SearchForm::SearchForm(QWidget* parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
QHBoxLayout *layout = new QHBoxLayout();
|
QVBoxLayout* layout = new QVBoxLayout();
|
||||||
|
QHBoxLayout* layoutNavigation = new QHBoxLayout();
|
||||||
|
QHBoxLayout* layoutMessage = new QHBoxLayout();
|
||||||
|
QSpacerItem *lSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Ignored);
|
||||||
|
QSpacerItem *rSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Ignored);
|
||||||
searchLine = new LineEdit();
|
searchLine = new LineEdit();
|
||||||
|
settings = new SearchSettingsForm();
|
||||||
|
messageLabel = new QLabel();
|
||||||
|
|
||||||
|
settings->setVisible(false);
|
||||||
|
messageLabel->setProperty("state", QStringLiteral("red"));
|
||||||
|
messageLabel->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/labels.css")));
|
||||||
|
messageLabel->setText(tr("The text could not be found."));
|
||||||
|
messageLabel->setVisible(false);
|
||||||
|
|
||||||
|
settingsButton = createButton("searchSettingsButton", "green");
|
||||||
upButton = createButton("searchUpButton", "green");
|
upButton = createButton("searchUpButton", "green");
|
||||||
downButton = createButton("searchDownButton", "green");
|
downButton = createButton("searchDownButton", "green");
|
||||||
hideButton = createButton("searchHideButton", "red");
|
hideButton = createButton("searchHideButton", "red");
|
||||||
|
startButton = createButton("startButton", "green");
|
||||||
|
startButton->setText(tr("Start"));
|
||||||
|
|
||||||
layout->setMargin(0);
|
layoutNavigation->setMargin(0);
|
||||||
layout->addWidget(searchLine);
|
layoutNavigation->addWidget(settingsButton);
|
||||||
layout->addWidget(upButton);
|
layoutNavigation->addWidget(searchLine);
|
||||||
layout->addWidget(downButton);
|
layoutNavigation->addWidget(startButton);
|
||||||
layout->addWidget(hideButton);
|
layoutNavigation->addWidget(upButton);
|
||||||
|
layoutNavigation->addWidget(downButton);
|
||||||
|
layoutNavigation->addWidget(hideButton);
|
||||||
|
|
||||||
|
layout->addLayout(layoutNavigation);
|
||||||
|
layout->addWidget(settings);
|
||||||
|
|
||||||
|
layoutMessage->addSpacerItem(lSpacer);
|
||||||
|
layoutMessage->addWidget(messageLabel);
|
||||||
|
layoutMessage->addSpacerItem(rSpacer);
|
||||||
|
layout->addLayout(layoutMessage);
|
||||||
|
|
||||||
|
startButton->setHidden(true);
|
||||||
|
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
@ -48,6 +87,10 @@ SearchForm::SearchForm(QWidget* parent) : QWidget(parent)
|
|||||||
connect(upButton, &QPushButton::clicked, this, &SearchForm::clickedUp);
|
connect(upButton, &QPushButton::clicked, this, &SearchForm::clickedUp);
|
||||||
connect(downButton, &QPushButton::clicked, this, &SearchForm::clickedDown);
|
connect(downButton, &QPushButton::clicked, this, &SearchForm::clickedDown);
|
||||||
connect(hideButton, &QPushButton::clicked, this, &SearchForm::clickedHide);
|
connect(hideButton, &QPushButton::clicked, this, &SearchForm::clickedHide);
|
||||||
|
connect(startButton, &QPushButton::clicked, this, &SearchForm::clickedStart);
|
||||||
|
connect(settingsButton, &QPushButton::clicked, this, &SearchForm::clickedSearch);
|
||||||
|
|
||||||
|
connect(settings, &SearchSettingsForm::updateSettings, this, &SearchForm::changedState);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchForm::removeSearchPhrase()
|
void SearchForm::removeSearchPhrase()
|
||||||
@ -60,6 +103,11 @@ QString SearchForm::getSearchPhrase() const
|
|||||||
return searchPhrase;
|
return searchPhrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParameterSearch SearchForm::getParameterSearch()
|
||||||
|
{
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
|
||||||
void SearchForm::setFocusEditor()
|
void SearchForm::setFocusEditor()
|
||||||
{
|
{
|
||||||
searchLine->setFocus();
|
searchLine->setFocus();
|
||||||
@ -87,20 +135,99 @@ QPushButton *SearchForm::createButton(const QString& name, const QString& state)
|
|||||||
return btn;
|
return btn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParameterSearch SearchForm::getAndCheckParametrSearch()
|
||||||
|
{
|
||||||
|
if (isActiveSettings) {
|
||||||
|
auto sendParam = settings->getParameterSearch();
|
||||||
|
if (!isChangedPhrase && !sendParam.isUpdate) {
|
||||||
|
sendParam.period = PeriodSearch::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
isChangedPhrase = false;
|
||||||
|
parameter = sendParam;
|
||||||
|
|
||||||
|
return sendParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParameterSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchForm::setStateName(QPushButton *btn, ToolButtonState state)
|
||||||
|
{
|
||||||
|
const auto index = static_cast<unsigned long>(state);
|
||||||
|
btn->setProperty("state", STATE_NAME[index]);
|
||||||
|
btn->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/chatForm/buttons.css")));
|
||||||
|
btn->setEnabled(index != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchForm::useBeginState()
|
||||||
|
{
|
||||||
|
setStateName(upButton, ToolButtonState::Common);
|
||||||
|
setStateName(downButton, ToolButtonState::Common);
|
||||||
|
messageLabel->setVisible(false);
|
||||||
|
isPrevSearch = false;
|
||||||
|
}
|
||||||
|
|
||||||
void SearchForm::changedSearchPhrase(const QString& text)
|
void SearchForm::changedSearchPhrase(const QString& text)
|
||||||
{
|
{
|
||||||
|
useBeginState();
|
||||||
|
|
||||||
|
if (searchPhrase == text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString l = text.right(1);
|
||||||
|
if (!l.isEmpty() && l != " " && l[0].isSpace()) {
|
||||||
|
searchLine->setText(searchPhrase);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
searchPhrase = text;
|
searchPhrase = text;
|
||||||
emit searchInBegin(searchPhrase);
|
isChangedPhrase = true;
|
||||||
|
if (isActiveSettings) {
|
||||||
|
if (startButton->isHidden()) {
|
||||||
|
changedState(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isSearchInBegin = true;
|
||||||
|
emit searchInBegin(searchPhrase, getAndCheckParametrSearch());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchForm::clickedUp()
|
void SearchForm::clickedUp()
|
||||||
{
|
{
|
||||||
emit searchUp(searchPhrase);
|
if (downButton->isEnabled()) {
|
||||||
|
isPrevSearch = false;
|
||||||
|
} else {
|
||||||
|
isPrevSearch = true;
|
||||||
|
setStateName(downButton, ToolButtonState::Common);
|
||||||
|
messageLabel->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startButton->isHidden()) {
|
||||||
|
isSearchInBegin = false;
|
||||||
|
emit searchUp(searchPhrase, getAndCheckParametrSearch());
|
||||||
|
} else {
|
||||||
|
clickedStart();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchForm::clickedDown()
|
void SearchForm::clickedDown()
|
||||||
{
|
{
|
||||||
emit searchDown(searchPhrase);
|
if (upButton->isEnabled()) {
|
||||||
|
isPrevSearch = false;
|
||||||
|
} else {
|
||||||
|
isPrevSearch = true;
|
||||||
|
setStateName(upButton, ToolButtonState::Common);
|
||||||
|
messageLabel->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startButton->isHidden()) {
|
||||||
|
isSearchInBegin = false;
|
||||||
|
emit searchDown(searchPhrase, getAndCheckParametrSearch());
|
||||||
|
} else {
|
||||||
|
clickedStart();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchForm::clickedHide()
|
void SearchForm::clickedHide()
|
||||||
@ -109,6 +236,64 @@ void SearchForm::clickedHide()
|
|||||||
emit visibleChanged();
|
emit visibleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SearchForm::clickedStart()
|
||||||
|
{
|
||||||
|
changedState(false);
|
||||||
|
isSearchInBegin = true;
|
||||||
|
emit searchInBegin(searchPhrase, getAndCheckParametrSearch());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchForm::clickedSearch()
|
||||||
|
{
|
||||||
|
isActiveSettings = !isActiveSettings;
|
||||||
|
settings->setVisible(isActiveSettings);
|
||||||
|
useBeginState();
|
||||||
|
|
||||||
|
if (isActiveSettings) {
|
||||||
|
setStateName(settingsButton, ToolButtonState::Active);
|
||||||
|
} else {
|
||||||
|
setStateName(settingsButton, ToolButtonState::Common);
|
||||||
|
changedState(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchForm::changedState(bool isUpdate)
|
||||||
|
{
|
||||||
|
if (isUpdate) {
|
||||||
|
startButton->setHidden(false);
|
||||||
|
upButton->setHidden(true);
|
||||||
|
downButton->setHidden(true);
|
||||||
|
} else {
|
||||||
|
startButton->setHidden(true);
|
||||||
|
upButton->setHidden(false);
|
||||||
|
downButton->setHidden(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
useBeginState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchForm::showMessageNotFound(SearchDirection direction)
|
||||||
|
{
|
||||||
|
if (isSearchInBegin) {
|
||||||
|
if (parameter.period == PeriodSearch::AfterDate) {
|
||||||
|
setStateName(downButton, ToolButtonState::Disabled);
|
||||||
|
} else if (parameter.period == PeriodSearch::BeforeDate) {
|
||||||
|
setStateName(upButton, ToolButtonState::Disabled);
|
||||||
|
} else {
|
||||||
|
setStateName(upButton, ToolButtonState::Disabled);
|
||||||
|
setStateName(downButton, ToolButtonState::Disabled);
|
||||||
|
}
|
||||||
|
} else if (isPrevSearch) {
|
||||||
|
setStateName(upButton, ToolButtonState::Disabled);
|
||||||
|
setStateName(downButton, ToolButtonState::Disabled);
|
||||||
|
} else if (direction == SearchDirection::Up) {
|
||||||
|
setStateName(upButton, ToolButtonState::Disabled);
|
||||||
|
} else {
|
||||||
|
setStateName(downButton, ToolButtonState::Disabled);
|
||||||
|
}
|
||||||
|
messageLabel->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
LineEdit::LineEdit(QWidget* parent) : QLineEdit(parent)
|
LineEdit::LineEdit(QWidget* parent) : QLineEdit(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -22,17 +22,27 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
#include "searchtypes.h"
|
||||||
|
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
class QLabel;
|
||||||
class LineEdit;
|
class LineEdit;
|
||||||
|
class SearchSettingsForm;
|
||||||
|
|
||||||
class SearchForm final : public QWidget
|
class SearchForm final : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
enum class ToolButtonState {
|
||||||
|
Disabled = 0, // Grey
|
||||||
|
Common = 1, // Green
|
||||||
|
Active = 2, // Red
|
||||||
|
};
|
||||||
|
|
||||||
explicit SearchForm(QWidget* parent = nullptr);
|
explicit SearchForm(QWidget* parent = nullptr);
|
||||||
void removeSearchPhrase();
|
void removeSearchPhrase();
|
||||||
QString getSearchPhrase() const;
|
QString getSearchPhrase() const;
|
||||||
|
ParameterSearch getParameterSearch();
|
||||||
void setFocusEditor();
|
void setFocusEditor();
|
||||||
void insertEditor(const QString &text);
|
void insertEditor(const QString &text);
|
||||||
|
|
||||||
@ -42,24 +52,43 @@ protected:
|
|||||||
private:
|
private:
|
||||||
// TODO: Merge with 'createButton' from chatformheader.cpp
|
// TODO: Merge with 'createButton' from chatformheader.cpp
|
||||||
QPushButton* createButton(const QString& name, const QString& state);
|
QPushButton* createButton(const QString& name, const QString& state);
|
||||||
|
ParameterSearch getAndCheckParametrSearch();
|
||||||
|
void setStateName(QPushButton* btn, ToolButtonState state);
|
||||||
|
void useBeginState();
|
||||||
|
|
||||||
|
QPushButton* settingsButton;
|
||||||
QPushButton* upButton;
|
QPushButton* upButton;
|
||||||
QPushButton* downButton;
|
QPushButton* downButton;
|
||||||
QPushButton* hideButton;
|
QPushButton* hideButton;
|
||||||
|
QPushButton* startButton;
|
||||||
LineEdit* searchLine;
|
LineEdit* searchLine;
|
||||||
|
SearchSettingsForm* settings;
|
||||||
|
QLabel* messageLabel;
|
||||||
|
|
||||||
QString searchPhrase;
|
QString searchPhrase;
|
||||||
|
ParameterSearch parameter;
|
||||||
|
|
||||||
|
bool isActiveSettings{false};
|
||||||
|
bool isChangedPhrase{false};
|
||||||
|
bool isSearchInBegin{true};
|
||||||
|
bool isPrevSearch{false};
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void changedSearchPhrase(const QString& text);
|
void changedSearchPhrase(const QString& text);
|
||||||
void clickedUp();
|
void clickedUp();
|
||||||
void clickedDown();
|
void clickedDown();
|
||||||
void clickedHide();
|
void clickedHide();
|
||||||
|
void clickedStart();
|
||||||
|
void clickedSearch();
|
||||||
|
void changedState(bool isUpdate);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void showMessageNotFound(SearchDirection direction);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void searchInBegin(const QString& phrase);
|
void searchInBegin(const QString& phrase, const ParameterSearch& parameter);
|
||||||
void searchUp(const QString& phrase);
|
void searchUp(const QString& phrase, const ParameterSearch& parameter);
|
||||||
void searchDown(const QString& phrase);
|
void searchDown(const QString& phrase, const ParameterSearch& parameter);
|
||||||
void visibleChanged();
|
void visibleChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
78
src/widget/searchtypes.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef SEARCHTYPES_H
|
||||||
|
#define SEARCHTYPES_H
|
||||||
|
|
||||||
|
#include <QDate>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
|
enum class FilterSearch {
|
||||||
|
None,
|
||||||
|
Register,
|
||||||
|
WordsOnly,
|
||||||
|
Regular,
|
||||||
|
RegisterAndWordsOnly,
|
||||||
|
RegisterAndRegular
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PeriodSearch {
|
||||||
|
None,
|
||||||
|
WithTheEnd,
|
||||||
|
WithTheFirst,
|
||||||
|
AfterDate,
|
||||||
|
BeforeDate
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SearchDirection {
|
||||||
|
Up,
|
||||||
|
Down
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParameterSearch {
|
||||||
|
FilterSearch filter{FilterSearch::None};
|
||||||
|
PeriodSearch period{PeriodSearch::None};
|
||||||
|
QDate date;
|
||||||
|
bool isUpdate{false};
|
||||||
|
|
||||||
|
bool operator ==(const ParameterSearch& other) {
|
||||||
|
return filter == other.filter &&
|
||||||
|
period == other.period &&
|
||||||
|
date == other.date;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=(const ParameterSearch& other) {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SearchExtraFunctions {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief generateFilterWordsOnly generate string for filter "Whole words only" for correct search phrase
|
||||||
|
* containing symbols "\[]/^$.|?*+(){}"
|
||||||
|
* @param phrase for search
|
||||||
|
* @return new phrase for search
|
||||||
|
*/
|
||||||
|
static QString generateFilterWordsOnly(const QString &phrase) {
|
||||||
|
QString filter = QRegularExpression::escape(phrase);
|
||||||
|
|
||||||
|
const QString symbols = QStringLiteral("\\[]/^$.|?*+(){}");
|
||||||
|
|
||||||
|
if (filter != phrase) {
|
||||||
|
if (filter.left(1) != QLatin1String("\\")) {
|
||||||
|
filter = QLatin1String("\\b") + filter;
|
||||||
|
} else {
|
||||||
|
filter = QLatin1String("(^|\\s)") + filter;
|
||||||
|
}
|
||||||
|
if (!symbols.contains(filter.right(1))) {
|
||||||
|
filter += QLatin1String("\\b");
|
||||||
|
} else {
|
||||||
|
filter += QLatin1String("($|\\s)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filter = QStringLiteral("\\b%1\\b").arg(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //SEARCHTYPES_H
|
@ -69,6 +69,14 @@ QAbstractButton#callButton
|
|||||||
|
|
||||||
/* SearchLine */
|
/* SearchLine */
|
||||||
|
|
||||||
|
QAbstractButton#searchSettingsButton
|
||||||
|
{
|
||||||
|
background-image: url(":/ui/chatForm/searchSettingsButton.svg");
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
QAbstractButton#searchHideButton
|
QAbstractButton#searchHideButton
|
||||||
{
|
{
|
||||||
background-image: url(":/ui/chatForm/searchHideButton.svg");
|
background-image: url(":/ui/chatForm/searchHideButton.svg");
|
||||||
@ -77,7 +85,6 @@ QAbstractButton#searchHideButton
|
|||||||
height: 35px;
|
height: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QAbstractButton#searchUpButton
|
QAbstractButton#searchUpButton
|
||||||
{
|
{
|
||||||
background-image: url(":/ui/chatForm/searchUpButton.svg");
|
background-image: url(":/ui/chatForm/searchUpButton.svg");
|
||||||
@ -94,6 +101,22 @@ QAbstractButton#searchDownButton
|
|||||||
height: 35px;
|
height: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QAbstractButton#choiceDateButton
|
||||||
|
{
|
||||||
|
background-image: url(":/ui/chatForm/searchCalendarButton.svg");
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 45px;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractButton#startButton
|
||||||
|
{
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 60px;
|
||||||
|
height: 35px;
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
|
||||||
/* Common */
|
/* Common */
|
||||||
|
|
||||||
QAbstractButton
|
QAbstractButton
|
||||||
|
14
ui/chatForm/labels.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
QLabel
|
||||||
|
{
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel:disabled
|
||||||
|
{
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLabel[state="red"]
|
||||||
|
{
|
||||||
|
color: #e84747;
|
||||||
|
}
|
98
ui/chatForm/searchCalendarButton.svg
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.34902"
|
||||||
|
height="20.696665"
|
||||||
|
viewBox="0 0 24.34902 20.696665"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="searchCalendarButton.svg"
|
||||||
|
style="enable-background:new">
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1194"
|
||||||
|
inkscape:window-height="727"
|
||||||
|
id="namedview12"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="11.402803"
|
||||||
|
inkscape:cx="12.17451"
|
||||||
|
inkscape:cy="10.348332"
|
||||||
|
inkscape:window-x="356"
|
||||||
|
inkscape:window-y="158"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2289"
|
||||||
|
osb:paint="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#6e0000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2287" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
style="display:inline"
|
||||||
|
transform="translate(1136.2519,-82.207318)">
|
||||||
|
<g
|
||||||
|
id="g877"
|
||||||
|
transform="matrix(0.04610001,0,0,0.04610001,-1114.1308,77.270056)"
|
||||||
|
style="fill:#ffffff">
|
||||||
|
<rect
|
||||||
|
ry="15.194334"
|
||||||
|
y="107.09895"
|
||||||
|
x="-43.287827"
|
||||||
|
height="79.375"
|
||||||
|
width="39.6875"
|
||||||
|
id="rect816"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.33097997;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.55504587;paint-order:stroke fill markers" />
|
||||||
|
<path
|
||||||
|
id="rect850"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,-479.85032,216.85036)"
|
||||||
|
d="M 133.22656,-214.80859 C 59.41896,-214.80859 0,-155.38963 0,-81.582031 V 0 h 2000 v -81.582031 c 0,-73.807599 -59.419,-133.226559 -133.2266,-133.226559 z M 0,188.15625 v 963.80855 c 0,73.8076 59.41896,133.2266 133.22656,133.2266 H 1866.7734 c 73.8076,0 133.2266,-59.419 133.2266,-133.2266 V 188.15625 Z"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99010497;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.55504587;paint-order:stroke fill markers"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<rect
|
||||||
|
ry="15.194334"
|
||||||
|
y="107.09895"
|
||||||
|
x="-426.93365"
|
||||||
|
height="79.375"
|
||||||
|
width="39.6875"
|
||||||
|
id="rect816-7"
|
||||||
|
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.33097997;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:3.9000001;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.55504587;paint-order:stroke fill markers;enable-background:new" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
@ -9,37 +9,35 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="7.0183306mm"
|
width="26.525974"
|
||||||
height="4.1245208mm"
|
height="15.58874"
|
||||||
viewBox="0 0 7.0183304 4.1245209"
|
viewBox="0 0 26.525974 15.58874"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg8"
|
id="svg8"
|
||||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
sodipodi:docname="searchDownButton.svg"
|
||||||
sodipodi:docname="searchDownButton.svg">
|
inkscape:version="0.92.2 2405546, 2018-03-11">
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
pagecolor="#ffffff"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
borderopacity="1.0"
|
borderopacity="1"
|
||||||
inkscape:pageopacity="0.0"
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="2.8"
|
|
||||||
inkscape:cx="185.76311"
|
|
||||||
inkscape:cy="-116.1932"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
fit-margin-top="0"
|
|
||||||
fit-margin-left="0"
|
|
||||||
fit-margin-right="0"
|
|
||||||
fit-margin-bottom="0"
|
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1015"
|
inkscape:window-height="1015"
|
||||||
|
id="namedview9"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="12.817625"
|
||||||
|
inkscape:cx="13.262987"
|
||||||
|
inkscape:cy="7.7943702"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="0"
|
||||||
inkscape:window-y="876"
|
inkscape:window-y="36"
|
||||||
inkscape:window-maximized="1" />
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata5">
|
id="metadata5">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
@ -60,7 +58,7 @@
|
|||||||
<g
|
<g
|
||||||
id="g11"
|
id="g11"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
transform="matrix(0.03267961,0,0,0.03267961,-57.771132,39.897882)">
|
transform="matrix(0.1242249,0,0,0.1242249,-52.303786,36.122025)">
|
||||||
<rect
|
<rect
|
||||||
transform="rotate(-44.285246)"
|
transform="rotate(-44.285246)"
|
||||||
style="fill:#ffffff;stroke-width:0.36410955"
|
style="fill:#ffffff;stroke-width:0.36410955"
|
||||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
@ -9,37 +9,35 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="5.5071211mm"
|
width="26"
|
||||||
height="5.5071211mm"
|
height="26"
|
||||||
viewBox="0 0 5.5071209 5.5071212"
|
viewBox="0 0 26 26"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg8"
|
id="svg8"
|
||||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
sodipodi:docname="searchHideButton.svg"
|
||||||
sodipodi:docname="hideButton.svg">
|
inkscape:version="0.92.2 2405546, 2018-03-11">
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
pagecolor="#ffffff"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
borderopacity="1.0"
|
borderopacity="1"
|
||||||
inkscape:pageopacity="0.0"
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="2.8"
|
|
||||||
inkscape:cx="186.40227"
|
|
||||||
inkscape:cy="-38.76831"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
fit-margin-top="0"
|
|
||||||
fit-margin-left="0"
|
|
||||||
fit-margin-right="0"
|
|
||||||
fit-margin-bottom="0"
|
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1015"
|
inkscape:window-height="1015"
|
||||||
|
id="namedview9"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="9.0769231"
|
||||||
|
inkscape:cx="13"
|
||||||
|
inkscape:cy="13"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="0"
|
||||||
inkscape:window-y="876"
|
inkscape:window-y="36"
|
||||||
inkscape:window-maximized="1" />
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata5">
|
id="metadata5">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
@ -48,7 +46,7 @@
|
|||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:type
|
<dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
@ -59,7 +57,7 @@
|
|||||||
transform="translate(59.891963,-41.449704)">
|
transform="translate(59.891963,-41.449704)">
|
||||||
<g
|
<g
|
||||||
id="g30"
|
id="g30"
|
||||||
transform="matrix(0.42362466,0.42362466,-0.42362466,0.42362466,-22.854056,42.277356)"
|
transform="matrix(1.9999999,1.9999999,-1.9999999,1.9999999,114.96993,45.355829)"
|
||||||
style="fill:#ffffff">
|
style="fill:#ffffff">
|
||||||
<rect
|
<rect
|
||||||
y="41.988605"
|
y="41.988605"
|
||||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
53
ui/chatForm/searchSettingsButton.svg
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="22.608538"
|
||||||
|
height="22.608543"
|
||||||
|
viewBox="0 0 22.608539 22.608543"
|
||||||
|
enable-background="new 0 0 15.615 15.616"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="searchSettingsButton.svg"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
version="1.1"
|
||||||
|
id="svg6"><metadata
|
||||||
|
id="metadata9"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs7" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1169"
|
||||||
|
inkscape:window-height="745"
|
||||||
|
id="namedview5"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:zoom="15.112705"
|
||||||
|
inkscape:cx="7.8074999"
|
||||||
|
inkscape:cy="16.211526"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="36"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg6" />
|
||||||
|
<path
|
||||||
|
d="m 22.608538,10.183688 c 0,-0.2852152 -0.236003,-0.5183051 -0.518335,-0.5183051 h -0.955599 c -0.288127,0 -0.589284,-0.2229595 -0.668919,-0.4994838 L 19.168392,6.1371404 C 19.030843,5.889577 19.075722,5.5218341 19.27698,5.3162508 l 0.645756,-0.6442642 c 0.202706,-0.2026848 0.202706,-0.5313344 0,-0.7340239 L 18.369167,2.3830454 c -0.20125,-0.2026859 -0.531372,-0.2026859 -0.738417,0 L 16.931428,3.0837706 C 16.725832,3.2893579 16.353724,3.3443717 16.100349,3.2140707 L 13.46522,2.1571936 C 13.190124,2.0804606 12.96136,1.782216 12.96136,1.4941079 V 0.5168576 C 12.96136,0.2345406 12.728252,0 12.445917,0 H 10.24515 C 9.9599197,0 9.7253655,0.234541 9.7253655,0.5168576 v 0.9772503 c 0,0.2881081 -0.2258667,0.5877995 -0.4980661,0.6732181 L 6.1722829,3.4746724 C 5.9261437,3.61801 5.5612809,3.5702314 5.3571307,3.3704474 l -0.68774,-0.6862637 c -0.1998076,-0.2012533 -0.5313693,-0.2012533 -0.7326241,0 L 2.3817512,4.2405479 c -0.2041499,0.2026848 -0.2041499,0.5313342 0,0.7340239 L 3.1274059,5.7259702 C 3.334452,5.928655 3.3894712,6.299293 3.2562666,6.5512046 L 2.2166937,9.1644505 C 2.1399568,9.4409884 1.8416947,9.6653821 1.5535678,9.6653821 H 0.5168907 C 0.23165972,9.6653796 0,9.8984739 0,10.183688 v 2.199178 c 0,0.286676 0.23165972,0.521202 0.5168907,0.521202 h 1.0366771 c 0.2881267,0 0.5892847,0.222956 0.6718131,0.498035 l 1.2770241,3.005592 c 0.1462352,0.247564 0.094112,0.615306 -0.1042469,0.816548 l -0.7152493,0.713756 c -0.2012548,0.202687 -0.2012548,0.531334 0,0.734023 l 1.5579114,1.554919 c 0.2026997,0.202688 0.5328173,0.202688 0.7311763,0 l 0.7644767,-0.760086 c 0.2041494,-0.202688 0.5704624,-0.256266 0.8252873,-0.120157 l 2.6655348,1.062673 c 0.2722005,0.07961 0.4980661,0.379319 0.4980661,0.663083 v 1.016336 c 0,0.286639 0.2345578,0.519753 0.5197836,0.519753 h 2.200768 c 0.282338,0 0.515445,-0.233097 0.515445,-0.519753 v -1.016343 c 0,-0.283773 0.225867,-0.583454 0.50386,-0.667427 l 2.981172,-1.265359 c 0.249035,-0.140437 0.611003,-0.09123 0.816601,0.108604 l 0.673261,0.677563 c 0.201254,0.20125 0.532818,0.20125 0.734071,0 l 1.557911,-1.557812 c 0.20125,-0.20125 0.20125,-0.532783 0,-0.732578 l -0.719592,-0.71667 c -0.19836,-0.202686 -0.254825,-0.573319 -0.118728,-0.825236 l 1.080113,-2.688527 c 0.0753,-0.275072 0.376445,-0.499484 0.664574,-0.502381 h 0.955595 c 0.282339,0 0.518336,-0.233089 0.518336,-0.518305 z m -11.303545,4.815317 c -2.0429492,0 -3.694972,-1.654813 -3.694972,-3.696183 0,-2.0413696 1.6520228,-3.694736 3.694972,-3.694736 2.040053,0 3.697868,1.6533664 3.697868,3.694736 0,2.04137 -1.657815,3.696183 -3.697868,3.696183 z"
|
||||||
|
id="path2"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#ffffff;stroke-width:1.44782674" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
@ -9,37 +9,35 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="7.0183306mm"
|
width="26.525974"
|
||||||
height="4.1245208mm"
|
height="15.58874"
|
||||||
viewBox="0 0 7.0183304 4.1245209"
|
viewBox="0 0 26.525974 15.58874"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
id="svg8"
|
id="svg8"
|
||||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
sodipodi:docname="searchUpButton.svg"
|
||||||
sodipodi:docname="searchUpButton.svg">
|
inkscape:version="0.92.2 2405546, 2018-03-11">
|
||||||
<defs
|
|
||||||
id="defs2" />
|
|
||||||
<sodipodi:namedview
|
<sodipodi:namedview
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
pagecolor="#ffffff"
|
||||||
bordercolor="#666666"
|
bordercolor="#666666"
|
||||||
borderopacity="1.0"
|
borderopacity="1"
|
||||||
inkscape:pageopacity="0.0"
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="2.8"
|
|
||||||
inkscape:cx="185.76311"
|
|
||||||
inkscape:cy="-116.1932"
|
|
||||||
inkscape:document-units="mm"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
fit-margin-top="0"
|
|
||||||
fit-margin-left="0"
|
|
||||||
fit-margin-right="0"
|
|
||||||
fit-margin-bottom="0"
|
|
||||||
inkscape:window-width="1920"
|
inkscape:window-width="1920"
|
||||||
inkscape:window-height="1015"
|
inkscape:window-height="1015"
|
||||||
|
id="namedview9"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="12.817625"
|
||||||
|
inkscape:cx="0.81918401"
|
||||||
|
inkscape:cy="7.79437"
|
||||||
inkscape:window-x="0"
|
inkscape:window-x="0"
|
||||||
inkscape:window-y="876"
|
inkscape:window-y="36"
|
||||||
inkscape:window-maximized="1" />
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
<metadata
|
<metadata
|
||||||
id="metadata5">
|
id="metadata5">
|
||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
@ -48,7 +46,7 @@
|
|||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:type
|
<dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
@ -56,11 +54,11 @@
|
|||||||
inkscape:label="Layer 1"
|
inkscape:label="Layer 1"
|
||||||
inkscape:groupmode="layer"
|
inkscape:groupmode="layer"
|
||||||
id="layer1"
|
id="layer1"
|
||||||
transform="translate(59.722852,-41.245778)">
|
transform="translate(59.722851,-41.245778)">
|
||||||
<g
|
<g
|
||||||
id="g11"
|
id="g11"
|
||||||
style="fill:#ffffff"
|
style="fill:#ffffff"
|
||||||
transform="matrix(0.03267961,0,0,-0.03267961,-57.771132,46.718195)">
|
transform="matrix(0.12336383,0,0,-0.12336383,-52.355211,61.903867)">
|
||||||
<rect
|
<rect
|
||||||
transform="rotate(-44.285246)"
|
transform="rotate(-44.285246)"
|
||||||
style="fill:#ffffff;stroke-width:0.36410955"
|
style="fill:#ffffff;stroke-width:0.36410955"
|
||||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
@ -223,3 +223,9 @@ QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
|
|||||||
{
|
{
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRadioButton
|
||||||
|
{
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|