3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * \author Angus Leeming
10 * Full author contact details are available in file CREDITS.
15 #include "GuiApplication.h"
16 #include "GuiSearch.h"
19 #include "qt_helpers.h"
20 #include "FuncRequest.h"
22 #include "BufferView.h"
25 #include "FuncRequest.h"
27 #include "GuiKeySymbol.h"
30 #include "support/debug.h"
31 #include "support/gettext.h"
32 #include "frontends/alert.h"
33 #include "frontends/Clipboard.h"
39 #include "QSizePolicy"
48 static void uniqueInsert(QComboBox * box, QString const & text)
50 for (int i = box->count(); --i >= 0; )
51 if (box->itemText(i) == text)
54 box->insertItem(0, text);
58 GuiSearchWidget::GuiSearchWidget(QWidget * parent)
63 // fix height to minimum
64 setFixedHeight(sizeHint().height());
66 // align items in grid on top
67 gridLayout->setAlignment(Qt::AlignTop);
69 connect(findPB, SIGNAL(clicked()), this, SLOT(findClicked()));
70 connect(findPrevPB, SIGNAL(clicked()), this, SLOT(findPrevClicked()));
71 connect(minimizePB, SIGNAL(clicked()), this, SLOT(minimizeClicked()));
72 connect(replacePB, SIGNAL(clicked()), this, SLOT(replaceClicked()));
73 connect(replacePrevPB, SIGNAL(clicked()), this, SLOT(replacePrevClicked()));
74 connect(replaceallPB, SIGNAL(clicked()), this, SLOT(replaceallClicked()));
75 connect(findCO, SIGNAL(editTextChanged(QString)),
76 this, SLOT(findChanged()));
77 if(qApp->clipboard()->supportsFindBuffer()) {
78 connect(qApp->clipboard(), SIGNAL(findBufferChanged()),
79 this, SLOT(findBufferChanged()));
83 setFocusProxy(findCO);
85 findCO->setCompleter(nullptr);
86 replaceCO->setCompleter(nullptr);
88 replacePB->setEnabled(false);
89 replacePrevPB->setEnabled(false);
90 replaceallPB->setEnabled(false);
94 void GuiSearchWidget::keyPressEvent(QKeyEvent * ev)
97 setKeySymbol(&sym, ev);
99 // catch Return and Shift-Return
100 if (ev->key() == Qt::Key_Return) {
101 findClicked(ev->modifiers() == Qt::ShiftModifier);
105 // we catch the key sequences for forward and backwards search
107 KeyModifier mod = lyx::q_key_state(ev->modifiers());
108 KeySequence keyseq(&theTopLevelKeymap(), &theTopLevelKeymap());
109 FuncRequest fr = keyseq.addkey(sym, mod);
110 if (fr == FuncRequest(LFUN_WORD_FIND_FORWARD) || fr == FuncRequest(LFUN_WORD_FIND)) {
114 if (fr == FuncRequest(LFUN_WORD_FIND_BACKWARD)) {
118 if (fr == FuncRequest(LFUN_DIALOG_TOGGLE, "findreplace")) {
123 QWidget::keyPressEvent(ev);
127 void GuiSearchWidget::minimizeClicked(bool const toggle)
130 minimized_ = !minimized_;
132 replaceLA->setHidden(minimized_);
133 replaceCO->setHidden(minimized_);
134 replacePB->setHidden(minimized_);
135 replacePrevPB->setHidden(minimized_);
136 replaceallPB->setHidden(minimized_);
137 CBFrame->setHidden(minimized_);
139 minimizePB->setText(qt_("Ex&pand"));
140 minimizePB->setToolTip(qt_("Show replace and option widgets"));
142 minimizePB->setText(qt_("&Minimize"));
143 minimizePB->setToolTip(qt_("Hide replace and option widgets"));
146 Q_EMIT needSizeUpdate();
147 Q_EMIT needTitleBarUpdate();
151 void GuiSearchWidget::showEvent(QShowEvent * e)
155 findCO->lineEdit()->selectAll();
156 QWidget::showEvent(e);
160 void GuiSearchWidget::findBufferChanged()
162 docstring search = theClipboard().getFindBuffer();
163 if (!search.empty()) {
164 LYXERR(Debug::CLIPBOARD, "from findbuffer: " << search);
165 #if QT_VERSION > 0x050000
166 findCO->setCurrentText(toqstr(search));
168 findCO->setEditText(toqstr(search));
174 void GuiSearchWidget::findChanged()
176 bool const emptytext = findCO->currentText().isEmpty();
177 findPB->setEnabled(!emptytext);
178 findPrevPB->setEnabled(!emptytext);
179 bool const replace = !emptytext && bv_ && !bv_->buffer().isReadonly();
180 replacePB->setEnabled(replace);
181 replacePrevPB->setEnabled(replace);
182 replaceallPB->setEnabled(replace);
183 if (instantSearchCB->isChecked() && !emptytext)
188 void GuiSearchWidget::findClicked(bool const backwards)
190 docstring const needle = qstring_to_ucs4(findCO->currentText());
191 find(needle, caseCB->isChecked(), wordsCB->isChecked(), !backwards,
192 instantSearchCB->isChecked(), wrapCB->isChecked());
193 uniqueInsert(findCO, findCO->currentText());
194 if (!instantSearchCB->isChecked())
195 findCO->lineEdit()->selectAll();
199 void GuiSearchWidget::findPrevClicked()
205 void GuiSearchWidget::replaceClicked(bool const backwards)
207 docstring const needle = qstring_to_ucs4(findCO->currentText());
208 docstring const repl = qstring_to_ucs4(replaceCO->currentText());
209 replace(needle, repl, caseCB->isChecked(), wordsCB->isChecked(),
210 !backwards, false, wrapCB->isChecked());
211 uniqueInsert(findCO, findCO->currentText());
212 uniqueInsert(replaceCO, replaceCO->currentText());
216 void GuiSearchWidget::replacePrevClicked()
218 replaceClicked(true);
222 void GuiSearchWidget::replaceallClicked()
224 replace(qstring_to_ucs4(findCO->currentText()),
225 qstring_to_ucs4(replaceCO->currentText()),
226 caseCB->isChecked(), wordsCB->isChecked(), true, true, true);
227 uniqueInsert(findCO, findCO->currentText());
228 uniqueInsert(replaceCO, replaceCO->currentText());
232 void GuiSearchWidget::find(docstring const & search, bool casesensitive,
233 bool matchword, bool forward, bool instant, bool wrap)
235 docstring const sdata =
236 find2string(search, casesensitive, matchword, forward, wrap);
238 // re-query current match
239 dispatch(FuncRequest(LFUN_WORD_BACKWARD));
241 dispatch(FuncRequest(LFUN_WORD_FIND, sdata));
245 void GuiSearchWidget::replace(docstring const & search, docstring const & replace,
246 bool casesensitive, bool matchword,
247 bool forward, bool all, bool wrap)
249 docstring const sdata =
250 replace2string(replace, search, casesensitive,
251 matchword, all, forward, wrap);
252 dispatch(FuncRequest(LFUN_WORD_REPLACE, sdata));
255 void GuiSearchWidget::saveSession(QSettings & settings, QString const & session_key) const
257 settings.setValue(session_key + "/casesensitive", caseCB->isChecked());
258 settings.setValue(session_key + "/words", wordsCB->isChecked());
259 settings.setValue(session_key + "/instant", instantSearchCB->isChecked());
260 settings.setValue(session_key + "/wrap", wrapCB->isChecked());
261 settings.setValue(session_key + "/minimized", minimized_);
265 void GuiSearchWidget::restoreSession(QString const & session_key)
268 caseCB->setChecked(settings.value(session_key + "/casesensitive", false).toBool());
269 wordsCB->setChecked(settings.value(session_key + "/words", false).toBool());
270 instantSearchCB->setChecked(settings.value(session_key + "/instant", false).toBool());
271 wrapCB->setChecked(settings.value(session_key + "/wrap", false).toBool());
272 minimized_ = settings.value(session_key + "/minimized", false).toBool();
273 // initialize hidings
274 minimizeClicked(false);
278 GuiSearch::GuiSearch(GuiView & parent, Qt::DockWidgetArea area, Qt::WindowFlags flags)
279 : DockView(parent, "findreplace", qt_("Search and Replace"), area, flags),
280 widget_(new GuiSearchWidget(this))
283 widget_->setBufferView(bufferview());
284 setFocusProxy(widget_->findCO);
286 connect(widget_, SIGNAL(needTitleBarUpdate()), this, SLOT(updateTitle()));
287 connect(widget_, SIGNAL(needSizeUpdate()), this, SLOT(updateSize()));
290 void GuiSearch::onBufferViewChanged()
292 widget_->setEnabled((bool)bufferview());
293 widget_->setBufferView(bufferview());
297 void GuiSearch::updateView()
304 void GuiSearch::saveSession(QSettings & settings) const
306 Dialog::saveSession(settings);
307 widget_->saveSession(settings, sessionKey());
311 void GuiSearch::restoreSession()
313 DockView::restoreSession();
314 widget_->restoreSession(sessionKey());
318 void GuiSearch::updateTitle()
320 if (widget_->isMinimized()) {
322 setTitleBarWidget(new QWidget());
323 titleBarWidget()->hide();
326 setTitleBarWidget(nullptr);
330 void GuiSearch::updateSize()
332 widget_->setFixedHeight(widget_->sizeHint().height());
333 if (widget_->isMinimized())
334 setFixedHeight(widget_->sizeHint().height());
336 // undo setFixedHeight
337 setMaximumHeight(QWIDGETSIZE_MAX);
344 } // namespace frontend
348 #include "moc_GuiSearch.cpp"