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/profileform.ui
|
||||
src/widget/form/removefrienddialog.ui
|
||||
src/widget/form/searchsettingsform.ui
|
||||
src/widget/form/setpassworddialog.ui
|
||||
src/widget/form/settings/aboutsettings.ui
|
||||
src/widget/form/settings/advancedsettings.ui
|
||||
|
@ -360,6 +361,7 @@ set(${PROJECT_NAME}_SOURCES
|
|||
src/widget/flowlayout.h
|
||||
src/widget/searchform.cpp
|
||||
src/widget/searchform.h
|
||||
src/widget/searchtypes.h
|
||||
src/widget/form/addfriendform.cpp
|
||||
src/widget/form/addfriendform.h
|
||||
src/widget/form/chatform.cpp
|
||||
|
@ -378,6 +380,8 @@ set(${PROJECT_NAME}_SOURCES
|
|||
src/widget/form/loadhistorydialog.h
|
||||
src/widget/form/profileform.cpp
|
||||
src/widget/form/profileform.h
|
||||
src/widget/form/searchsettingsform.cpp
|
||||
src/widget/form/searchsettingsform.h
|
||||
src/widget/form/setpassworddialog.cpp
|
||||
src/widget/form/setpassworddialog.h
|
||||
src/widget/form/settings/aboutform.cpp
|
||||
|
|
3
res.qrc
|
@ -55,6 +55,7 @@
|
|||
<file>ui/chatForm/buttons.css</file>
|
||||
<file>ui/chatForm/fullScreenButtons.css</file>
|
||||
<file>ui/chatForm/callButton.svg</file>
|
||||
<file>ui/chatForm/labels.css</file>
|
||||
<file>ui/chatForm/micButton.svg</file>
|
||||
<file>ui/chatForm/micButtonRed.svg</file>
|
||||
<file>ui/chatForm/videoButton.svg</file>
|
||||
|
@ -66,8 +67,10 @@
|
|||
<file>ui/chatForm/emoteButton.svg</file>
|
||||
<file>ui/chatForm/fileButton.svg</file>
|
||||
<file>ui/chatForm/screenshotButton.svg</file>
|
||||
<file>ui/chatForm/searchCalendarButton.svg</file>
|
||||
<file>ui/chatForm/searchDownButton.svg</file>
|
||||
<file>ui/chatForm/searchHideButton.svg</file>
|
||||
<file>ui/chatForm/searchSettingsButton.svg</file>
|
||||
<file>ui/chatForm/searchUpButton.svg</file>
|
||||
<file>ui/chatForm/sendButton.svg</file>
|
||||
<file>ui/chatForm/exitFullScreenButton.svg</file>
|
||||
|
|
|
@ -553,6 +553,14 @@ ChatLine::Ptr ChatLog::getLatestLine() const
|
|||
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
|
||||
* @param pos Position on screen in global coordinates
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
ChatLine::Ptr getTypingNotification() const;
|
||||
QVector<ChatLine::Ptr> getLines();
|
||||
ChatLine::Ptr getLatestLine() const;
|
||||
ChatLine::Ptr getFirstLine() const;
|
||||
ChatLineContent* getContentFromGlobalPos(QPoint pos) const;
|
||||
const uint repNameAfter = 5 * 60;
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#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,
|
||||
const QColor c)
|
||||
: rawText(rwText)
|
||||
|
@ -58,7 +60,7 @@ void Text::setText(const QString& txt)
|
|||
dirty = true;
|
||||
}
|
||||
|
||||
void Text::selectText(const QString &txt, const int index)
|
||||
void Text::selectText(const QString& txt, const std::pair<int, int>& point)
|
||||
{
|
||||
regenerate();
|
||||
|
||||
|
@ -66,21 +68,22 @@ void Text::selectText(const QString &txt, const int index)
|
|||
return;
|
||||
}
|
||||
|
||||
auto cursor = doc->find(txt, index);
|
||||
auto cursor = doc->find(txt, point.first);
|
||||
|
||||
if (!cursor.isNull()) {
|
||||
cursor.beginEditBlock();
|
||||
cursor.setPosition(index);
|
||||
cursor.setPosition(index + txt.size(), QTextCursor::KeepAnchor);
|
||||
cursor.endEditBlock();
|
||||
selectText(cursor, point);
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -439,3 +442,20 @@ QString Text::extractImgTooltip(int pos) const
|
|||
|
||||
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();
|
||||
|
||||
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();
|
||||
|
||||
virtual void setWidth(qreal width) final;
|
||||
|
@ -78,6 +79,8 @@ protected:
|
|||
QString extractImgTooltip(int pos) const;
|
||||
|
||||
private:
|
||||
void selectText(QTextCursor& cursor, const std::pair<int, int>& point);
|
||||
|
||||
QTextDocument* doc = nullptr;
|
||||
QString text;
|
||||
QString rawText;
|
||||
|
|
|
@ -28,14 +28,6 @@
|
|||
#include <QFile>
|
||||
#include <QMetaObject>
|
||||
#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;
|
||||
}
|
||||
|
||||
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 (!execNow("PRAGMA key = \"x'" + hexKey + "'\"")) {
|
||||
qWarning() << "Failed to set encryption key";
|
||||
|
@ -705,3 +709,43 @@ QVariant RawDatabase::extractData(sqlite3_stmt* stmt, int col)
|
|||
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 <QVariant>
|
||||
#include <QVector>
|
||||
#include <QRegularExpression>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
struct sqlite3;
|
||||
struct sqlite3_stmt;
|
||||
/// 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>
|
||||
|
||||
|
||||
class RawDatabase : QObject
|
||||
{
|
||||
|
@ -85,8 +91,12 @@ protected:
|
|||
static QString deriveKey(const QString& password, const QByteArray& salt);
|
||||
static QString deriveKey(const QString& password);
|
||||
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:
|
||||
static void regexp(sqlite3_context* ctx, int argc, sqlite3_value** argv, const QRegularExpression::PatternOptions cs);
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
QVector<Query> queries;
|
||||
|
|
|
@ -315,35 +315,107 @@ QList<History::DateMessages> History::getChatHistoryCounts(const ToxPk& friendPk
|
|||
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;
|
||||
auto rowCallback = [&counts](const QVector<QVariant>& row) {
|
||||
counts.append(QDateTime::fromMSecsSinceEpoch(row[0].toLongLong()));
|
||||
QDateTime result;
|
||||
auto rowCallback = [&result](const QVector<QVariant>& row) {
|
||||
result = QDateTime::fromMSecsSinceEpoch(row[0].toLongLong());
|
||||
};
|
||||
|
||||
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("SELECT timestamp "
|
||||
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' "
|
||||
"AND message LIKE '%%2%' "
|
||||
"AND timestamp < '%3' ORDER BY timestamp DESC LIMIT 1;")
|
||||
"AND %2 "
|
||||
"%3")
|
||||
.arg(friendPk)
|
||||
.arg(phrase)
|
||||
.arg(from.toMSecsSinceEpoch());
|
||||
|
||||
.arg(message)
|
||||
.arg(period);
|
||||
|
||||
db->execNow({queryText, rowCallback});
|
||||
|
||||
if (!counts.isEmpty()) {
|
||||
return counts[0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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/persistence/db/rawdatabase.h"
|
||||
#include "src/widget/searchtypes.h"
|
||||
|
||||
class Profile;
|
||||
class HistoryKeeper;
|
||||
|
@ -82,7 +83,8 @@ public:
|
|||
const QDateTime& to);
|
||||
QList<HistMessage> getChatHistoryDefaultNum(const QString& friendPk);
|
||||
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);
|
||||
|
||||
|
|
|
@ -502,7 +502,38 @@ void ChatForm::onVolMuteToggle()
|
|||
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()) {
|
||||
disableSearchText();
|
||||
|
@ -511,29 +542,27 @@ void ChatForm::onSearchUp(const QString& phrase)
|
|||
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
|
||||
int numLines = lines.size();
|
||||
|
||||
int startLine = numLines - searchPoint.x();
|
||||
int startLine;
|
||||
|
||||
if (startLine == 0) {
|
||||
QString pk = f->getPublicKey().toString();
|
||||
QDateTime newBaseDate = history->getDateWhereFindPhrase(pk, earliestMessage, phrase);
|
||||
|
||||
if (!newBaseDate.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
searchAfterLoadHistory = true;
|
||||
loadHistoryByDateRange(newBaseDate);
|
||||
if (searchAfterLoadHistory) {
|
||||
startLine = 1;
|
||||
searchAfterLoadHistory = false;
|
||||
} else {
|
||||
startLine = numLines - searchPoint.x();
|
||||
}
|
||||
|
||||
if (startLine == 0 && loadHistory(phrase, parameter)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isSearch = searchInText(phrase, true);
|
||||
const bool isSearch = searchInText(phrase, parameter, SearchDirection::Up);
|
||||
|
||||
if (!isSearch) {
|
||||
QString pk = f->getPublicKey().toString();
|
||||
QDateTime newBaseDate = history->getDateWhereFindPhrase(pk, earliestMessage, phrase);
|
||||
const QString pk = f->getPublicKey().toString();
|
||||
const QDateTime newBaseDate = history->getDateWhereFindPhrase(pk, earliestMessage, phrase, parameter);
|
||||
|
||||
if (!newBaseDate.isValid()) {
|
||||
emit messageNotFoundShow(SearchDirection::Up);
|
||||
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)
|
||||
|
@ -728,10 +759,10 @@ QString getMsgAuthorDispName(const ToxPk& authorPk, const QString& dispName)
|
|||
|
||||
void ChatForm::loadHistoryDefaultNum(bool processUndelivered)
|
||||
{
|
||||
QString pk = f->getPublicKey().toString();
|
||||
const QString pk = f->getPublicKey().toString();
|
||||
QList<History::HistMessage> msgs = history->getChatHistoryDefaultNum(pk);
|
||||
if (!msgs.isEmpty()) {
|
||||
earliestMessage = msgs.back().timestamp;
|
||||
earliestMessage = msgs.first().timestamp;
|
||||
}
|
||||
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()
|
||||
{
|
||||
loadHistoryAction->setText(tr("Load chat history..."));
|
||||
|
|
|
@ -77,8 +77,9 @@ public slots:
|
|||
void onFileNameChanged(const ToxPk& friendPk);
|
||||
|
||||
protected slots:
|
||||
void onSearchUp(const QString& phrase) override;
|
||||
void onSearchDown(const QString& phrase) override;
|
||||
void searchInBegin(const QString& phrase, const ParameterSearch& parameter) override;
|
||||
void onSearchUp(const QString& phrase, const ParameterSearch& parameter) override;
|
||||
void onSearchDown(const QString& phrase, const ParameterSearch& parameter) override;
|
||||
|
||||
private slots:
|
||||
void clearChatArea(bool notInForm) override final;
|
||||
|
@ -143,6 +144,7 @@ private:
|
|||
void stopCounter(bool error = false);
|
||||
void updateCallButtons();
|
||||
void SendMessageStr(QString msg);
|
||||
bool loadHistory(const QString& phrase, const ParameterSearch& parameter);
|
||||
|
||||
protected:
|
||||
GenericNetCamView* createNetcam() final override;
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <QFileDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#ifdef SPELL_CHECKING
|
||||
|
@ -233,6 +234,7 @@ GenericChatForm::GenericChatForm(const Contact* contact, QWidget* parent)
|
|||
connect(searchForm, &SearchForm::searchUp, this, &GenericChatForm::onSearchUp);
|
||||
connect(searchForm, &SearchForm::searchDown, this, &GenericChatForm::onSearchDown);
|
||||
connect(searchForm, &SearchForm::visibleChanged, this, &GenericChatForm::onSearchTriggered);
|
||||
connect(this, &GenericChatForm::messageNotFoundShow, searchForm, &SearchForm::showMessageNotFound);
|
||||
|
||||
connect(chatWidget, &ChatLog::workerTimeoutFinished, this, &GenericChatForm::onContinueSearch);
|
||||
|
||||
|
@ -283,18 +285,12 @@ void GenericChatForm::hideFileMenu()
|
|||
|
||||
QDate GenericChatForm::getLatestDate() const
|
||||
{
|
||||
ChatLine::Ptr chatLine = chatWidget->getLatestLine();
|
||||
return getDate(chatWidget->getLatestLine());
|
||||
}
|
||||
|
||||
if (chatLine) {
|
||||
Timestamp* timestamp = qobject_cast<Timestamp*>(chatLine->getContent(2));
|
||||
|
||||
if (timestamp)
|
||||
return timestamp->getTime().date();
|
||||
else
|
||||
return QDate::currentDate();
|
||||
}
|
||||
|
||||
return QDate();
|
||||
QDate GenericChatForm::getFirstDate() const
|
||||
{
|
||||
return getDate(chatWidget->getFirstLine());
|
||||
}
|
||||
|
||||
void GenericChatForm::setName(const QString& newName)
|
||||
|
@ -551,6 +547,21 @@ void GenericChatForm::addSystemDateMessage()
|
|||
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()
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -576,19 +587,59 @@ bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
|
|||
disableSearchText();
|
||||
}
|
||||
|
||||
QVector<ChatLine::Ptr> lines = chatWidget->getLines();
|
||||
auto lines = chatWidget->getLines();
|
||||
|
||||
if (lines.isEmpty()) {
|
||||
return isSearch;
|
||||
}
|
||||
|
||||
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) {
|
||||
return isSearch;
|
||||
}
|
||||
|
||||
const bool searchUp = (direction == SearchDirection::Up);
|
||||
for (int i = startLine; searchUp ? i >= 0 : i < numLines; searchUp ? --i : ++i) {
|
||||
ChatLine::Ptr l = lines[i];
|
||||
|
||||
|
@ -608,19 +659,56 @@ bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
int index = indexForSearchInLine(txt, phrase, searchUp);
|
||||
if ((index == -1 && searchPoint.y() > -1)) {
|
||||
auto point = indexForSearchInLine(txt, phrase, parameter, direction);
|
||||
if ((point.first == -1 && searchPoint.y() > -1)) {
|
||||
text->deselectText();
|
||||
searchPoint.setY(-1);
|
||||
} else {
|
||||
chatWidget->scrollToLine(l);
|
||||
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;
|
||||
|
||||
break;
|
||||
|
@ -630,27 +718,100 @@ bool GenericChatForm::searchInText(const QString& phrase, bool searchUp)
|
|||
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;
|
||||
if (searchPoint.y() > -1) {
|
||||
startIndex = searchPoint.y() - 1;
|
||||
}
|
||||
|
||||
index = txt.lastIndexOf(phrase, startIndex, Qt::CaseInsensitive);
|
||||
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);
|
||||
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 {
|
||||
int startIndex = 0;
|
||||
if (searchPoint.y() > -1) {
|
||||
startIndex = searchPoint.y() + 1;
|
||||
}
|
||||
|
||||
index = txt.indexOf(phrase, startIndex, Qt::CaseInsensitive);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
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 index;
|
||||
return std::make_pair(index, size);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
QString phrase = searchForm->getSearchPhrase();
|
||||
const QString phrase = searchForm->getSearchPhrase();
|
||||
const ParameterSearch parameter = searchForm->getParameterSearch();
|
||||
if (!phrase.isEmpty() && searchAfterLoadHistory) {
|
||||
searchAfterLoadHistory = false;
|
||||
onSearchUp(phrase);
|
||||
if (parameter.period == PeriodSearch::WithTheFirst || parameter.period == PeriodSearch::AfterDate) {
|
||||
searchAfterLoadHistory = false;
|
||||
onSearchDown(phrase, parameter);
|
||||
} else {
|
||||
onSearchUp(phrase, parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "src/chatlog/chatmessage.h"
|
||||
#include "src/core/toxpk.h"
|
||||
#include "src/widget/searchtypes.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QWidget>
|
||||
|
@ -81,12 +82,14 @@ public:
|
|||
void addAlertMessage(const ToxPk& author, const QString& message, const QDateTime& datetime);
|
||||
static QString resolveToxPk(const ToxPk& pk);
|
||||
QDate getLatestDate() const;
|
||||
QDate getFirstDate() const;
|
||||
|
||||
signals:
|
||||
void sendMessage(uint32_t, QString);
|
||||
void sendAction(uint32_t, QString);
|
||||
void chatAreaCleared();
|
||||
void messageInserted();
|
||||
void messageNotFoundShow(SearchDirection direction);
|
||||
|
||||
public slots:
|
||||
void focusInput();
|
||||
|
@ -113,14 +116,15 @@ protected slots:
|
|||
void searchFormShow();
|
||||
void onSearchTriggered();
|
||||
|
||||
void searchInBegin(const QString& phrase);
|
||||
virtual void onSearchUp(const QString& phrase) = 0;
|
||||
virtual void onSearchDown(const QString& phrase) = 0;
|
||||
virtual void searchInBegin(const QString& phrase, const ParameterSearch& parameter) = 0;
|
||||
virtual void onSearchUp(const QString& phrase, const ParameterSearch& parameter) = 0;
|
||||
virtual void onSearchDown(const QString& phrase, const ParameterSearch& parameter) = 0;
|
||||
void onContinueSearch();
|
||||
|
||||
private:
|
||||
void retranslateUi();
|
||||
void addSystemDateMessage();
|
||||
QDate getDate(const ChatLine::Ptr& chatLine) const;
|
||||
|
||||
protected:
|
||||
ChatMessage::Ptr createMessage(const ToxPk& author, const QString& message,
|
||||
|
@ -139,8 +143,8 @@ protected:
|
|||
virtual void resizeEvent(QResizeEvent* event) final override;
|
||||
virtual bool eventFilter(QObject* object, QEvent* event) final override;
|
||||
void disableSearchText();
|
||||
bool searchInText(const QString& phrase, bool searchUp);
|
||||
int indexForSearchInLine(const QString& txt, const QString& phrase, bool searchUp);
|
||||
bool searchInText(const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
||||
std::pair<int, int> indexForSearchInLine(const QString& txt, const QString& phrase, const ParameterSearch& parameter, SearchDirection direction);
|
||||
|
||||
protected:
|
||||
bool audioInputFlag;
|
||||
|
|
|
@ -199,14 +199,31 @@ void GroupChatForm::onTitleChanged(uint32_t groupId, const QString& author, cons
|
|||
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()
|
||||
|
|
|
@ -50,8 +50,9 @@ private slots:
|
|||
void onCallClicked();
|
||||
void onUserListChanged();
|
||||
void onTitleChanged(uint32_t groupId, const QString& author, const QString& title);
|
||||
void onSearchUp(const QString& phrase) override;
|
||||
void onSearchDown(const QString& phrase) override;
|
||||
void searchInBegin(const QString& phrase, const ParameterSearch& parameter) override;
|
||||
void onSearchUp(const QString& phrase, const ParameterSearch& parameter) override;
|
||||
void onSearchDown(const QString& phrase, const ParameterSearch& parameter) override;
|
||||
void onLabelContextMenuRequested(const QPoint& localPos);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -37,6 +37,13 @@ LoadHistoryDialog::LoadHistoryDialog(const ToxPk& friendPk, QWidget* parent)
|
|||
&LoadHistoryDialog::highlightDates);
|
||||
}
|
||||
|
||||
LoadHistoryDialog::LoadHistoryDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::LoadHistoryDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
LoadHistoryDialog::~LoadHistoryDialog()
|
||||
{
|
||||
delete ui;
|
||||
|
@ -54,6 +61,16 @@ QDateTime LoadHistoryDialog::getFromDate()
|
|||
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)
|
||||
{
|
||||
History* history = Nexus::getProfile()->getHistory();
|
||||
|
|
|
@ -34,9 +34,12 @@ class LoadHistoryDialog : public QDialog
|
|||
|
||||
public:
|
||||
explicit LoadHistoryDialog(const ToxPk& friendPk, QWidget* parent = 0);
|
||||
explicit LoadHistoryDialog(QWidget* parent = 0);
|
||||
~LoadHistoryDialog();
|
||||
|
||||
QDateTime getFromDate();
|
||||
void setTitle(const QString& title);
|
||||
void setInfoLabel(const QString& info);
|
||||
|
||||
public slots:
|
||||
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 "form/searchsettingsform.h"
|
||||
#include "src/widget/style.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include <array>
|
||||
|
||||
static std::array<QString, 3> STATE_NAME = {
|
||||
QString{},
|
||||
QStringLiteral("green"),
|
||||
QStringLiteral("red"),
|
||||
};
|
||||
|
||||
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();
|
||||
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");
|
||||
downButton = createButton("searchDownButton", "green");
|
||||
hideButton = createButton("searchHideButton", "red");
|
||||
startButton = createButton("startButton", "green");
|
||||
startButton->setText(tr("Start"));
|
||||
|
||||
layout->setMargin(0);
|
||||
layout->addWidget(searchLine);
|
||||
layout->addWidget(upButton);
|
||||
layout->addWidget(downButton);
|
||||
layout->addWidget(hideButton);
|
||||
layoutNavigation->setMargin(0);
|
||||
layoutNavigation->addWidget(settingsButton);
|
||||
layoutNavigation->addWidget(searchLine);
|
||||
layoutNavigation->addWidget(startButton);
|
||||
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);
|
||||
|
||||
|
@ -48,6 +87,10 @@ SearchForm::SearchForm(QWidget* parent) : QWidget(parent)
|
|||
connect(upButton, &QPushButton::clicked, this, &SearchForm::clickedUp);
|
||||
connect(downButton, &QPushButton::clicked, this, &SearchForm::clickedDown);
|
||||
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()
|
||||
|
@ -60,6 +103,11 @@ QString SearchForm::getSearchPhrase() const
|
|||
return searchPhrase;
|
||||
}
|
||||
|
||||
ParameterSearch SearchForm::getParameterSearch()
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
|
||||
void SearchForm::setFocusEditor()
|
||||
{
|
||||
searchLine->setFocus();
|
||||
|
@ -87,20 +135,99 @@ QPushButton *SearchForm::createButton(const QString& name, const QString& state)
|
|||
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)
|
||||
{
|
||||
useBeginState();
|
||||
|
||||
if (searchPhrase == text) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString l = text.right(1);
|
||||
if (!l.isEmpty() && l != " " && l[0].isSpace()) {
|
||||
searchLine->setText(searchPhrase);
|
||||
return;
|
||||
}
|
||||
|
||||
searchPhrase = text;
|
||||
emit searchInBegin(searchPhrase);
|
||||
isChangedPhrase = true;
|
||||
if (isActiveSettings) {
|
||||
if (startButton->isHidden()) {
|
||||
changedState(true);
|
||||
}
|
||||
} else {
|
||||
isSearchInBegin = true;
|
||||
emit searchInBegin(searchPhrase, getAndCheckParametrSearch());
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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()
|
||||
|
@ -109,6 +236,64 @@ void SearchForm::clickedHide()
|
|||
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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -22,17 +22,27 @@
|
|||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include "searchtypes.h"
|
||||
|
||||
class QPushButton;
|
||||
class QLabel;
|
||||
class LineEdit;
|
||||
class SearchSettingsForm;
|
||||
|
||||
class SearchForm final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class ToolButtonState {
|
||||
Disabled = 0, // Grey
|
||||
Common = 1, // Green
|
||||
Active = 2, // Red
|
||||
};
|
||||
|
||||
explicit SearchForm(QWidget* parent = nullptr);
|
||||
void removeSearchPhrase();
|
||||
QString getSearchPhrase() const;
|
||||
ParameterSearch getParameterSearch();
|
||||
void setFocusEditor();
|
||||
void insertEditor(const QString &text);
|
||||
|
||||
|
@ -42,24 +52,43 @@ protected:
|
|||
private:
|
||||
// TODO: Merge with 'createButton' from chatformheader.cpp
|
||||
QPushButton* createButton(const QString& name, const QString& state);
|
||||
ParameterSearch getAndCheckParametrSearch();
|
||||
void setStateName(QPushButton* btn, ToolButtonState state);
|
||||
void useBeginState();
|
||||
|
||||
QPushButton* settingsButton;
|
||||
QPushButton* upButton;
|
||||
QPushButton* downButton;
|
||||
QPushButton* hideButton;
|
||||
QPushButton* startButton;
|
||||
LineEdit* searchLine;
|
||||
SearchSettingsForm* settings;
|
||||
QLabel* messageLabel;
|
||||
|
||||
QString searchPhrase;
|
||||
ParameterSearch parameter;
|
||||
|
||||
bool isActiveSettings{false};
|
||||
bool isChangedPhrase{false};
|
||||
bool isSearchInBegin{true};
|
||||
bool isPrevSearch{false};
|
||||
|
||||
private slots:
|
||||
void changedSearchPhrase(const QString& text);
|
||||
void clickedUp();
|
||||
void clickedDown();
|
||||
void clickedHide();
|
||||
void clickedStart();
|
||||
void clickedSearch();
|
||||
void changedState(bool isUpdate);
|
||||
|
||||
public slots:
|
||||
void showMessageNotFound(SearchDirection direction);
|
||||
|
||||
signals:
|
||||
void searchInBegin(const QString& phrase);
|
||||
void searchUp(const QString& phrase);
|
||||
void searchDown(const QString& phrase);
|
||||
void searchInBegin(const QString& phrase, const ParameterSearch& parameter);
|
||||
void searchUp(const QString& phrase, const ParameterSearch& parameter);
|
||||
void searchDown(const QString& phrase, const ParameterSearch& parameter);
|
||||
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 */
|
||||
|
||||
QAbstractButton#searchSettingsButton
|
||||
{
|
||||
background-image: url(":/ui/chatForm/searchSettingsButton.svg");
|
||||
border-radius: 5px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
QAbstractButton#searchHideButton
|
||||
{
|
||||
background-image: url(":/ui/chatForm/searchHideButton.svg");
|
||||
|
@ -77,7 +85,6 @@ QAbstractButton#searchHideButton
|
|||
height: 35px;
|
||||
}
|
||||
|
||||
|
||||
QAbstractButton#searchUpButton
|
||||
{
|
||||
background-image: url(":/ui/chatForm/searchUpButton.svg");
|
||||
|
@ -94,6 +101,22 @@ QAbstractButton#searchDownButton
|
|||
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 */
|
||||
|
||||
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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="7.0183306mm"
|
||||
height="4.1245208mm"
|
||||
viewBox="0 0 7.0183304 4.1245209"
|
||||
width="26.525974"
|
||||
height="15.58874"
|
||||
viewBox="0 0 26.525974 15.58874"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
||||
sodipodi:docname="searchDownButton.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
sodipodi:docname="searchDownButton.svg"
|
||||
inkscape:version="0.92.2 2405546, 2018-03-11">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
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-height="1015"
|
||||
id="namedview9"
|
||||
showgrid="false"
|
||||
inkscape:zoom="12.817625"
|
||||
inkscape:cx="13.262987"
|
||||
inkscape:cy="7.7943702"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="876"
|
||||
inkscape:window-maximized="1" />
|
||||
inkscape:window-y="36"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
|
@ -60,7 +58,7 @@
|
|||
<g
|
||||
id="g11"
|
||||
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
|
||||
transform="rotate(-44.285246)"
|
||||
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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="5.5071211mm"
|
||||
height="5.5071211mm"
|
||||
viewBox="0 0 5.5071209 5.5071212"
|
||||
width="26"
|
||||
height="26"
|
||||
viewBox="0 0 26 26"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
||||
sodipodi:docname="hideButton.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
sodipodi:docname="searchHideButton.svg"
|
||||
inkscape:version="0.92.2 2405546, 2018-03-11">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
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-height="1015"
|
||||
id="namedview9"
|
||||
showgrid="false"
|
||||
inkscape:zoom="9.0769231"
|
||||
inkscape:cx="13"
|
||||
inkscape:cy="13"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="876"
|
||||
inkscape:window-maximized="1" />
|
||||
inkscape:window-y="36"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
|
@ -48,7 +46,7 @@
|
|||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
|
@ -59,7 +57,7 @@
|
|||
transform="translate(59.891963,-41.449704)">
|
||||
<g
|
||||
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">
|
||||
<rect
|
||||
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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="7.0183306mm"
|
||||
height="4.1245208mm"
|
||||
viewBox="0 0 7.0183304 4.1245209"
|
||||
width="26.525974"
|
||||
height="15.58874"
|
||||
viewBox="0 0 26.525974 15.58874"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
|
||||
sodipodi:docname="searchUpButton.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
sodipodi:docname="searchUpButton.svg"
|
||||
inkscape:version="0.92.2 2405546, 2018-03-11">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
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-height="1015"
|
||||
id="namedview9"
|
||||
showgrid="false"
|
||||
inkscape:zoom="12.817625"
|
||||
inkscape:cx="0.81918401"
|
||||
inkscape:cy="7.79437"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="876"
|
||||
inkscape:window-maximized="1" />
|
||||
inkscape:window-y="36"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
|
@ -48,7 +46,7 @@
|
|||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
|
@ -56,11 +54,11 @@
|
|||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(59.722852,-41.245778)">
|
||||
transform="translate(59.722851,-41.245778)">
|
||||
<g
|
||||
id="g11"
|
||||
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
|
||||
transform="rotate(-44.285246)"
|
||||
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;
|
||||
}
|
||||
|
||||
QRadioButton
|
||||
{
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
|
|