]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiCitation.cpp
renaming of some methods that hurt the eyes + removal of:
[lyx.git] / src / frontends / qt4 / GuiCitation.cpp
1 /**
2  * \file GuiCitation.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author Kalle Dalheimer
8  * \author Abdelrazak Younes
9  * \author Richard Heck
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "GuiCitation.h"
17
18 #include "debug.h"
19 #include "gettext.h"
20 #include "frontend_helpers.h"
21 #include "qt_helpers.h"
22
23 #include "support/lstrings.h"
24 #include "support/docstring.h"
25
26 #include <vector>
27 #include <string>
28
29 #include <QCloseEvent>
30
31 #undef KeyPress
32
33 #include <algorithm>
34 #include <string>
35 #include <vector>
36
37 using std::vector;
38 using std::string;
39
40
41 template<typename String>
42 static QStringList to_qstring_list(vector<String> const & v)
43 {
44         QStringList qlist;
45
46         for (size_t i = 0; i != v.size(); ++i) {
47                 if (v[i].empty())
48                         continue;
49                 qlist.append(lyx::toqstr(v[i]));
50         }
51         return qlist;
52 }
53
54
55 static vector<lyx::docstring> to_docstring_vector(QStringList const & qlist)
56 {
57         vector<lyx::docstring> v;
58         for (int i = 0; i != qlist.size(); ++i) {
59                 if (qlist[i].isEmpty())
60                         continue;
61                 v.push_back(lyx::qstring_to_ucs4(qlist[i]));
62         }
63         return v;
64 }
65
66
67 namespace lyx {
68 namespace frontend {
69
70 ///////////////////////////////////////////////////////////////////////
71 //
72 // GuiCitationDialog
73 //
74 ///////////////////////////////////////////////////////////////////////
75
76
77 GuiCitationDialog::GuiCitationDialog(Dialog & dialog, GuiCitation * form)
78         : Dialog::View(dialog, _("Citation")), form_(form)
79 {
80         setupUi(this);
81
82         setWindowTitle(toqstr("LyX: " + getViewTitle()));
83
84         connect(citationStyleCO, SIGNAL(activated(int)),
85                 this, SLOT(changed()));
86         connect(fulllistCB, SIGNAL(clicked()),
87                 this, SLOT(changed()));
88         connect(forceuppercaseCB, SIGNAL(clicked()),
89                 this, SLOT(changed()));
90         connect(textBeforeED, SIGNAL(textChanged(const QString&)),
91                 this, SLOT(changed()));
92         connect(textAfterED, SIGNAL(textChanged(const QString&)),
93                 this, SLOT(changed()));
94         connect(clearPB, SIGNAL(clicked()),
95                 findLE, SLOT(clear()));
96         connect(this, SIGNAL(rejected()), this, SLOT(cleanUp()));
97
98         selectionManager = 
99                 new GuiSelectionManager(availableLV, selectedLV, 
100                                       addPB, deletePB, upPB, downPB, 
101                                       form_->available(), form_->selected());
102         connect(selectionManager, SIGNAL(selectionChanged()),
103                 this, SLOT(setCitedKeys()));
104         connect(selectionManager, SIGNAL(updateHook()),
105                 this, SLOT(updateDialog()));
106         connect(selectionManager, SIGNAL(okHook()),
107                                         this, SLOT(on_okPB_clicked()));
108
109 }
110
111
112 GuiCitationDialog::~GuiCitationDialog()
113 {}
114
115
116 void GuiCitationDialog::cleanUp() 
117 {
118         form_->clearSelection();
119         form_->clearParams();
120         close();
121 }
122
123
124 void GuiCitationDialog::closeEvent(QCloseEvent * e)
125 {
126         form_->clearSelection();
127         form_->clearParams();
128         e->accept();
129 }
130
131
132 void GuiCitationDialog::applyView()
133 {
134         int  const choice = std::max(0, citationStyleCO->currentIndex());
135         style_ = choice;
136         bool const full  = fulllistCB->isChecked();
137         bool const force = forceuppercaseCB->isChecked();
138
139         QString const before = textBeforeED->text();
140         QString const after = textAfterED->text();
141
142         form_->apply(choice, full, force, before, after);
143 }
144
145
146 void GuiCitationDialog::hideView()
147 {
148         form_->clearParams();
149         accept();
150 }
151
152
153 void GuiCitationDialog::showView()
154 {
155         findLE->clear();
156         availableLV->setFocus();
157         QDialog::show();
158         raise();
159         activateWindow();
160 }
161
162
163 bool GuiCitationDialog::isVisibleView() const
164 {
165         return QDialog::isVisible();
166 }
167
168
169 void GuiCitationDialog::on_okPB_clicked()
170 {
171         applyView();
172         form_->clearSelection();
173         hideView();
174 }
175
176
177 void GuiCitationDialog::on_cancelPB_clicked()
178 {
179         form_->clearSelection();
180         hide();
181 }
182
183
184 void GuiCitationDialog::on_applyPB_clicked()
185 {
186         applyView();
187 }
188
189
190 void GuiCitationDialog::on_restorePB_clicked()
191 {
192         form_->init();
193         update();
194 }
195
196
197 void GuiCitationDialog::updateView()
198 {
199         fillFields();
200         fillEntries();
201         updateDialog();
202 }
203
204
205 //The main point of separating this out is that the fill*() methods
206 //called in update() do not need to be called for INTERNAL updates,
207 //such as when addPB is pressed, as the list of fields, entries, etc,
208 //will not have changed. At the moment, however, the division between
209 //fillStyles() and updateStyles() doesn't lend itself to dividing the
210 //two methods, though they should be divisible.
211 void GuiCitationDialog::updateDialog()
212 {
213         if (selectionManager->selectedFocused()) { 
214                 if (selectedLV->selectionModel()->selectedIndexes().isEmpty())
215                         updateInfo(availableLV->currentIndex());
216                 else
217                         updateInfo(selectedLV->currentIndex());
218         } else {
219                 if (availableLV->selectionModel()->selectedIndexes().isEmpty())
220                         updateInfo(QModelIndex());
221                 else
222                         updateInfo(availableLV->currentIndex());
223         }
224         setButtons();
225
226         textBeforeED->setText(form_->textBefore());
227         textAfterED->setText(form_->textAfter());
228         fillStyles();
229         updateStyle();
230 }
231
232
233 void GuiCitationDialog::updateStyle()
234 {
235         biblio::CiteEngine const engine = form_->getEngine();
236         bool const natbib_engine =
237                 engine == biblio::ENGINE_NATBIB_AUTHORYEAR ||
238                 engine == biblio::ENGINE_NATBIB_NUMERICAL;
239         bool const basic_engine = engine == biblio::ENGINE_BASIC;
240
241         bool const haveSelection = 
242                 selectedLV->model()->rowCount() > 0;
243         fulllistCB->setEnabled(natbib_engine && haveSelection);
244         forceuppercaseCB->setEnabled(natbib_engine && haveSelection);
245         textBeforeED->setEnabled(!basic_engine && haveSelection);
246         textBeforeLA->setEnabled(!basic_engine && haveSelection);
247         textAfterED->setEnabled(haveSelection);
248         textAfterLA->setEnabled(haveSelection);
249         citationStyleCO->setEnabled(!basic_engine && haveSelection);
250         citationStyleLA->setEnabled(!basic_engine && haveSelection);
251
252         string const & command = form_->params().getCmdName();
253
254         // Find the style of the citekeys
255         vector<biblio::CiteStyle> const & styles =
256                 ControlCitation::getCiteStyles();
257         biblio::CitationStyle const cs(command);
258
259         vector<biblio::CiteStyle>::const_iterator cit =
260                 std::find(styles.begin(), styles.end(), cs.style);
261
262         // restore the latest natbib style
263         if (style_ >= 0 && style_ < citationStyleCO->count())
264                 citationStyleCO->setCurrentIndex(style_);
265         else
266                 citationStyleCO->setCurrentIndex(0);
267
268         if (cit != styles.end()) {
269                 int const i = int(cit - styles.begin());
270                 citationStyleCO->setCurrentIndex(i);
271                 fulllistCB->setChecked(cs.full);
272                 forceuppercaseCB->setChecked(cs.forceUCase);
273         } else {
274                 fulllistCB->setChecked(false);
275                 forceuppercaseCB->setChecked(false);
276         }
277 }
278
279
280 //This one needs to be called whenever citationStyleCO needs
281 //to be updated---and this would be on anything that changes the
282 //selection in selectedLV, or on a general update.
283 void GuiCitationDialog::fillStyles()
284 {
285         int const oldIndex = citationStyleCO->currentIndex();
286
287         citationStyleCO->clear();
288
289         QStringList selected_keys = form_->selected()->stringList();
290         if (selected_keys.empty()) {
291                 citationStyleCO->setEnabled(false);
292                 citationStyleLA->setEnabled(false);
293                 return;
294         }
295
296         int curr = selectedLV->model()->rowCount() - 1;
297         if (curr < 0)
298                 return;
299
300         if (!selectedLV->selectionModel()->selectedIndexes().empty())
301                 curr = selectedLV->selectionModel()->selectedIndexes()[0].row();
302
303         QStringList sty = form_->citationStyles(curr);
304
305         bool const basic_engine =
306                         (form_->getEngine() == biblio::ENGINE_BASIC);
307
308         citationStyleCO->setEnabled(!sty.isEmpty() && !basic_engine);
309         citationStyleLA->setEnabled(!sty.isEmpty() && !basic_engine);
310
311         if (sty.isEmpty() || basic_engine)
312                 return;
313
314         citationStyleCO->insertItems(0, sty);
315
316         if (oldIndex != -1 && oldIndex < citationStyleCO->count())
317                 citationStyleCO->setCurrentIndex(oldIndex);
318 }
319
320
321 void GuiCitationDialog::fillFields()
322 {
323         fieldsCO->blockSignals(true);
324         int const oldIndex = fieldsCO->currentIndex();
325         fieldsCO->clear();
326         QStringList const & fields = form_->getFieldsAsQStringList();
327         fieldsCO->insertItem(0, qt_("All Fields"));
328         fieldsCO->insertItem(1, qt_("Keys"));
329         fieldsCO->insertItems(2, fields);
330         if (oldIndex != -1 && oldIndex < fieldsCO->count())
331                 fieldsCO->setCurrentIndex(oldIndex);
332         fieldsCO->blockSignals(false);
333 }
334
335
336 void GuiCitationDialog::fillEntries()
337 {
338         entriesCO->blockSignals(true);
339         int const oldIndex = entriesCO->currentIndex();
340         entriesCO->clear();
341         QStringList const & entries = form_->getEntriesAsQStringList();
342         entriesCO->insertItem(0, qt_("All Entry Types"));
343         entriesCO->insertItems(1, entries);
344         if (oldIndex != -1 && oldIndex < entriesCO->count())
345                 entriesCO->setCurrentIndex(oldIndex);
346         entriesCO->blockSignals(false);
347 }
348
349
350 bool GuiCitationDialog::isSelected(const QModelIndex & idx)
351 {
352         QString const str = idx.data().toString();
353         return form_->selected()->stringList().contains(str);
354 }
355
356
357 void GuiCitationDialog::setButtons()
358 {
359         selectionManager->updateView();
360         int const srows = selectedLV->model()->rowCount();
361         applyPB->setEnabled(srows > 0);
362         okPB->setEnabled(srows > 0);
363 }
364
365
366 void GuiCitationDialog::updateInfo(QModelIndex const & idx)
367 {
368         if (idx.isValid()) {
369                 QString const keytxt = form_->getKeyInfo(idx.data().toString());
370                 infoML->document()->setPlainText(keytxt);
371         } else
372                 infoML->document()->clear();
373 }
374
375
376 void GuiCitationDialog::setCitedKeys() 
377 {
378         form_->setCitedKeys();
379 }
380
381
382 void GuiCitationDialog::findText(QString const & text, bool reset)
383 {
384         //"All Fields" and "Keys" are the first two
385         int index = fieldsCO->currentIndex() - 2; 
386         vector<docstring> const & fields = form_->availableFields();
387         docstring field;
388         
389         if (index <= -1 || index >= int(fields.size()))
390                 //either "All Fields" or "Keys" or an invalid value
391                 field = from_ascii("");
392         else
393                 field = fields[index];
394         
395         //Was it "Keys"?
396         bool const onlyKeys = index == -1;
397         
398         //"All Entry Types" is first.
399         index = entriesCO->currentIndex() - 1; 
400         vector<docstring> const & entries = form_->availableEntries();
401         docstring entryType;
402         if (index < 0 || index >= int(entries.size()))
403                 entryType = from_ascii("");
404         else 
405                 entryType = entries[index];
406         
407         bool const case_sentitive = caseCB->checkState();
408         bool const reg_exp = regexCB->checkState();
409         form_->findKey(text, onlyKeys, field, entryType, 
410                        case_sentitive, reg_exp, reset);
411         //FIXME
412         //It'd be nice to save and restore the current selection in 
413         //availableLV. Currently, we get an automatic reset, since the
414         //model is reset.
415         
416         updateDialog();
417 }
418
419
420 void GuiCitationDialog::on_fieldsCO_currentIndexChanged(int /*index*/)
421 {
422         findText(findLE->text(), true);
423 }
424
425
426 void GuiCitationDialog::on_entriesCO_currentIndexChanged(int /*index*/)
427 {
428         findText(findLE->text(), true);
429 }
430
431
432 void GuiCitationDialog::on_findLE_textChanged(const QString & text)
433 {
434         clearPB->setDisabled(text.isEmpty());
435         if (text.isEmpty())
436                 findLE->setFocus();
437         findText(text);
438 }
439
440
441 void GuiCitationDialog::on_caseCB_stateChanged(int)
442 {
443         findText(findLE->text());
444 }
445
446
447 void GuiCitationDialog::on_regexCB_stateChanged(int)
448 {
449         findText(findLE->text());
450 }
451
452
453 void GuiCitationDialog::changed()
454 {
455         fillStyles();
456         setButtons();
457 }
458
459 ///////////////////////////////////////////////////////////////////////
460 //
461 // GuiCitation
462 //
463 ///////////////////////////////////////////////////////////////////////
464
465 GuiCitation::GuiCitation(GuiDialog & parent)
466         : ControlCitation(parent)
467 {
468 }
469
470
471 void GuiCitation::apply(int const choice, bool const full, bool const force,
472                       QString before, QString after)
473 {
474         if (cited_keys_.isEmpty())
475                 return;
476
477         vector<biblio::CiteStyle> const & styles =
478                 ControlCitation::getCiteStyles();
479
480         string const command =
481                 biblio::CitationStyle(styles[choice], full, force)
482                 .asLatexStr();
483
484         params().setCmdName(command);
485         params()["key"] = qstring_to_ucs4(cited_keys_.join(","));
486         params()["before"] = qstring_to_ucs4(before);
487         params()["after"] = qstring_to_ucs4(after);
488         dispatchParams();
489 }
490
491
492 void GuiCitation::clearSelection()
493 {
494         cited_keys_.clear();
495         selected_model_.setStringList(cited_keys_);
496 }
497
498
499 QString GuiCitation::textBefore()
500 {
501         return toqstr(params()["before"]);
502 }
503
504
505 QString GuiCitation::textAfter()
506 {
507         return toqstr(params()["after"]);
508 }
509
510
511 bool GuiCitation::initialiseParams(std::string const & data)
512 {
513         if (!ControlCitation::initialiseParams(data))
514                 return false;
515         init();
516         return true;
517 }
518
519
520 void GuiCitation::init()
521 {
522         // Make the list of all available bibliography keys
523         all_keys_ = to_qstring_list(availableKeys());
524         available_model_.setStringList(all_keys_);
525
526         // Ditto for the keys cited in this inset
527         QString str = toqstr(params()["key"]);
528         if (str.isEmpty())
529                 cited_keys_.clear();
530         else
531                 cited_keys_ = str.split(",");
532         selected_model_.setStringList(cited_keys_);
533 }
534
535
536 void GuiCitation::findKey(QString const & str, bool only_keys,
537         docstring field, docstring entryType,
538         bool case_sensitive, bool reg_exp, bool reset)
539 {
540         // Used for optimisation: store last searched string.
541         static QString last_searched_string;
542         // Used to disable the above optimisation.
543         static bool last_case_sensitive;
544         static bool last_reg_exp;
545         // Reset last_searched_string in case of changed option.
546         if (last_case_sensitive != case_sensitive
547                 || last_reg_exp != reg_exp) {
548                         LYXERR(Debug::GUI) << "GuiCitation::findKey: optimisation disabled!" << std::endl;
549                 last_searched_string.clear();
550         }
551         // save option for next search.
552         last_case_sensitive = case_sensitive;
553         last_reg_exp = reg_exp;
554
555         Qt::CaseSensitivity qtcase = case_sensitive?
556                         Qt::CaseSensitive: Qt::CaseInsensitive;
557         QStringList keys;
558         // If new string (str) contains the last searched one...
559         if (!reset &&
560                 !last_searched_string.isEmpty() &&
561                 str.size() > 1 &&
562                 str.contains(last_searched_string, qtcase))
563                 // ... then only search within already found list.
564                 keys = available_model_.stringList();
565         else
566                 // ... else search all keys.
567                 keys = all_keys_;
568         // save searched string for next search.
569         last_searched_string = str;
570
571         QStringList result;
572         
573         // First, filter by entryType, which will be faster than 
574         // what follows, so we may get to do that on less.
575         vector<docstring> keyVector = to_docstring_vector(keys);
576         filterByEntryType(keyVector, entryType);
577         
578         if (str.isEmpty())
579                 result = to_qstring_list(keyVector);
580         else
581                 result = to_qstring_list(searchKeys(keyVector, only_keys, 
582                         qstring_to_ucs4(str), field, case_sensitive, reg_exp));
583         
584         available_model_.setStringList(result);
585 }
586
587
588 QStringList GuiCitation::getFieldsAsQStringList()
589 {
590         return to_qstring_list(availableFields());
591 }
592
593
594 QStringList GuiCitation::getEntriesAsQStringList()
595 {
596         return to_qstring_list(availableEntries());
597 }
598
599
600 QStringList GuiCitation::citationStyles(int sel)
601 {
602         docstring const key = qstring_to_ucs4(cited_keys_[sel]);
603         return to_qstring_list(getCiteStrings(key));
604 }
605
606
607 QString GuiCitation::getKeyInfo(QString const & sel)
608 {
609         return toqstr(getInfo(qstring_to_ucs4(sel)));
610 }
611
612 void GuiCitation::setCitedKeys() 
613 {
614         cited_keys_ = selected_model_.stringList();
615 }
616
617 } // namespace frontend
618 } // namespace lyx
619
620 #include "GuiCitation_moc.cpp"
621