]> git.lyx.org Git - features.git/blob - src/frontends/qt/GuiThesaurus.cpp
Allow compiling with Qt6
[features.git] / src / frontends / qt / GuiThesaurus.cpp
1 /**
2  * \file GuiThesaurus.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 Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "GuiThesaurus.h"
15 #include "GuiApplication.h"
16
17 #include "qt_helpers.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "BufferView.h"
22 #include "FuncRequest.h"
23 #include "Language.h"
24 #include "lyxfind.h"
25 #include "WordLangTuple.h"
26
27 #include "support/debug.h"
28 #include "support/gettext.h"
29 #include "support/lstrings.h"
30
31 #include <QAbstractItemModel>
32 #include <QCompleter>
33 #include <QDialogButtonBox>
34 #include <QHeaderView>
35 #include <QLineEdit>
36 #include <QPushButton>
37 #include <QTreeWidget>
38 #include <QTreeWidgetItem>
39
40
41 using namespace lyx::support;
42 using namespace std;
43
44 namespace lyx {
45 namespace frontend {
46
47 GuiThesaurus::GuiThesaurus(GuiView & lv)
48         : GuiDialog(lv, "thesaurus", qt_("Thesaurus"))
49 {
50         setupUi(this);
51
52         meaningsTV->setColumnCount(1);
53         meaningsTV->header()->hide();
54
55         connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
56                 this, SLOT(slotButtonBox(QAbstractButton *)));
57         connect(replaceED, SIGNAL(returnPressed()),
58                 this, SLOT(replaceClicked()));
59         connect(replaceED, SIGNAL(textChanged(QString)),
60                 this, SLOT(change_adaptor()));
61         connect(entryCO, SIGNAL(editTextChanged(const QString &)),
62                 this, SLOT(entryChanged()));
63         connect(entryCO, SIGNAL(activated(int)),
64                 this, SLOT(entryChanged()));
65         connect(lookupPB, SIGNAL(clicked()),
66                 this, SLOT(entryChanged()));
67         connect(replacePB, SIGNAL(clicked()),
68                 this, SLOT(replaceClicked()));
69         connect(languageCO, SIGNAL(activated(int)),
70                 this, SLOT(entryChanged()));
71         connect(meaningsTV, SIGNAL(itemClicked(QTreeWidgetItem *, int)),
72                 this, SLOT(itemClicked(QTreeWidgetItem *, int)));
73         connect(meaningsTV, SIGNAL(itemSelectionChanged()),
74                 this, SLOT(selectionChanged()));
75         connect(meaningsTV, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
76                 this, SLOT(selectionClicked(QTreeWidgetItem *, int)));
77
78         // language
79         QAbstractItemModel * language_model = guiApp->languageModel();
80         // FIXME: it would be nice if sorting was enabled/disabled via a checkbox.
81         language_model->sort(0);
82         languageCO->setModel(language_model);
83         languageCO->setModelColumn(2);
84
85         //bug #8138
86         if (entryCO->completer())
87                 entryCO->completer()->setCompletionMode(QCompleter::PopupCompletion);
88
89         bc().setCancel(buttonBox->button(QDialogButtonBox::Close));
90         bc().setApply(replacePB, true);
91         bc().setPolicy(ButtonPolicy::OkApplyCancelReadOnlyPolicy);
92
93         setFocusProxy(entryCO);
94 }
95
96 void GuiThesaurus::checkStatus()
97 {
98         if (!isBufferAvailable()) {
99                 // deactivate the thesaurus if we have no buffer
100                 enableView(false);
101                 return;
102         }
103         updateView();
104 }
105
106 void GuiThesaurus::change_adaptor()
107 {
108         changed();
109 }
110
111
112 void GuiThesaurus::entryChanged()
113 {
114         updateLists();
115 }
116
117
118 void GuiThesaurus::selectionChanged()
119 {
120         int const col = meaningsTV->currentColumn();
121         if (col < 0 || isBufferReadonly())
122                 return;
123
124         QString item = meaningsTV->currentItem()->text(col);
125         // cut out the classification in brackets:
126         // "hominid (generic term)" -> "hominid"
127 #if QT_VERSION < 0x060000
128         QRegExp re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$");
129 #else
130         QRegularExpression re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$");
131 #endif
132         // This is for items with classifications at the beginning:
133         // "(noun) man" -> "man"; "(noun) male (generic term)" -> "male"
134 #if QT_VERSION < 0x060000
135         QRegExp rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$");
136         int pos = re.indexIn(item);
137         if (pos > -1)
138                 item = re.cap(1).trimmed();
139         pos = rex.indexIn(item);
140         if (pos > -1)
141                 item = rex.cap(2).trimmed();
142 #else
143         QRegularExpression rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$");
144         QRegularExpressionMatch match = re.match(item);
145         if (match.hasMatch())
146                 item = match.captured(1).trimmed();
147         match = rex.match(item);
148         if (match.hasMatch())
149                 item = match.captured(2).trimmed();
150 #endif
151         replaceED->setText(item);
152         replacePB->setEnabled(!isBufferReadonly());
153         changed();
154 }
155
156
157 void GuiThesaurus::itemClicked(QTreeWidgetItem * /*item*/, int /*col*/)
158 {
159         selectionChanged();
160 }
161
162
163 void GuiThesaurus::selectionClicked(QTreeWidgetItem * item, int col)
164 {
165         QString str = item->text(col);
166         // cut out the classification in brackets:
167         // "hominid (generic term)" -> "hominid"
168 #if QT_VERSION < 0x060000
169         QRegExp re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$");
170 #else
171         QRegularExpression re("^([^\\(\\)]+)\\b\\(?.*\\)?.*$");
172 #endif
173         // This is for items with classifications at the beginning:
174         // "(noun) man" -> "man"; "(noun) male (generic term)" -> "male"
175 #if QT_VERSION < 0x060000
176         QRegExp rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$");
177         int pos = re.indexIn(str);
178         if (pos > -1)
179                 str = re.cap(1).trimmed();
180         pos = rex.indexIn(str);
181         if (pos > -1)
182                 str = rex.cap(2).trimmed();
183 #else
184         QRegularExpression rex("^(\\(.+\\))\\s*([^\\(\\)]+)\\s*\\(?.*\\)?.*$");
185         QRegularExpressionMatch match = re.match(str);
186         if (match.hasMatch())
187                 str = match.captured(1).trimmed();
188         match = rex.match(str);
189         if (match.hasMatch())
190                 str = match.captured(2).trimmed();
191 #endif
192         entryCO->insertItem(0, str);
193         entryCO->setCurrentIndex(0);
194
195         selectionChanged();
196         updateLists();
197 }
198
199
200 void GuiThesaurus::updateLists()
201 {
202         meaningsTV->clear();
203
204         if (entryCO->currentText().isEmpty())
205                 return;
206
207         meaningsTV->setUpdatesEnabled(false);
208
209         QString const lang = languageCO->itemData(
210                 languageCO->currentIndex()).toString();
211         Language * language = const_cast<Language*>(lyx::languages.getLanguage(fromqstr(lang)));
212         docstring const lang_code = from_ascii(language->code());
213
214         Thesaurus::Meanings meanings =
215                 getMeanings(WordLangTuple(qstring_to_ucs4(entryCO->currentText()), language));
216
217         for (auto const & meaning_p : meanings) {
218                 QTreeWidgetItem * i = new QTreeWidgetItem(meaningsTV);
219                 i->setText(0, toqstr(meaning_p.first));
220                 meaningsTV->expandItem(i);
221                 for (docstring const & word : meaning_p.second) {
222                         QTreeWidgetItem * i2 = new QTreeWidgetItem(i);
223                         i2->setText(0, toqstr(word));
224                 }
225         }
226
227         meaningsTV->setEnabled(!meanings.empty());
228         lookupPB->setEnabled(!meanings.empty());
229         selectionLA->setEnabled(!meanings.empty() && !isBufferReadonly());
230         replaceED->setEnabled(!meanings.empty() && !isBufferReadonly());
231         replacePB->setEnabled(!meanings.empty() && !isBufferReadonly());
232
233         if (meanings.empty() && !thesaurus.thesaurusAvailable(lang_code)) {
234                 QTreeWidgetItem * i = new QTreeWidgetItem(meaningsTV);
235                 i->setText(0, qt_("No thesaurus available for this language!"));
236         }
237
238         meaningsTV->setUpdatesEnabled(true);
239         meaningsTV->update();
240 }
241
242
243 void GuiThesaurus::updateContents()
244 {
245         entryCO->clear();
246         entryCO->addItem(toqstr(text_));
247         entryCO->setCurrentIndex(0);
248         replaceED->setText("");
249         int const pos = languageCO->findData(toqstr(lang_));
250         if (pos != -1)
251                 languageCO->setCurrentIndex(pos);
252         updateLists();
253 }
254
255
256 void GuiThesaurus::replaceClicked()
257 {
258         replace(qstring_to_ucs4(replaceED->text()));
259 }
260
261
262 bool GuiThesaurus::initialiseParams(string const & sdata)
263 {
264         string arg;
265         string const lang = rsplit(sdata, arg, ' ');
266         if (prefixIs(lang, "lang=")) {
267                 lang_ = from_utf8(split(lang, '='));
268                 text_ = from_utf8(arg);
269         } else {
270                 text_ = from_utf8(sdata);
271                 if (bufferview())
272                         lang_ = from_ascii(
273                                 bufferview()->buffer().params().language->lang());
274         }
275         return true;
276 }
277
278
279 void GuiThesaurus::clearParams()
280 {
281         text_.erase();
282         lang_.erase();
283 }
284
285
286 void GuiThesaurus::replace(docstring const & newstr)
287 {
288         /* FIXME: this is not suitable ! We need to have a "lock"
289          * on a particular charpos in a paragraph that is broken on
290          * deletion/change !
291          */
292         docstring const sdata =
293                 replace2string(newstr, text_,
294                                      true,  // case sensitive
295                                      true,  // match word
296                                      false, // all words
297                                      true,  // forward
298                                      false,  // find next
299                                      false,  // auto-wrap
300                                      false); // only selection
301         dispatch(FuncRequest(LFUN_WORD_REPLACE, sdata));
302 }
303
304
305 Thesaurus::Meanings const & GuiThesaurus::getMeanings(WordLangTuple const & wl)
306 {
307         if (wl.word() != laststr_)
308                 meanings_ = thesaurus.lookup(wl);
309         return meanings_;
310 }
311
312
313 } // namespace frontend
314 } // namespace lyx
315
316
317 #include "moc_GuiThesaurus.cpp"