1 /*
2     Copyright © 2015-2019 by The qTox Project Contributors
3 
4     This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6     qTox is libre software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10 
11     qTox is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with qTox.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "searchform.h"
21 #include "form/searchsettingsform.h"
22 #include "src/widget/style.h"
23 
24 #include <QVBoxLayout>
25 #include <QHBoxLayout>
26 #include <QPushButton>
27 #include <QLabel>
28 #include <QKeyEvent>
29 
30 #include <array>
31 
32 static std::array<QString, 3> STATE_NAME = {
33     QString{},
34     QStringLiteral("green"),
35     QStringLiteral("red"),
36 };
37 
SearchForm(QWidget * parent)38 SearchForm::SearchForm(QWidget* parent) : QWidget(parent)
39 {
40     QVBoxLayout* layout = new QVBoxLayout();
41     QHBoxLayout* layoutNavigation = new QHBoxLayout();
42     QHBoxLayout* layoutMessage = new QHBoxLayout();
43     QSpacerItem *lSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Ignored);
44     QSpacerItem *rSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Ignored);
45     searchLine = new LineEdit();
46     settings = new SearchSettingsForm();
47     messageLabel = new QLabel();
48 
49     settings->setVisible(false);
50     messageLabel->setProperty("state", QStringLiteral("red"));
51     messageLabel->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/labels.css")));
52     messageLabel->setText(tr("The text could not be found."));
53     messageLabel->setVisible(false);
54 
55     settingsButton = createButton("searchSettingsButton", "green");
56     upButton = createButton("searchUpButton", "green");
57     downButton = createButton("searchDownButton", "green");
58     hideButton = createButton("searchHideButton", "red");
59     startButton = createButton("startButton", "green");
60     startButton->setText(tr("Start"));
61 
62     layoutNavigation->setMargin(0);
63     layoutNavigation->addWidget(settingsButton);
64     layoutNavigation->addWidget(searchLine);
65     layoutNavigation->addWidget(startButton);
66     layoutNavigation->addWidget(upButton);
67     layoutNavigation->addWidget(downButton);
68     layoutNavigation->addWidget(hideButton);
69 
70     layout->addLayout(layoutNavigation);
71     layout->addWidget(settings);
72 
73     layoutMessage->addSpacerItem(lSpacer);
74     layoutMessage->addWidget(messageLabel);
75     layoutMessage->addSpacerItem(rSpacer);
76     layout->addLayout(layoutMessage);
77 
78     startButton->setHidden(true);
79 
80     setLayout(layout);
81 
82     connect(searchLine, &LineEdit::textChanged, this, &SearchForm::changedSearchPhrase);
83     connect(searchLine, &LineEdit::clickEnter, this, &SearchForm::clickedUp);
84     connect(searchLine, &LineEdit::clickShiftEnter, this, &SearchForm::clickedDown);
85     connect(searchLine, &LineEdit::clickEsc, this, &SearchForm::clickedHide);
86 
87     connect(upButton, &QPushButton::clicked, this, &SearchForm::clickedUp);
88     connect(downButton, &QPushButton::clicked, this, &SearchForm::clickedDown);
89     connect(hideButton, &QPushButton::clicked, this, &SearchForm::clickedHide);
90     connect(startButton, &QPushButton::clicked, this, &SearchForm::clickedStart);
91     connect(settingsButton, &QPushButton::clicked, this, &SearchForm::clickedSearch);
92 
93     connect(settings, &SearchSettingsForm::updateSettings, this, &SearchForm::changedState);
94 }
95 
removeSearchPhrase()96 void SearchForm::removeSearchPhrase()
97 {
98     searchLine->setText("");
99 }
100 
getSearchPhrase() const101 QString SearchForm::getSearchPhrase() const
102 {
103     return searchPhrase;
104 }
105 
getParameterSearch()106 ParameterSearch SearchForm::getParameterSearch()
107 {
108     return parameter;
109 }
110 
setFocusEditor()111 void SearchForm::setFocusEditor()
112 {
113     searchLine->setFocus();
114 }
115 
insertEditor(const QString & text)116 void SearchForm::insertEditor(const QString &text)
117 {
118     searchLine->insert(text);
119 }
120 
reloadTheme()121 void SearchForm::reloadTheme()
122 {
123     settingsButton->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/buttons.css")));
124     upButton->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/buttons.css")));
125     downButton->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/buttons.css")));
126     hideButton->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/buttons.css")));
127     startButton->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/buttons.css")));
128 
129     settings->reloadTheme();
130 }
131 
showEvent(QShowEvent * event)132 void SearchForm::showEvent(QShowEvent* event)
133 {
134     QWidget::showEvent(event);
135     emit visibleChanged();
136 }
137 
createButton(const QString & name,const QString & state)138 QPushButton *SearchForm::createButton(const QString& name, const QString& state)
139 {
140     QPushButton* btn = new QPushButton();
141     btn->setAttribute(Qt::WA_LayoutUsesWidgetRect);
142     btn->setObjectName(name);
143     btn->setProperty("state", state);
144     btn->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/buttons.css")));
145 
146     return btn;
147 }
148 
getAndCheckParametrSearch()149 ParameterSearch SearchForm::getAndCheckParametrSearch()
150 {
151     if (isActiveSettings) {
152         auto sendParam = settings->getParameterSearch();
153         if (!isChangedPhrase && !sendParam.isUpdate) {
154             sendParam.period = PeriodSearch::None;
155         }
156 
157         isChangedPhrase = false;
158         parameter = sendParam;
159 
160         return sendParam;
161     }
162 
163     return ParameterSearch();
164 }
165 
setStateName(QPushButton * btn,ToolButtonState state)166 void SearchForm::setStateName(QPushButton *btn, ToolButtonState state)
167 {
168     const auto index = static_cast<unsigned long>(state);
169     btn->setProperty("state", STATE_NAME[index]);
170     btn->setStyleSheet(Style::getStylesheet(QStringLiteral("chatForm/buttons.css")));
171     btn->setEnabled(index != 0);
172 }
173 
useBeginState()174 void SearchForm::useBeginState()
175 {
176     setStateName(upButton, ToolButtonState::Common);
177     setStateName(downButton, ToolButtonState::Common);
178     messageLabel->setVisible(false);
179     isPrevSearch = false;
180 }
181 
changedSearchPhrase(const QString & text)182 void SearchForm::changedSearchPhrase(const QString& text)
183 {
184     useBeginState();
185 
186     if (searchPhrase == text) {
187         return;
188     }
189 
190     QString l = text.right(1);
191     if (!l.isEmpty() && l != " " && l[0].isSpace()) {
192         searchLine->setText(searchPhrase);
193         return;
194     }
195 
196     searchPhrase = text;
197     isChangedPhrase = true;
198     if (isActiveSettings) {
199         if (startButton->isHidden()) {
200             changedState(true);
201         }
202     } else {
203         isSearchInBegin = true;
204         emit searchInBegin(searchPhrase, getAndCheckParametrSearch());
205     }
206 }
207 
clickedUp()208 void SearchForm::clickedUp()
209 {
210     if (downButton->isEnabled()) {
211         isPrevSearch = false;
212     } else {
213         isPrevSearch = true;
214         setStateName(downButton, ToolButtonState::Common);
215         messageLabel->setVisible(false);
216     }
217 
218     if (startButton->isHidden()) {
219         isSearchInBegin = false;
220         emit searchUp(searchPhrase, getAndCheckParametrSearch());
221     } else {
222         clickedStart();
223     }
224 }
225 
clickedDown()226 void SearchForm::clickedDown()
227 {
228     if (upButton->isEnabled()) {
229         isPrevSearch = false;
230     } else {
231         isPrevSearch = true;
232         setStateName(upButton, ToolButtonState::Common);
233         messageLabel->setVisible(false);
234     }
235 
236     if (startButton->isHidden()) {
237         isSearchInBegin = false;
238         emit searchDown(searchPhrase, getAndCheckParametrSearch());
239     } else {
240         clickedStart();
241     }
242 }
243 
clickedHide()244 void SearchForm::clickedHide()
245 {
246     hide();
247     emit visibleChanged();
248 }
249 
clickedStart()250 void SearchForm::clickedStart()
251 {
252     changedState(false);
253     isSearchInBegin = true;
254     emit searchInBegin(searchPhrase, getAndCheckParametrSearch());
255 }
256 
clickedSearch()257 void SearchForm::clickedSearch()
258 {
259     isActiveSettings = !isActiveSettings;
260     settings->setVisible(isActiveSettings);
261     useBeginState();
262 
263     if (isActiveSettings) {
264         setStateName(settingsButton, ToolButtonState::Active);
265     } else {
266         setStateName(settingsButton, ToolButtonState::Common);
267         changedState(false);
268     }
269 }
270 
changedState(bool isUpdate)271 void SearchForm::changedState(bool isUpdate)
272 {
273     if (isUpdate) {
274         startButton->setHidden(false);
275         upButton->setHidden(true);
276         downButton->setHidden(true);
277     } else {
278         startButton->setHidden(true);
279         upButton->setHidden(false);
280         downButton->setHidden(false);
281     }
282 
283     useBeginState();
284 }
285 
showMessageNotFound(SearchDirection direction)286 void SearchForm::showMessageNotFound(SearchDirection direction)
287 {
288     if (isSearchInBegin) {
289         if (parameter.period == PeriodSearch::AfterDate) {
290             setStateName(downButton, ToolButtonState::Disabled);
291         } else if (parameter.period == PeriodSearch::BeforeDate) {
292             setStateName(upButton, ToolButtonState::Disabled);
293         } else {
294             setStateName(upButton, ToolButtonState::Disabled);
295             setStateName(downButton, ToolButtonState::Disabled);
296         }
297     } else if (isPrevSearch) {
298         setStateName(upButton, ToolButtonState::Disabled);
299         setStateName(downButton, ToolButtonState::Disabled);
300     } else if (direction == SearchDirection::Up) {
301         setStateName(upButton, ToolButtonState::Disabled);
302     } else {
303         setStateName(downButton, ToolButtonState::Disabled);
304     }
305     messageLabel->setVisible(true);
306 }
307 
LineEdit(QWidget * parent)308 LineEdit::LineEdit(QWidget* parent) : QLineEdit(parent)
309 {
310 }
311 
keyPressEvent(QKeyEvent * event)312 void LineEdit::keyPressEvent(QKeyEvent* event)
313 {
314     int key = event->key();
315 
316     if ((key == Qt::Key_Enter || key == Qt::Key_Return)) {
317         if ((event->modifiers() & Qt::ShiftModifier)) {
318             emit clickShiftEnter();
319         } else {
320             emit clickEnter();
321         }
322     } else if (key == Qt::Key_Escape) {
323         emit clickEsc();
324     }
325 
326     QLineEdit::keyPressEvent(event);
327 }
328 
329 
330