]> git.lyx.org Git - lyx.git/blob - src/frontends/qt/GuiSearch.cpp
28c8ae61245109b4a36b002ac6b4fb1409d3278a
[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         CBGroupBox->setHidden(minimized_);
132         if (minimized_) {
133                 minimizePB->setText(qt_("Ex&pand"));
134                 minimizePB->setToolTip("Show replace and option widgets");
135         } else {
136                 minimizePB->setText(qt_("&Minimize"));
137                 minimizePB->setToolTip("Hide replace and option widgets");
138         }
139
140         Q_EMIT needSizeUpdate();
141         Q_EMIT needTitleBarUpdate();
142 }
143
144
145 void GuiSearchWidget::showEvent(QShowEvent * e)
146 {
147         findChanged();
148         findPB->setFocus();
149         findCO->lineEdit()->selectAll();
150         QWidget::showEvent(e);
151 }
152
153
154 void GuiSearchWidget::findChanged()
155 {
156         findPB->setEnabled(!findCO->currentText().isEmpty());
157         findPrevPB->setEnabled(!findCO->currentText().isEmpty());
158         bool const replace = !findCO->currentText().isEmpty()
159                         && bv_ && !bv_->buffer().isReadonly();
160         replacePB->setEnabled(replace);
161         replacePrevPB->setEnabled(replace);
162         replaceallPB->setEnabled(replace);
163         replaceLA->setEnabled(replace);
164         replaceCO->setEnabled(replace);
165 }
166
167
168 void GuiSearchWidget::findClicked(bool const backwards)
169 {
170         docstring const needle = qstring_to_ucs4(findCO->currentText());
171         find(needle, caseCB->isChecked(), wordsCB->isChecked(), !backwards);
172         uniqueInsert(findCO, findCO->currentText());
173         findCO->lineEdit()->selectAll();
174 }
175
176
177 void GuiSearchWidget::findPrevClicked()
178 {
179         findClicked(true);
180 }
181
182
183 void GuiSearchWidget::replaceClicked(bool const backwards)
184 {
185         docstring const needle = qstring_to_ucs4(findCO->currentText());
186         docstring const repl = qstring_to_ucs4(replaceCO->currentText());
187         replace(needle, repl, caseCB->isChecked(), wordsCB->isChecked(),
188                 !backwards, false);
189         uniqueInsert(findCO, findCO->currentText());
190         uniqueInsert(replaceCO, replaceCO->currentText());
191 }
192
193
194 void GuiSearchWidget::replacePrevClicked()
195 {
196         replaceClicked(true);
197 }
198
199
200 void GuiSearchWidget::replaceallClicked()
201 {
202         replace(qstring_to_ucs4(findCO->currentText()),
203                 qstring_to_ucs4(replaceCO->currentText()),
204                 caseCB->isChecked(), wordsCB->isChecked(), true, true);
205         uniqueInsert(findCO, findCO->currentText());
206         uniqueInsert(replaceCO, replaceCO->currentText());
207 }
208
209
210 void GuiSearchWidget::find(docstring const & search, bool casesensitive,
211                          bool matchword, bool forward)
212 {
213         docstring const sdata =
214                 find2string(search, casesensitive, matchword, forward);
215         dispatch(FuncRequest(LFUN_WORD_FIND, sdata));
216 }
217
218
219 void GuiSearchWidget::replace(docstring const & search, docstring const & replace,
220                             bool casesensitive, bool matchword,
221                             bool forward, bool all)
222 {
223         docstring const sdata =
224                 replace2string(replace, search, casesensitive,
225                                      matchword, all, forward);
226         dispatch(FuncRequest(LFUN_WORD_REPLACE, sdata));
227 }
228
229 void GuiSearchWidget::saveSession(QSettings & settings, QString const & session_key) const
230 {
231         settings.setValue(session_key + "/casesensitive", caseCB->isChecked());
232         settings.setValue(session_key + "/words", wordsCB->isChecked());
233         settings.setValue(session_key + "/minimized", minimized_);
234 }
235
236
237 void GuiSearchWidget::restoreSession(QString const & session_key)
238 {
239         QSettings settings;
240         caseCB->setChecked(settings.value(session_key + "/casesensitive", false).toBool());
241         wordsCB->setChecked(settings.value(session_key + "/words", false).toBool());
242         minimized_ = settings.value(session_key + "/minimized", false).toBool();
243         // initialize hidings
244         minimizeClicked(false);
245 }
246
247
248 GuiSearch::GuiSearch(GuiView & parent, Qt::DockWidgetArea area, Qt::WindowFlags flags)
249         : DockView(parent, "findreplace", qt_("Search and Replace"), area, flags),
250           widget_(new GuiSearchWidget(this))
251 {
252         setWidget(widget_);
253         widget_->setBufferView(bufferview());
254         setFocusProxy(widget_->findCO);
255
256         connect(widget_, SIGNAL(needTitleBarUpdate()), this, SLOT(updateTitle()));
257         connect(widget_, SIGNAL(needSizeUpdate()), this, SLOT(updateSize()));
258 }
259
260 void GuiSearch::onBufferViewChanged()
261 {
262         widget_->setEnabled((bool)bufferview());
263         widget_->setBufferView(bufferview());
264 }
265
266
267 void GuiSearch::updateView()
268 {
269         updateTitle();
270         updateSize();
271 }
272
273
274 void GuiSearch::saveSession(QSettings & settings) const
275 {
276         Dialog::saveSession(settings);
277         widget_->saveSession(settings, sessionKey());
278 }
279
280
281 void GuiSearch::restoreSession()
282 {
283         DockView::restoreSession();
284         widget_->restoreSession(sessionKey());
285 }
286
287
288 void GuiSearch::updateTitle()
289 {
290         if (widget_->isMinimized()) {
291                 // remove title bar
292                 setTitleBarWidget(new QWidget());
293                 titleBarWidget()->hide();
294         } else
295                 // restore title bar
296                 setTitleBarWidget(nullptr);
297 }
298
299
300 void GuiSearch::updateSize()
301 {
302         widget_->setFixedHeight(widget_->sizeHint().height());
303         if (widget_->isMinimized())
304                 // FIXME still a bit too tall
305                 setFixedHeight(widget_->sizeHint().height());
306         else {
307                 // undo setFixedHeight
308                 setMaximumHeight(QWIDGETSIZE_MAX);
309                 setMinimumHeight(0);
310         }
311         update();
312 }
313
314
315 } // namespace frontend
316 } // namespace lyx
317
318
319 #include "moc_GuiSearch.cpp"