]> git.lyx.org Git - lyx.git/blob - src/frontends/qt/GuiSearch.cpp
Transform simple search dialog to dock widget (#2625)
[lyx.git] / src / frontends / qt / GuiSearch.cpp
1 /**
2  * \file GuiSearch.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Edwin Leuven
8  * \author Angus Leeming
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiSearch.h"
16
17 #include "lyxfind.h"
18 #include "qt_helpers.h"
19 #include "FuncRequest.h"
20 #include "LyX.h"
21 #include "BufferView.h"
22 #include "Buffer.h"
23 #include "Cursor.h"
24 #include "FuncRequest.h"
25 #include "KeyMap.h"
26 #include "GuiKeySymbol.h"
27 #include "GuiView.h"
28
29 #include "support/debug.h"
30 #include "support/gettext.h"
31 #include "frontends/alert.h"
32
33 #include <QLineEdit>
34 #include <QSettings>
35 #include <QShowEvent>
36 #include "QSizePolicy"
37
38 using namespace std;
39
40 using lyx::KeySymbol;
41
42 namespace lyx {
43 namespace frontend {
44
45 static void uniqueInsert(QComboBox * box, QString const & text)
46 {
47         for (int i = box->count(); --i >= 0; )
48                 if (box->itemText(i) == text)
49                         return;
50
51         box->insertItem(0, text);
52 }
53
54
55 GuiSearchWidget::GuiSearchWidget(QWidget * parent)
56         :       QWidget(parent)
57 {
58         setupUi(this);
59
60         // fix height to minimum
61         setFixedHeight(sizeHint().height());
62
63         // align items in grid on top
64         gridLayout->setAlignment(Qt::AlignTop);
65
66         connect(findPB, SIGNAL(clicked()), this, SLOT(findClicked()));
67         connect(findPrevPB, SIGNAL(clicked()), this, SLOT(findPrevClicked()));
68         connect(minimizePB, SIGNAL(clicked()), this, SLOT(minimizeClicked()));
69         connect(replacePB, SIGNAL(clicked()), this, SLOT(replaceClicked()));
70         connect(replacePrevPB, SIGNAL(clicked()), this, SLOT(replacePrevClicked()));
71         connect(replaceallPB, SIGNAL(clicked()), this, SLOT(replaceallClicked()));
72         connect(findCO, SIGNAL(editTextChanged(QString)),
73                 this, SLOT(findChanged()));
74
75         setFocusProxy(findCO);
76
77         findCO->setCompleter(0);
78         replaceCO->setCompleter(0);
79
80         replacePB->setEnabled(false);
81         replacePrevPB->setEnabled(false);
82         replaceallPB->setEnabled(false);
83 }
84
85
86 void GuiSearchWidget::keyPressEvent(QKeyEvent * ev)
87 {
88         KeySymbol sym;
89         setKeySymbol(&sym, ev);
90
91         // catch Return and Shift-Return
92         if (ev->key() == Qt::Key_Return) {
93                 findClicked(ev->modifiers() == Qt::ShiftModifier);
94                 return;
95         }
96
97         // we catch the key sequences for forward and backwards search
98         if (sym.isOK()) {
99                 KeyModifier mod = lyx::q_key_state(ev->modifiers());
100                 KeySequence keyseq(&theTopLevelKeymap(), &theTopLevelKeymap());
101                 FuncRequest fr = keyseq.addkey(sym, mod);
102                 if (fr == FuncRequest(LFUN_WORD_FIND_FORWARD) || fr == FuncRequest(LFUN_WORD_FIND)) {
103                         findClicked();
104                         return;
105                 }
106                 if (fr == FuncRequest(LFUN_WORD_FIND_BACKWARD)) {
107                         findClicked(true);
108                         return;
109                 }
110                 if (fr == FuncRequest(LFUN_DIALOG_TOGGLE, "findreplace")) {
111                         dispatch(fr);
112                         return;
113                 }
114         }
115         QWidget::keyPressEvent(ev);
116 }
117
118
119 void GuiSearchWidget::minimizeClicked(bool const toggle)
120 {
121         if (toggle)
122                 minimized_ = !minimized_;
123
124         replaceLA->setHidden(minimized_);
125         replaceCO->setHidden(minimized_);
126         replacePB->setHidden(minimized_);
127         replacePrevPB->setHidden(minimized_);
128         replaceallPB->setHidden(minimized_);
129         wordsCB->setHidden(minimized_);
130         caseCB->setHidden(minimized_);
131         if (minimized_) {
132                 minimizePB->setText(qt_("Ex&pand"));
133                 minimizePB->setToolTip("Show replace and option widgets");
134         } else {
135                 minimizePB->setText(qt_("&Minimize"));
136                 minimizePB->setToolTip("Hide replace and option widgets");
137         }
138
139         Q_EMIT needSizeUpdate();
140         Q_EMIT needTitleBarUpdate();
141 }
142
143
144 void GuiSearchWidget::showEvent(QShowEvent * e)
145 {
146         findChanged();
147         findPB->setFocus();
148         findCO->lineEdit()->selectAll();
149         QWidget::showEvent(e);
150 }
151
152
153 void GuiSearchWidget::findChanged()
154 {
155         findPB->setEnabled(!findCO->currentText().isEmpty());
156         findPrevPB->setEnabled(!findCO->currentText().isEmpty());
157         bool const replace = !findCO->currentText().isEmpty()
158                         && bv_ && !bv_->buffer().isReadonly();
159         replacePB->setEnabled(replace);
160         replacePrevPB->setEnabled(replace);
161         replaceallPB->setEnabled(replace);
162         replaceLA->setEnabled(replace);
163         replaceCO->setEnabled(replace);
164 }
165
166
167 void GuiSearchWidget::findClicked(bool const backwards)
168 {
169         docstring const needle = qstring_to_ucs4(findCO->currentText());
170         find(needle, caseCB->isChecked(), wordsCB->isChecked(), !backwards);
171         uniqueInsert(findCO, findCO->currentText());
172         findCO->lineEdit()->selectAll();
173 }
174
175
176 void GuiSearchWidget::findPrevClicked()
177 {
178         findClicked(true);
179 }
180
181
182 void GuiSearchWidget::replaceClicked(bool const backwards)
183 {
184         docstring const needle = qstring_to_ucs4(findCO->currentText());
185         docstring const repl = qstring_to_ucs4(replaceCO->currentText());
186         replace(needle, repl, caseCB->isChecked(), wordsCB->isChecked(),
187                 !backwards, false);
188         uniqueInsert(findCO, findCO->currentText());
189         uniqueInsert(replaceCO, replaceCO->currentText());
190 }
191
192
193 void GuiSearchWidget::replacePrevClicked()
194 {
195         replaceClicked(true);
196 }
197
198
199 void GuiSearchWidget::replaceallClicked()
200 {
201         replace(qstring_to_ucs4(findCO->currentText()),
202                 qstring_to_ucs4(replaceCO->currentText()),
203                 caseCB->isChecked(), wordsCB->isChecked(), true, true);
204         uniqueInsert(findCO, findCO->currentText());
205         uniqueInsert(replaceCO, replaceCO->currentText());
206 }
207
208
209 void GuiSearchWidget::find(docstring const & search, bool casesensitive,
210                          bool matchword, bool forward)
211 {
212         docstring const sdata =
213                 find2string(search, casesensitive, matchword, forward);
214         dispatch(FuncRequest(LFUN_WORD_FIND, sdata));
215 }
216
217
218 void GuiSearchWidget::replace(docstring const & search, docstring const & replace,
219                             bool casesensitive, bool matchword,
220                             bool forward, bool all)
221 {
222         docstring const sdata =
223                 replace2string(replace, search, casesensitive,
224                                      matchword, all, forward);
225         dispatch(FuncRequest(LFUN_WORD_REPLACE, sdata));
226 }
227
228 void GuiSearchWidget::saveSession(QSettings & settings, QString const & session_key) const
229 {
230         settings.setValue(session_key + "/casesensitive", caseCB->isChecked());
231         settings.setValue(session_key + "/words", wordsCB->isChecked());
232         settings.setValue(session_key + "/minimized", minimized_);
233 }
234
235
236 void GuiSearchWidget::restoreSession(QString const & session_key)
237 {
238         QSettings settings;
239         caseCB->setChecked(settings.value(session_key + "/casesensitive", false).toBool());
240         wordsCB->setChecked(settings.value(session_key + "/words", false).toBool());
241         minimized_ = settings.value(session_key + "/minimized", false).toBool();
242         // initialize hidings
243         minimizeClicked(false);
244 }
245
246
247 GuiSearch::GuiSearch(GuiView & parent, Qt::DockWidgetArea area, Qt::WindowFlags flags)
248         : DockView(parent, "findreplace", qt_("Search and Replace"), area, flags),
249           widget_(new GuiSearchWidget(this))
250 {
251         setWidget(widget_);
252         widget_->setBufferView(bufferview());
253         setFocusProxy(widget_->findCO);
254
255         connect(widget_, SIGNAL(needTitleBarUpdate()), this, SLOT(updateTitle()));
256         connect(widget_, SIGNAL(needSizeUpdate()), this, SLOT(updateSize()));
257 }
258
259 void GuiSearch::onBufferViewChanged()
260 {
261         widget_->setEnabled((bool)bufferview());
262         widget_->setBufferView(bufferview());
263 }
264
265
266 void GuiSearch::updateView()
267 {
268         updateTitle();
269         updateSize();
270 }
271
272
273 void GuiSearch::saveSession(QSettings & settings) const
274 {
275         Dialog::saveSession(settings);
276         widget_->saveSession(settings, sessionKey());
277 }
278
279
280 void GuiSearch::restoreSession()
281 {
282         DockView::restoreSession();
283         widget_->restoreSession(sessionKey());
284 }
285
286
287 void GuiSearch::updateTitle()
288 {
289         if (widget_->isMinimized()) {
290                 // remove title bar
291                 setTitleBarWidget(new QWidget());
292                 titleBarWidget()->hide();
293         } else
294                 // restore title bar
295                 setTitleBarWidget(nullptr);
296 }
297
298
299 void GuiSearch::updateSize()
300 {
301         widget_->setFixedHeight(widget_->sizeHint().height());
302         if (widget_->isMinimized())
303                 // FIXME still a bit too tall
304                 setFixedHeight(widget_->sizeHint().height());
305         else {
306                 // undo setFixedHeight
307                 setMaximumHeight(QWIDGETSIZE_MAX);
308                 setMinimumHeight(0);
309         }
310         update();
311 }
312
313
314 } // namespace frontend
315 } // namespace lyx
316
317
318 #include "moc_GuiSearch.cpp"