1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

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
This commit is contained in:
sudden6 2018-08-15 14:46:24 +02:00
commit 8e182b7dfd
No known key found for this signature in database
GPG Key ID: 279509B499E032B9
32 changed files with 1448 additions and 191 deletions

View File

@ -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

View File

@ -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>

View 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

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}
/**

View File

@ -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 &parameter);
QDateTime getStartDateChatHistory(const QString& friendPk);
void markAsSent(qint64 messageId);

View File

@ -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..."));

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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()

View File

@ -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:

View File

@ -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();

View File

@ -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);

View 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);
}

View 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

View 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>

View File

@ -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)
{
}

View File

@ -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
View 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

View File

@ -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
View File

@ -0,0 +1,14 @@
QLabel
{
color: #000;
}
QLabel:disabled
{
color: #ddd;
}
QLabel[state="red"]
{
color: #e84747;
}

View 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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -223,3 +223,9 @@ QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
{
background: none;
}
QRadioButton
{
background: white;
color: black;
}