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 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
115 bc().setCancel(closePB);
116 bc().addReadOnly(databaseLW);
117 bc().addReadOnly(stylePB);
118 bc().addReadOnly(styleCB);
119 bc().addReadOnly(bibtocCB);
120 bc().addReadOnly(addBibPB);
121 // Delete/Up/Down are handled with more conditions in
122 // databaseChanged().
124 // Make sure the delete/up/down buttons are disabled if necessary.
129 void GuiBibtex::bibEDChanged()
131 // Indicate to the button controller that the contents have
132 // changed. The actual test of validity is carried out by
133 // the checkedLineEdit.
134 add_bc_.setValid(true);
138 void GuiBibtex::change_adaptor()
144 void GuiBibtex::browsePressed()
146 QString const file = browseBst(QString());
151 QString const filen = changeExtension(file, "");
152 bool present = false;
153 unsigned int pres = 0;
155 for (int i = 0; i != styleCB->count(); ++i) {
156 if (styleCB->itemText(i) == filen) {
163 styleCB->insertItem(0, filen);
165 styleCB->setCurrentIndex(pres);
170 void GuiBibtex::browseBibPressed()
172 QString const file = browseBib(QString()).trimmed();
177 QString const f = changeExtension(file, "");
178 bool present = false;
180 for (int i = 0; i < add_->bibLW->count(); ++i) {
181 if (add_->bibLW->item(i)->text() == f)
186 add_->bibLW->addItem(f);
190 add_->bibED->setText(f);
194 void GuiBibtex::addPressed()
196 add_bc_.setValid(false);
201 void GuiBibtex::addDatabase()
203 int const sel = add_->bibLW->currentRow();
204 QString const file = add_->bibED->text().trimmed();
206 if (sel < 0 && file.isEmpty())
209 // Add the selected browser_bib keys to browser_database
210 // multiple selections are possible
211 for (int i = 0; i != add_->bibLW->count(); ++i) {
212 QListWidgetItem * const item = add_->bibLW->item(i);
213 if (add_->bibLW->isItemSelected(item)) {
214 add_->bibLW->setItemSelected(item, false);
215 QList<QListWidgetItem *> matches =
216 databaseLW->findItems(item->text(), Qt::MatchExactly);
217 if (matches.empty()) {
218 QString label = item->text();
219 QListWidgetItem * db = new QListWidgetItem(label);
220 db->setFlags(db->flags() | Qt::ItemIsSelectable);
221 databaseLW->addItem(db);
226 if (!file.isEmpty()) {
227 add_->bibED->clear();
228 QString const f = changeExtension(file, "");
229 QList<QListWidgetItem *> matches =
230 databaseLW->findItems(f, Qt::MatchExactly);
231 if (matches.empty()) {
232 QListWidgetItem * db = new QListWidgetItem(f);
233 db->setFlags(db->flags() | Qt::ItemIsSelectable);
234 databaseLW->addItem(db);
243 void GuiBibtex::deletePressed()
245 QListWidgetItem *cur = databaseLW->takeItem(databaseLW->currentRow());
254 void GuiBibtex::upPressed()
256 int row = databaseLW->currentRow();
257 QListWidgetItem *cur = databaseLW->takeItem(row);
258 databaseLW->insertItem(row - 1, cur);
259 databaseLW->setCurrentItem(cur);
264 void GuiBibtex::downPressed()
266 int row = databaseLW->currentRow();
267 QListWidgetItem *cur = databaseLW->takeItem(row);
268 databaseLW->insertItem(row + 1, cur);
269 databaseLW->setCurrentItem(cur);
274 void GuiBibtex::rescanClicked()
281 void GuiBibtex::databaseChanged()
283 bool readOnly = isBufferReadonly();
284 int count = databaseLW->count();
285 int row = databaseLW->currentRow();
286 deletePB->setEnabled(!readOnly && row != -1);
287 upPB->setEnabled(!readOnly && count > 1 && row > 0);
288 downPB->setEnabled(!readOnly && count > 1 && row < count - 1);
292 void GuiBibtex::availableChanged()
294 add_bc_.setValid(true);
298 void GuiBibtex::updateContents()
300 bool bibtopic = usingBibtopic();
301 bool biblatex = usingBiblatex();
305 docstring bibs = params_["bibfiles"];
308 while (!bibs.empty()) {
309 bibs = split(bibs, bib, ',');
312 QListWidgetItem * db = new QListWidgetItem(toqstr(bib));
313 db->setFlags(db->flags() | Qt::ItemIsSelectable);
314 databaseLW->addItem(db);
318 add_->bibLW->clear();
320 QStringList bibfiles = bibFiles();
321 for (int i = 0; i != bibfiles.count(); ++i)
322 add_->bibLW->addItem(changeExtension(bibfiles[i], ""));
324 QString const bibstyle = styleFile();
326 bibtocCB->setChecked(bibtotoc() && !bibtopic);
327 bibtocCB->setEnabled(!bibtopic);
329 if (!bibtopic && btPrintCO->count() == 3)
330 btPrintCO->removeItem(1);
331 else if (bibtopic && btPrintCO->count() < 3)
332 btPrintCO->insertItem(1, qt_("all uncited references", 0));
334 docstring const & btprint = params_["btprint"];
336 if ((bibtopic && btprint == from_ascii("btPrintNotCited")) ||
337 (!bibtopic && btprint == from_ascii("btPrintAll")))
339 else if (bibtopic && btprint == from_ascii("btPrintAll"))
342 btPrintCO->setCurrentIndex(btp);
344 // Only useful for biblatex
345 biblatexOptsLA->setVisible(biblatex);
346 biblatexOptsLE->setVisible(biblatex);
348 // only useful for BibTeX
349 styleCB->setVisible(!biblatex);
350 styleLA->setVisible(!biblatex);
351 stylePB->setVisible(!biblatex);
358 QStringList const str = bibStyles();
359 for (int i = 0; i != str.count(); ++i) {
360 QString item = changeExtension(str[i], "");
361 if (item == bibstyle)
363 styleCB->addItem(item);
366 if (item_nr == -1 && !bibstyle.isEmpty()) {
367 styleCB->addItem(bibstyle);
368 item_nr = styleCB->count() - 1;
373 styleCB->setCurrentIndex(item_nr);
375 styleCB->clearEditText();
377 biblatexOptsLE->setText(toqstr(params_["biblatexopts"]));
381 void GuiBibtex::applyView()
385 unsigned int maxCount = databaseLW->count();
386 for (unsigned int i = 0; i < maxCount; i++) {
389 QString item = databaseLW->item(i)->text();
390 docstring bibfile = qstring_to_ucs4(item);
394 params_["bibfiles"] = dbs;
396 docstring const bibstyle = qstring_to_ucs4(styleCB->currentText());
397 bool const bibtotoc = bibtocCB->isChecked();
399 if (bibtotoc && !bibstyle.empty()) {
400 // both bibtotoc and style
401 params_["options"] = "bibtotoc," + bibstyle;
402 } else if (bibtotoc) {
403 // bibtotoc and no style
404 params_["options"] = from_ascii("bibtotoc");
406 // only style. An empty one is valid, because some
407 // documentclasses have an own \bibliographystyle{}
409 params_["options"] = bibstyle;
412 params_["biblatexopts"] = qstring_to_ucs4(biblatexOptsLE->text());
414 int btp = btPrintCO->currentIndex();
416 if (usingBibtopic()) {
417 // bibtopic allows three kinds of sections:
418 // 1. sections that include all cited references of the database(s)
419 // 2. sections that include all uncited references of the database(s)
420 // 3. sections that include all references of the database(s), cited or not
423 params_["btprint"] = from_ascii("btPrintCited");
426 params_["btprint"] = from_ascii("btPrintNotCited");
429 params_["btprint"] = from_ascii("btPrintAll");
435 params_["btprint"] = docstring();
439 params_["btprint"] = from_ascii("btPrintAll");
446 bool GuiBibtex::isValid()
448 return databaseLW->count() != 0;
452 QString GuiBibtex::browseBib(QString const & in_name) const
454 QString const label1 = qt_("Documents|#o#O");
455 QString const dir1 = toqstr(lyxrc.document_path);
456 QStringList const filter(qt_("BibTeX Databases (*.bib)"));
457 return browseRelToParent(in_name, bufferFilePath(),
458 qt_("Select a BibTeX database to add"), filter, false, label1, dir1);
462 QString GuiBibtex::browseBst(QString const & in_name) const
464 QString const label1 = qt_("Documents|#o#O");
465 QString const dir1 = toqstr(lyxrc.document_path);
466 QStringList const filter(qt_("BibTeX Styles (*.bst)"));
467 return browseRelToParent(in_name, bufferFilePath(),
468 qt_("Select a BibTeX style"), filter, false, label1, dir1);
472 QStringList GuiBibtex::bibStyles() const
474 QStringList data = texFileList("bstFiles.lst");
475 // test whether we have a valid list, otherwise run rescan
476 if (data.isEmpty()) {
478 data = texFileList("bstFiles.lst");
480 for (int i = 0; i != data.size(); ++i)
481 data[i] = onlyFileName(data[i]);
482 // sort on filename only (no path)
488 QStringList GuiBibtex::bibFiles() const
490 QStringList data = texFileList("bibFiles.lst");
491 // test whether we have a valid list, otherwise run rescan
492 if (data.isEmpty()) {
494 data = texFileList("bibFiles.lst");
496 for (int i = 0; i != data.size(); ++i)
497 data[i] = onlyFileName(data[i]);
498 // sort on filename only (no path)
504 void GuiBibtex::rescanBibStyles() const
507 rescanTexStyles("bib");
509 rescanTexStyles("bst bib");
513 bool GuiBibtex::usingBibtopic() const
515 return buffer().params().use_bibtopic;
519 bool GuiBibtex::bibtotoc() const
521 return prefixIs(to_utf8(params_["options"]), "bibtotoc");
525 bool GuiBibtex::usingBiblatex() const
527 return buffer().masterBuffer()->params().useBiblatex();
531 QString GuiBibtex::styleFile() const
533 // the different bibtex packages have (and need) their
534 // own "plain" stylefiles
535 QString defaultstyle = toqstr(buffer().params().defaultBiblioStyle());
537 QString bst = toqstr(params_["options"]);
540 int pos = bst.indexOf(',');
543 // docstring bibtotoc = from_ascii("bibtotoc");
544 // bst = split(bst, bibtotoc, ',');
545 bst = bst.mid(pos + 1);
551 // propose default style file for new insets
552 // existing insets might have (legally) no bst files
553 // (if the class already provides a style)
554 if (bst.isEmpty() && params_["bibfiles"].empty())
561 bool GuiBibtex::initialiseParams(std::string const & data)
563 InsetCommand::string2params(data, params_);
568 void GuiBibtex::dispatchParams()
570 std::string const lfun = InsetCommand::params2string(params_);
571 dispatch(FuncRequest(getLfun(), lfun));
576 Dialog * createGuiBibtex(GuiView & lv) { return new GuiBibtex(lv); }
579 } // namespace frontend
582 #include "moc_GuiBibtex.cpp"