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"
22 #include "FuncRequest.h"
24 #include "qt_helpers.h"
25 #include "Validator.h"
27 #include "ui_BibtexAddUi.h"
29 #include "ButtonPolicy.h"
31 #include "frontends/alert.h"
33 #include "insets/InsetBibtex.h"
35 #include "support/debug.h"
36 #include "support/ExceptionMessage.h"
37 #include "support/FileName.h"
38 #include "support/filetools.h" // changeExtension
39 #include "support/gettext.h"
40 #include "support/lstrings.h"
42 #include <QPushButton>
43 #include <QListWidget>
48 using namespace lyx::support;
54 GuiBibtex::GuiBibtex(GuiView & lv)
55 : GuiDialog(lv, "bibtex", qt_("BibTeX Bibliography")),
56 params_(insetCode("bibtex"))
60 QDialog::setModal(true);
61 setWindowModality(Qt::WindowModal);
63 connect(okPB, SIGNAL(clicked()),
64 this, SLOT(slotOK()));
65 connect(applyPB, SIGNAL(clicked()),
66 this, SLOT(slotApply()));
67 connect(closePB, SIGNAL(clicked()),
68 this, SLOT(slotClose()));
69 connect(stylePB, SIGNAL(clicked()),
70 this, SLOT(browsePressed()));
71 connect(deletePB, SIGNAL(clicked()),
72 this, SLOT(deletePressed()));
73 connect(upPB, SIGNAL(clicked()),
74 this, SLOT(upPressed()));
75 connect(downPB, SIGNAL(clicked()),
76 this, SLOT(downPressed()));
77 connect(styleCB, SIGNAL(editTextChanged(QString)),
78 this, SLOT(change_adaptor()));
79 connect(databaseLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
80 this, SLOT(databaseChanged()));
81 connect(bibtocCB, SIGNAL(clicked()),
82 this, SLOT(change_adaptor()));
83 connect(btPrintCO, SIGNAL(activated(int)),
84 this, SLOT(change_adaptor()));
85 connect(addBibPB, SIGNAL(clicked()),
86 this, SLOT(addPressed()));
87 connect(rescanPB, SIGNAL(clicked()),
88 this, SLOT(rescanClicked()));
89 connect(biblatexOptsLE, SIGNAL(textChanged(QString)),
90 this, SLOT(change_adaptor()));
91 connect(bibEncodingCO, SIGNAL(activated(int)),
92 this, SLOT(change_adaptor()));
94 add_ = new GuiBibtexAddDialog(this);
95 add_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
96 add_bc_.setOK(add_->addPB);
97 add_bc_.setCancel(add_->closePB);
98 add_bc_.addCheckedLineEdit(add_->bibED, 0);
100 connect(add_->bibED, SIGNAL(textChanged(QString)),
101 this, SLOT(bibEDChanged()));
102 connect(add_->addPB, SIGNAL(clicked()),
103 this, SLOT(addDatabase()));
104 connect(add_->addPB, SIGNAL(clicked()),
105 add_, SLOT(accept()));
106 connect(add_->rescanPB, SIGNAL(clicked()),
107 this, SLOT(rescanClicked()));
108 connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
109 this, SLOT(addDatabase()));
110 connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
111 add_, SLOT(accept()));
112 connect(add_->bibLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
113 this, SLOT(availableChanged()));
114 connect(add_->browsePB, SIGNAL(clicked()),
115 this, SLOT(browseBibPressed()));
116 connect(add_->closePB, SIGNAL(clicked()),
117 add_, SLOT(reject()));
119 add_->bibLW->setToolTip(formatToolTip(qt_("This list consists of all databases that are indexed by LaTeX and thus are found without a file path. "
120 "This is usually everything in the bib/ subdirectory of LaTeX's texmf tree. "
121 "If you want to reuse your own database, this is the place you should store it.")));
123 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
125 bc().setApply(applyPB);
126 bc().setCancel(closePB);
127 bc().addReadOnly(databaseLW);
128 bc().addReadOnly(stylePB);
129 bc().addReadOnly(styleCB);
130 bc().addReadOnly(bibtocCB);
131 bc().addReadOnly(addBibPB);
132 bc().addReadOnly(bibEncodingCO);
133 // Delete/Up/Down are handled with more conditions in
134 // databaseChanged().
136 // Always put the default encoding in the first position.
137 bibEncodingCO->addItem(qt_("Document Encoding"), "default");
138 QMap<QString, QString> encodinglist;
139 for (auto const & encvar : encodings) {
140 if (!encvar.unsafe() && !encvar.guiName().empty())
141 encodinglist.insert(qt_(encvar.guiName()), toqstr(encvar.name()));
143 QMap<QString, QString>::const_iterator it = encodinglist.constBegin();
144 while (it != encodinglist.constEnd()) {
145 bibEncodingCO->addItem(it.key(), it.value());
149 // Make sure the delete/up/down buttons are disabled if necessary.
154 void GuiBibtex::bibEDChanged()
156 // Indicate to the button controller that the contents have
157 // changed. The actual test of validity is carried out by
158 // the checkedLineEdit.
159 add_bc_.setValid(true);
163 void GuiBibtex::change_adaptor()
169 void GuiBibtex::browsePressed()
171 QString const file = browseBst(QString());
176 QString const filen = changeExtension(file, "");
177 bool present = false;
178 unsigned int pres = 0;
180 for (int i = 0; i != styleCB->count(); ++i) {
181 if (styleCB->itemText(i) == filen) {
188 styleCB->insertItem(0, filen);
190 styleCB->setCurrentIndex(pres);
195 void GuiBibtex::browseBibPressed()
197 QString const file = browseBib(QString()).trimmed();
202 QString const f = changeExtension(file, "");
203 bool present = false;
205 for (int i = 0; i < add_->bibLW->count(); ++i) {
206 if (add_->bibLW->item(i)->text() == f)
211 add_->bibLW->addItem(f);
215 add_->bibED->setText(f);
219 void GuiBibtex::addPressed()
221 add_bc_.setValid(false);
226 void GuiBibtex::addDatabase()
228 int const sel = add_->bibLW->currentRow();
229 QString const file = add_->bibED->text().trimmed();
231 if (sel < 0 && file.isEmpty())
234 // Add the selected browser_bib keys to browser_database
235 // multiple selections are possible
236 for (int i = 0; i != add_->bibLW->count(); ++i) {
237 QListWidgetItem * const item = add_->bibLW->item(i);
238 if (add_->bibLW->isItemSelected(item)) {
239 add_->bibLW->setItemSelected(item, false);
240 QList<QListWidgetItem *> matches =
241 databaseLW->findItems(item->text(), Qt::MatchExactly);
242 if (matches.empty()) {
243 QString label = item->text();
244 QListWidgetItem * db = new QListWidgetItem(label);
245 db->setFlags(db->flags() | Qt::ItemIsSelectable);
246 databaseLW->addItem(db);
251 if (!file.isEmpty()) {
252 add_->bibED->clear();
253 QString const f = changeExtension(file, "");
254 QList<QListWidgetItem *> matches =
255 databaseLW->findItems(f, Qt::MatchExactly);
256 if (matches.empty()) {
257 QListWidgetItem * db = new QListWidgetItem(f);
258 db->setFlags(db->flags() | Qt::ItemIsSelectable);
259 databaseLW->addItem(db);
268 void GuiBibtex::deletePressed()
270 QListWidgetItem *cur = databaseLW->takeItem(databaseLW->currentRow());
279 void GuiBibtex::upPressed()
281 int row = databaseLW->currentRow();
282 QListWidgetItem *cur = databaseLW->takeItem(row);
283 databaseLW->insertItem(row - 1, cur);
284 databaseLW->setCurrentItem(cur);
289 void GuiBibtex::downPressed()
291 int row = databaseLW->currentRow();
292 QListWidgetItem *cur = databaseLW->takeItem(row);
293 databaseLW->insertItem(row + 1, cur);
294 databaseLW->setCurrentItem(cur);
299 void GuiBibtex::rescanClicked()
306 void GuiBibtex::databaseChanged()
308 bool readOnly = isBufferReadonly();
309 int count = databaseLW->count();
310 int row = databaseLW->currentRow();
311 deletePB->setEnabled(!readOnly && row != -1);
312 upPB->setEnabled(!readOnly && count > 1 && row > 0);
313 downPB->setEnabled(!readOnly && count > 1 && row < count - 1);
317 void GuiBibtex::availableChanged()
319 add_bc_.setValid(true);
323 void GuiBibtex::updateContents()
325 bool bibtopic = usingBibtopic();
326 bool biblatex = usingBiblatex();
329 setTitle(qt_("Biblatex Bibliography"));
331 setTitle(qt_("BibTeX Bibliography"));
335 docstring bibs = params_["bibfiles"];
338 while (!bibs.empty()) {
339 bibs = split(bibs, bib, ',');
342 QListWidgetItem * db = new QListWidgetItem(toqstr(bib));
343 db->setFlags(db->flags() | Qt::ItemIsSelectable);
344 databaseLW->addItem(db);
348 add_->bibLW->clear();
350 QStringList bibfiles = bibFiles();
351 for (int i = 0; i != bibfiles.count(); ++i)
352 add_->bibLW->addItem(changeExtension(bibfiles[i], ""));
354 QString const bibstyle = styleFile();
356 bibtocCB->setChecked(bibtotoc() && !bibtopic);
357 bibtocCB->setEnabled(!bibtopic);
360 btPrintCO->addItem(qt_("all cited references"), toqstr("btPrintCited"));
362 btPrintCO->addItem(qt_("all uncited references"), toqstr("btPrintNotCited"));
363 btPrintCO->addItem(qt_("all references"), toqstr("btPrintAll"));
364 if (usingBiblatex() && !buffer().masterParams().multibib.empty())
365 btPrintCO->addItem(qt_("all reference units"), toqstr("bibbysection"));
367 docstring btprint = params_["btprint"];
370 btprint = from_ascii("btPrintCited");
371 btPrintCO->setCurrentIndex(btPrintCO->findData(toqstr(btprint)));
373 docstring encoding = params_["encoding"];
374 if (encoding.empty())
376 encoding = from_ascii("default");
377 bibEncodingCO->setCurrentIndex(bibEncodingCO->findData(toqstr(encoding)));
379 // Only useful for biblatex
380 biblatexOptsLA->setVisible(biblatex);
381 biblatexOptsLE->setVisible(biblatex);
383 // only useful for BibTeX
384 bstGB->setVisible(!biblatex);
391 QStringList const str = bibStyles();
392 for (int i = 0; i != str.count(); ++i) {
393 QString item = changeExtension(str[i], "");
394 if (item == bibstyle)
396 styleCB->addItem(item);
399 if (item_nr == -1 && !bibstyle.isEmpty()) {
400 styleCB->addItem(bibstyle);
401 item_nr = styleCB->count() - 1;
406 styleCB->setCurrentIndex(item_nr);
408 styleCB->clearEditText();
410 biblatexOptsLE->setText(toqstr(params_["biblatexopts"]));
414 void GuiBibtex::applyView()
418 unsigned int maxCount = databaseLW->count();
419 for (unsigned int i = 0; i < maxCount; i++) {
422 QString item = databaseLW->item(i)->text();
423 docstring bibfile = qstring_to_ucs4(item);
427 params_["bibfiles"] = dbs;
429 docstring const bibstyle = qstring_to_ucs4(styleCB->currentText());
430 bool const bibtotoc = bibtocCB->isChecked();
432 if (bibtotoc && !bibstyle.empty()) {
433 // both bibtotoc and style
434 params_["options"] = "bibtotoc," + bibstyle;
435 } else if (bibtotoc) {
436 // bibtotoc and no style
437 params_["options"] = from_ascii("bibtotoc");
439 // only style. An empty one is valid, because some
440 // documentclasses have an own \bibliographystyle{}
442 params_["options"] = bibstyle;
445 params_["biblatexopts"] = qstring_to_ucs4(biblatexOptsLE->text());
447 params_["btprint"] = qstring_to_ucs4(btPrintCO->itemData(btPrintCO->currentIndex()).toString());
449 params_["encoding"] = qstring_to_ucs4(bibEncodingCO->itemData(bibEncodingCO->currentIndex()).toString());
453 bool GuiBibtex::isValid()
455 return databaseLW->count() != 0;
459 QString GuiBibtex::browseBib(QString const & in_name) const
461 QString const label1 = qt_("D&ocuments");
462 QString const dir1 = toqstr(lyxrc.document_path);
463 QStringList const filter(qt_("BibTeX Databases (*.bib)"));
464 return browseRelToParent(in_name, bufferFilePath(),
465 qt_("Select a BibTeX database to add"), filter, false, label1, dir1);
469 QString GuiBibtex::browseBst(QString const & in_name) const
471 QString const label1 = qt_("D&ocuments");
472 QString const dir1 = toqstr(lyxrc.document_path);
473 QStringList const filter(qt_("BibTeX Styles (*.bst)"));
474 return browseRelToParent(in_name, bufferFilePath(),
475 qt_("Select a BibTeX style"), filter, false, label1, dir1);
479 QStringList GuiBibtex::bibStyles() const
481 QStringList sdata = texFileList("bstFiles.lst");
482 // test whether we have a valid list, otherwise run rescan
483 if (sdata.isEmpty()) {
485 sdata = texFileList("bstFiles.lst");
487 for (int i = 0; i != sdata.size(); ++i)
488 sdata[i] = onlyFileName(sdata[i]);
489 // sort on filename only (no path)
495 QStringList GuiBibtex::bibFiles() const
497 QStringList sdata = texFileList("bibFiles.lst");
498 // test whether we have a valid list, otherwise run rescan
499 if (sdata.isEmpty()) {
501 sdata = texFileList("bibFiles.lst");
503 for (int i = 0; i != sdata.size(); ++i)
504 sdata[i] = onlyFileName(sdata[i]);
505 // sort on filename only (no path)
511 void GuiBibtex::rescanBibStyles() const
514 rescanTexStyles("bib");
516 rescanTexStyles("bst bib");
520 bool GuiBibtex::usingBibtopic() const
522 return buffer().params().useBibtopic();
526 bool GuiBibtex::bibtotoc() const
528 return prefixIs(to_utf8(params_["options"]), "bibtotoc");
532 bool GuiBibtex::usingBiblatex() const
534 return buffer().masterBuffer()->params().useBiblatex();
538 QString GuiBibtex::styleFile() const
540 // the different bibtex packages have (and need) their
541 // own "plain" stylefiles
542 QString defaultstyle = toqstr(buffer().params().defaultBiblioStyle());
544 QString bst = toqstr(params_["options"]);
547 int pos = bst.indexOf(',');
550 // docstring bibtotoc = from_ascii("bibtotoc");
551 // bst = split(bst, bibtotoc, ',');
552 bst = bst.mid(pos + 1);
558 // propose default style file for new insets
559 // existing insets might have (legally) no bst files
560 // (if the class already provides a style)
561 if (bst.isEmpty() && params_["bibfiles"].empty())
568 bool GuiBibtex::initialiseParams(std::string const & sdata)
570 InsetCommand::string2params(sdata, params_);
575 void GuiBibtex::dispatchParams()
577 std::string const lfun = InsetCommand::params2string(params_);
578 dispatch(FuncRequest(getLfun(), lfun));
583 Dialog * createGuiBibtex(GuiView & lv) { return new GuiBibtex(lv); }
586 } // namespace frontend
589 #include "moc_GuiBibtex.cpp"