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 btPrintCO->setCurrentIndex(btPrintCO->findData(toqstr(params_["btprint"])));
343 // Only useful for biblatex
344 biblatexOptsLA->setVisible(biblatex);
345 biblatexOptsLE->setVisible(biblatex);
347 // only useful for BibTeX
348 styleCB->setVisible(!biblatex);
349 styleLA->setVisible(!biblatex);
350 stylePB->setVisible(!biblatex);
357 QStringList const str = bibStyles();
358 for (int i = 0; i != str.count(); ++i) {
359 QString item = changeExtension(str[i], "");
360 if (item == bibstyle)
362 styleCB->addItem(item);
365 if (item_nr == -1 && !bibstyle.isEmpty()) {
366 styleCB->addItem(bibstyle);
367 item_nr = styleCB->count() - 1;
372 styleCB->setCurrentIndex(item_nr);
374 styleCB->clearEditText();
376 biblatexOptsLE->setText(toqstr(params_["biblatexopts"]));
380 void GuiBibtex::applyView()
384 unsigned int maxCount = databaseLW->count();
385 for (unsigned int i = 0; i < maxCount; i++) {
388 QString item = databaseLW->item(i)->text();
389 docstring bibfile = qstring_to_ucs4(item);
393 params_["bibfiles"] = dbs;
395 docstring const bibstyle = qstring_to_ucs4(styleCB->currentText());
396 bool const bibtotoc = bibtocCB->isChecked();
398 if (bibtotoc && !bibstyle.empty()) {
399 // both bibtotoc and style
400 params_["options"] = "bibtotoc," + bibstyle;
401 } else if (bibtotoc) {
402 // bibtotoc and no style
403 params_["options"] = from_ascii("bibtotoc");
405 // only style. An empty one is valid, because some
406 // documentclasses have an own \bibliographystyle{}
408 params_["options"] = bibstyle;
411 params_["biblatexopts"] = qstring_to_ucs4(biblatexOptsLE->text());
413 params_["btprint"] = qstring_to_ucs4(btPrintCO->itemData(btPrintCO->currentIndex()).toString());
417 bool GuiBibtex::isValid()
419 return databaseLW->count() != 0;
423 QString GuiBibtex::browseBib(QString const & in_name) const
425 QString const label1 = qt_("Documents|#o#O");
426 QString const dir1 = toqstr(lyxrc.document_path);
427 QStringList const filter(qt_("BibTeX Databases (*.bib)"));
428 return browseRelToParent(in_name, bufferFilePath(),
429 qt_("Select a BibTeX database to add"), filter, false, label1, dir1);
433 QString GuiBibtex::browseBst(QString const & in_name) const
435 QString const label1 = qt_("Documents|#o#O");
436 QString const dir1 = toqstr(lyxrc.document_path);
437 QStringList const filter(qt_("BibTeX Styles (*.bst)"));
438 return browseRelToParent(in_name, bufferFilePath(),
439 qt_("Select a BibTeX style"), filter, false, label1, dir1);
443 QStringList GuiBibtex::bibStyles() const
445 QStringList data = texFileList("bstFiles.lst");
446 // test whether we have a valid list, otherwise run rescan
447 if (data.isEmpty()) {
449 data = texFileList("bstFiles.lst");
451 for (int i = 0; i != data.size(); ++i)
452 data[i] = onlyFileName(data[i]);
453 // sort on filename only (no path)
459 QStringList GuiBibtex::bibFiles() const
461 QStringList data = texFileList("bibFiles.lst");
462 // test whether we have a valid list, otherwise run rescan
463 if (data.isEmpty()) {
465 data = texFileList("bibFiles.lst");
467 for (int i = 0; i != data.size(); ++i)
468 data[i] = onlyFileName(data[i]);
469 // sort on filename only (no path)
475 void GuiBibtex::rescanBibStyles() const
478 rescanTexStyles("bib");
480 rescanTexStyles("bst bib");
484 bool GuiBibtex::usingBibtopic() const
486 return buffer().params().useBibtopic();
490 bool GuiBibtex::bibtotoc() const
492 return prefixIs(to_utf8(params_["options"]), "bibtotoc");
496 bool GuiBibtex::usingBiblatex() const
498 return buffer().masterBuffer()->params().useBiblatex();
502 QString GuiBibtex::styleFile() const
504 // the different bibtex packages have (and need) their
505 // own "plain" stylefiles
506 QString defaultstyle = toqstr(buffer().params().defaultBiblioStyle());
508 QString bst = toqstr(params_["options"]);
511 int pos = bst.indexOf(',');
514 // docstring bibtotoc = from_ascii("bibtotoc");
515 // bst = split(bst, bibtotoc, ',');
516 bst = bst.mid(pos + 1);
522 // propose default style file for new insets
523 // existing insets might have (legally) no bst files
524 // (if the class already provides a style)
525 if (bst.isEmpty() && params_["bibfiles"].empty())
532 bool GuiBibtex::initialiseParams(std::string const & data)
534 InsetCommand::string2params(data, params_);
539 void GuiBibtex::dispatchParams()
541 std::string const lfun = InsetCommand::params2string(params_);
542 dispatch(FuncRequest(getLfun(), lfun));
547 Dialog * createGuiBibtex(GuiView & lv) { return new GuiBibtex(lv); }
550 } // namespace frontend
553 #include "moc_GuiBibtex.cpp"