3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * \author Angus Leeming
9 * \author Jürgen Spitzmüller
11 * Full author contact details are available in file CREDITS.
16 #include "GuiBibtex.h"
19 #include "BufferParams.h"
20 #include "CiteEnginesList.h"
21 #include "FuncRequest.h"
23 #include "qt_helpers.h"
24 #include "Validator.h"
26 #include "ui_BibtexAddUi.h"
28 #include "ButtonPolicy.h"
30 #include "frontends/alert.h"
32 #include "insets/InsetBibtex.h"
34 #include "support/debug.h"
35 #include "support/ExceptionMessage.h"
36 #include "support/FileName.h"
37 #include "support/filetools.h" // changeExtension
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
41 #include <QPushButton>
42 #include <QListWidget>
47 using namespace lyx::support;
53 GuiBibtex::GuiBibtex(GuiView & lv)
54 : GuiDialog(lv, "bibtex", qt_("BibTeX Bibliography")),
55 params_(insetCode("bibtex"))
59 QDialog::setModal(true);
61 connect(okPB, SIGNAL(clicked()),
62 this, SLOT(slotOK()));
63 connect(closePB, SIGNAL(clicked()),
64 this, SLOT(slotClose()));
65 connect(stylePB, SIGNAL(clicked()),
66 this, SLOT(browsePressed()));
67 connect(deletePB, SIGNAL(clicked()),
68 this, SLOT(deletePressed()));
69 connect(upPB, SIGNAL(clicked()),
70 this, SLOT(upPressed()));
71 connect(downPB, SIGNAL(clicked()),
72 this, SLOT(downPressed()));
73 connect(styleCB, SIGNAL(editTextChanged(QString)),
74 this, SLOT(change_adaptor()));
75 connect(databaseLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
76 this, SLOT(databaseChanged()));
77 connect(bibtocCB, SIGNAL(clicked()),
78 this, SLOT(change_adaptor()));
79 connect(btPrintCO, SIGNAL(activated(int)),
80 this, SLOT(change_adaptor()));
81 connect(addBibPB, SIGNAL(clicked()),
82 this, SLOT(addPressed()));
83 connect(rescanPB, SIGNAL(clicked()),
84 this, SLOT(rescanClicked()));
85 connect(biblatexOptsLE, SIGNAL(textChanged(QString)),
86 this, SLOT(change_adaptor()));
88 add_ = new GuiBibtexAddDialog(this);
89 add_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
90 add_bc_.setOK(add_->addPB);
91 add_bc_.setCancel(add_->closePB);
92 add_bc_.addCheckedLineEdit(add_->bibED, 0);
94 connect(add_->bibED, SIGNAL(textChanged(QString)),
95 this, SLOT(bibEDChanged()));
96 connect(add_->addPB, SIGNAL(clicked()),
97 this, SLOT(addDatabase()));
98 connect(add_->addPB, SIGNAL(clicked()),
99 add_, SLOT(accept()));
100 connect(add_->rescanPB, SIGNAL(clicked()),
101 this, SLOT(rescanClicked()));
102 connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
103 this, SLOT(addDatabase()));
104 connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
105 add_, SLOT(accept()));
106 connect(add_->bibLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
107 this, SLOT(availableChanged()));
108 connect(add_->browsePB, SIGNAL(clicked()),
109 this, SLOT(browseBibPressed()));
110 connect(add_->closePB, SIGNAL(clicked()),
111 add_, SLOT(reject()));
113 add_->bibLW->setToolTip(formatToolTip(qt_("This list consists of all databases that are indexed by LaTeX and thus are found without a file path. "
114 "This is usually everything in the bib/ subdirectory of LaTeX's texmf tree. "
115 "If you want to reuse your own database, this is the place you should store it.")));
117 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
119 bc().setCancel(closePB);
120 bc().addReadOnly(databaseLW);
121 bc().addReadOnly(stylePB);
122 bc().addReadOnly(styleCB);
123 bc().addReadOnly(bibtocCB);
124 bc().addReadOnly(addBibPB);
125 // Delete/Up/Down are handled with more conditions in
126 // databaseChanged().
128 // Make sure the delete/up/down buttons are disabled if necessary.
133 void GuiBibtex::bibEDChanged()
135 // Indicate to the button controller that the contents have
136 // changed. The actual test of validity is carried out by
137 // the checkedLineEdit.
138 add_bc_.setValid(true);
142 void GuiBibtex::change_adaptor()
148 void GuiBibtex::browsePressed()
150 QString const file = browseBst(QString());
155 QString const filen = changeExtension(file, "");
156 bool present = false;
157 unsigned int pres = 0;
159 for (int i = 0; i != styleCB->count(); ++i) {
160 if (styleCB->itemText(i) == filen) {
167 styleCB->insertItem(0, filen);
169 styleCB->setCurrentIndex(pres);
174 void GuiBibtex::browseBibPressed()
176 QString const file = browseBib(QString()).trimmed();
181 QString const f = changeExtension(file, "");
182 bool present = false;
184 for (int i = 0; i < add_->bibLW->count(); ++i) {
185 if (add_->bibLW->item(i)->text() == f)
190 add_->bibLW->addItem(f);
194 add_->bibED->setText(f);
198 void GuiBibtex::addPressed()
200 add_bc_.setValid(false);
205 void GuiBibtex::addDatabase()
207 int const sel = add_->bibLW->currentRow();
208 QString const file = add_->bibED->text().trimmed();
210 if (sel < 0 && file.isEmpty())
213 // Add the selected browser_bib keys to browser_database
214 // multiple selections are possible
215 for (int i = 0; i != add_->bibLW->count(); ++i) {
216 QListWidgetItem * const item = add_->bibLW->item(i);
217 if (add_->bibLW->isItemSelected(item)) {
218 add_->bibLW->setItemSelected(item, false);
219 QList<QListWidgetItem *> matches =
220 databaseLW->findItems(item->text(), Qt::MatchExactly);
221 if (matches.empty()) {
222 QString label = item->text();
223 QListWidgetItem * db = new QListWidgetItem(label);
224 db->setFlags(db->flags() | Qt::ItemIsSelectable);
225 databaseLW->addItem(db);
230 if (!file.isEmpty()) {
231 add_->bibED->clear();
232 QString const f = changeExtension(file, "");
233 QList<QListWidgetItem *> matches =
234 databaseLW->findItems(f, Qt::MatchExactly);
235 if (matches.empty()) {
236 QListWidgetItem * db = new QListWidgetItem(f);
237 db->setFlags(db->flags() | Qt::ItemIsSelectable);
238 databaseLW->addItem(db);
247 void GuiBibtex::deletePressed()
249 QListWidgetItem *cur = databaseLW->takeItem(databaseLW->currentRow());
258 void GuiBibtex::upPressed()
260 int row = databaseLW->currentRow();
261 QListWidgetItem *cur = databaseLW->takeItem(row);
262 databaseLW->insertItem(row - 1, cur);
263 databaseLW->setCurrentItem(cur);
268 void GuiBibtex::downPressed()
270 int row = databaseLW->currentRow();
271 QListWidgetItem *cur = databaseLW->takeItem(row);
272 databaseLW->insertItem(row + 1, cur);
273 databaseLW->setCurrentItem(cur);
278 void GuiBibtex::rescanClicked()
285 void GuiBibtex::databaseChanged()
287 bool readOnly = isBufferReadonly();
288 int count = databaseLW->count();
289 int row = databaseLW->currentRow();
290 deletePB->setEnabled(!readOnly && row != -1);
291 upPB->setEnabled(!readOnly && count > 1 && row > 0);
292 downPB->setEnabled(!readOnly && count > 1 && row < count - 1);
296 void GuiBibtex::availableChanged()
298 add_bc_.setValid(true);
302 void GuiBibtex::updateContents()
304 bool bibtopic = usingBibtopic();
305 bool biblatex = usingBiblatex();
309 docstring bibs = params_["bibfiles"];
312 while (!bibs.empty()) {
313 bibs = split(bibs, bib, ',');
316 QListWidgetItem * db = new QListWidgetItem(toqstr(bib));
317 db->setFlags(db->flags() | Qt::ItemIsSelectable);
318 databaseLW->addItem(db);
322 add_->bibLW->clear();
324 QStringList bibfiles = bibFiles();
325 for (int i = 0; i != bibfiles.count(); ++i)
326 add_->bibLW->addItem(changeExtension(bibfiles[i], ""));
328 QString const bibstyle = styleFile();
330 bibtocCB->setChecked(bibtotoc() && !bibtopic);
331 bibtocCB->setEnabled(!bibtopic);
334 btPrintCO->addItem(qt_("all cited references"), toqstr("btPrintCited"));
336 btPrintCO->addItem(qt_("all uncited references"), toqstr("btPrintNotCited"));
337 btPrintCO->addItem(qt_("all references"), toqstr("btPrintAll"));
338 if (usingBiblatex() && !buffer().masterParams().multibib.empty())
339 btPrintCO->addItem(qt_("all reference units"), toqstr("bibbysection"));
341 docstring btprint = params_["btprint"];
344 btprint = from_ascii("btPrintCited");
345 btPrintCO->setCurrentIndex(btPrintCO->findData(toqstr(btprint)));
347 // Only useful for biblatex
348 biblatexOptsLA->setVisible(biblatex);
349 biblatexOptsLE->setVisible(biblatex);
351 // only useful for BibTeX
352 styleCB->setVisible(!biblatex);
353 styleLA->setVisible(!biblatex);
354 stylePB->setVisible(!biblatex);
361 QStringList const str = bibStyles();
362 for (int i = 0; i != str.count(); ++i) {
363 QString item = changeExtension(str[i], "");
364 if (item == bibstyle)
366 styleCB->addItem(item);
369 if (item_nr == -1 && !bibstyle.isEmpty()) {
370 styleCB->addItem(bibstyle);
371 item_nr = styleCB->count() - 1;
376 styleCB->setCurrentIndex(item_nr);
378 styleCB->clearEditText();
380 biblatexOptsLE->setText(toqstr(params_["biblatexopts"]));
384 void GuiBibtex::applyView()
388 unsigned int maxCount = databaseLW->count();
389 for (unsigned int i = 0; i < maxCount; i++) {
392 QString item = databaseLW->item(i)->text();
393 docstring bibfile = qstring_to_ucs4(item);
397 params_["bibfiles"] = dbs;
399 docstring const bibstyle = qstring_to_ucs4(styleCB->currentText());
400 bool const bibtotoc = bibtocCB->isChecked();
402 if (bibtotoc && !bibstyle.empty()) {
403 // both bibtotoc and style
404 params_["options"] = "bibtotoc," + bibstyle;
405 } else if (bibtotoc) {
406 // bibtotoc and no style
407 params_["options"] = from_ascii("bibtotoc");
409 // only style. An empty one is valid, because some
410 // documentclasses have an own \bibliographystyle{}
412 params_["options"] = bibstyle;
415 params_["biblatexopts"] = qstring_to_ucs4(biblatexOptsLE->text());
417 params_["btprint"] = qstring_to_ucs4(btPrintCO->itemData(btPrintCO->currentIndex()).toString());
421 bool GuiBibtex::isValid()
423 return databaseLW->count() != 0;
427 QString GuiBibtex::browseBib(QString const & in_name) const
429 QString const label1 = qt_("Documents|#o#O");
430 QString const dir1 = toqstr(lyxrc.document_path);
431 QStringList const filter(qt_("BibTeX Databases (*.bib)"));
432 return browseRelToParent(in_name, bufferFilePath(),
433 qt_("Select a BibTeX database to add"), filter, false, label1, dir1);
437 QString GuiBibtex::browseBst(QString const & in_name) const
439 QString const label1 = qt_("Documents|#o#O");
440 QString const dir1 = toqstr(lyxrc.document_path);
441 QStringList const filter(qt_("BibTeX Styles (*.bst)"));
442 return browseRelToParent(in_name, bufferFilePath(),
443 qt_("Select a BibTeX style"), filter, false, label1, dir1);
447 QStringList GuiBibtex::bibStyles() const
449 QStringList data = texFileList("bstFiles.lst");
450 // test whether we have a valid list, otherwise run rescan
451 if (data.isEmpty()) {
453 data = texFileList("bstFiles.lst");
455 for (int i = 0; i != data.size(); ++i)
456 data[i] = onlyFileName(data[i]);
457 // sort on filename only (no path)
463 QStringList GuiBibtex::bibFiles() const
465 QStringList data = texFileList("bibFiles.lst");
466 // test whether we have a valid list, otherwise run rescan
467 if (data.isEmpty()) {
469 data = texFileList("bibFiles.lst");
471 for (int i = 0; i != data.size(); ++i)
472 data[i] = onlyFileName(data[i]);
473 // sort on filename only (no path)
479 void GuiBibtex::rescanBibStyles() const
482 rescanTexStyles("bib");
484 rescanTexStyles("bst bib");
488 bool GuiBibtex::usingBibtopic() const
490 return buffer().params().useBibtopic();
494 bool GuiBibtex::bibtotoc() const
496 return prefixIs(to_utf8(params_["options"]), "bibtotoc");
500 bool GuiBibtex::usingBiblatex() const
502 return buffer().masterBuffer()->params().useBiblatex();
506 QString GuiBibtex::styleFile() const
508 // the different bibtex packages have (and need) their
509 // own "plain" stylefiles
510 QString defaultstyle = toqstr(buffer().params().defaultBiblioStyle());
512 QString bst = toqstr(params_["options"]);
515 int pos = bst.indexOf(',');
518 // docstring bibtotoc = from_ascii("bibtotoc");
519 // bst = split(bst, bibtotoc, ',');
520 bst = bst.mid(pos + 1);
526 // propose default style file for new insets
527 // existing insets might have (legally) no bst files
528 // (if the class already provides a style)
529 if (bst.isEmpty() && params_["bibfiles"].empty())
536 bool GuiBibtex::initialiseParams(std::string const & data)
538 InsetCommand::string2params(data, params_);
543 void GuiBibtex::dispatchParams()
545 std::string const lfun = InsetCommand::params2string(params_);
546 dispatch(FuncRequest(getLfun(), lfun));
551 Dialog * createGuiBibtex(GuiView & lv) { return new GuiBibtex(lv); }
554 } // namespace frontend
557 #include "moc_GuiBibtex.cpp"