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 "FuncRequest.h"
22 #include "qt_helpers.h"
23 #include "Validator.h"
25 #include "ui_BibtexAddUi.h"
27 #include "ButtonPolicy.h"
29 #include "frontends/alert.h"
31 #include "insets/InsetBibtex.h"
33 #include "support/debug.h"
34 #include "support/ExceptionMessage.h"
35 #include "support/FileName.h"
36 #include "support/filetools.h" // changeExtension
37 #include "support/gettext.h"
38 #include "support/lstrings.h"
40 #include <QPushButton>
41 #include <QListWidget>
46 using namespace lyx::support;
52 GuiBibtex::GuiBibtex(GuiView & lv)
53 : GuiDialog(lv, "bibtex", qt_("BibTeX Bibliography")),
54 params_(insetCode("bibtex"))
58 QDialog::setModal(true);
60 connect(okPB, SIGNAL(clicked()),
61 this, SLOT(slotOK()));
62 connect(closePB, SIGNAL(clicked()),
63 this, SLOT(slotClose()));
64 connect(stylePB, SIGNAL(clicked()),
65 this, SLOT(browsePressed()));
66 connect(deletePB, SIGNAL(clicked()),
67 this, SLOT(deletePressed()));
68 connect(upPB, SIGNAL(clicked()),
69 this, SLOT(upPressed()));
70 connect(downPB, SIGNAL(clicked()),
71 this, SLOT(downPressed()));
72 connect(styleCB, SIGNAL(editTextChanged(QString)),
73 this, SLOT(change_adaptor()));
74 connect(databaseLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
75 this, SLOT(databaseChanged()));
76 connect(bibtocCB, SIGNAL(clicked()),
77 this, SLOT(change_adaptor()));
78 connect(btPrintCO, SIGNAL(activated(int)),
79 this, SLOT(change_adaptor()));
80 connect(addBibPB, SIGNAL(clicked()),
81 this, SLOT(addPressed()));
82 connect(rescanPB, SIGNAL(clicked()),
83 this, SLOT(rescanClicked()));
85 add_ = new GuiBibtexAddDialog(this);
86 add_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
87 add_bc_.setOK(add_->addPB);
88 add_bc_.setCancel(add_->closePB);
89 add_bc_.addCheckedLineEdit(add_->bibED, 0);
91 connect(add_->bibED, SIGNAL(textChanged(QString)),
92 this, SLOT(bibEDChanged()));
93 connect(add_->addPB, SIGNAL(clicked()),
94 this, SLOT(addDatabase()));
95 connect(add_->addPB, SIGNAL(clicked()),
96 add_, SLOT(accept()));
97 connect(add_->rescanPB, SIGNAL(clicked()),
98 this, SLOT(rescanClicked()));
99 connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
100 this, SLOT(addDatabase()));
101 connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
102 add_, SLOT(accept()));
103 connect(add_->bibLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
104 this, SLOT(availableChanged()));
105 connect(add_->browsePB, SIGNAL(clicked()),
106 this, SLOT(browseBibPressed()));
107 connect(add_->closePB, SIGNAL(clicked()),
108 add_, SLOT(reject()));
110 add_->bibLW->setToolTip(formatToolTip(qt_("This list consists of all databases that are indexed by LaTeX and thus are found without a file path. "
111 "This is usually everything in the bib/ subdirectory of LaTeX's texmf tree. "
112 "If you want to reuse your own database, this is the place you should store it.")));
114 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
116 bc().setCancel(closePB);
117 bc().addReadOnly(databaseLW);
118 bc().addReadOnly(stylePB);
119 bc().addReadOnly(styleCB);
120 bc().addReadOnly(bibtocCB);
121 bc().addReadOnly(addBibPB);
122 // Delete/Up/Down are handled with more conditions in
123 // databaseChanged().
125 // Make sure the delete/up/down buttons are disabled if necessary.
130 void GuiBibtex::bibEDChanged()
132 // Indicate to the button controller that the contents have
133 // changed. The actual test of validity is carried out by
134 // the checkedLineEdit.
135 add_bc_.setValid(true);
139 void GuiBibtex::change_adaptor()
145 void GuiBibtex::browsePressed()
147 QString const file = browseBst(QString());
152 QString const filen = changeExtension(file, "");
153 bool present = false;
154 unsigned int pres = 0;
156 for (int i = 0; i != styleCB->count(); ++i) {
157 if (styleCB->itemText(i) == filen) {
164 styleCB->insertItem(0, filen);
166 styleCB->setCurrentIndex(pres);
171 void GuiBibtex::browseBibPressed()
173 QString const file = browseBib(QString()).trimmed();
178 QString const f = changeExtension(file, "");
179 bool present = false;
181 for (int i = 0; i < add_->bibLW->count(); ++i) {
182 if (add_->bibLW->item(i)->text() == f)
187 add_->bibLW->addItem(f);
191 add_->bibED->setText(f);
195 void GuiBibtex::addPressed()
197 add_bc_.setValid(false);
202 void GuiBibtex::addDatabase()
204 int const sel = add_->bibLW->currentRow();
205 QString const file = add_->bibED->text().trimmed();
207 if (sel < 0 && file.isEmpty())
210 // Add the selected browser_bib keys to browser_database
211 // multiple selections are possible
212 for (int i = 0; i != add_->bibLW->count(); ++i) {
213 QListWidgetItem * const item = add_->bibLW->item(i);
214 if (add_->bibLW->isItemSelected(item)) {
215 add_->bibLW->setItemSelected(item, false);
216 QList<QListWidgetItem *> matches =
217 databaseLW->findItems(item->text(), Qt::MatchExactly);
218 if (matches.empty()) {
219 QString label = item->text();
220 QListWidgetItem * db = new QListWidgetItem(label);
221 db->setFlags(db->flags() | Qt::ItemIsSelectable);
222 databaseLW->addItem(db);
227 if (!file.isEmpty()) {
228 add_->bibED->clear();
229 QString const f = changeExtension(file, "");
230 QList<QListWidgetItem *> matches =
231 databaseLW->findItems(f, Qt::MatchExactly);
232 if (matches.empty()) {
233 QListWidgetItem * db = new QListWidgetItem(f);
234 db->setFlags(db->flags() | Qt::ItemIsSelectable);
235 databaseLW->addItem(db);
244 void GuiBibtex::deletePressed()
246 QListWidgetItem *cur = databaseLW->takeItem(databaseLW->currentRow());
255 void GuiBibtex::upPressed()
257 int row = databaseLW->currentRow();
258 QListWidgetItem *cur = databaseLW->takeItem(row);
259 databaseLW->insertItem(row - 1, cur);
260 databaseLW->setCurrentItem(cur);
265 void GuiBibtex::downPressed()
267 int row = databaseLW->currentRow();
268 QListWidgetItem *cur = databaseLW->takeItem(row);
269 databaseLW->insertItem(row + 1, cur);
270 databaseLW->setCurrentItem(cur);
275 void GuiBibtex::rescanClicked()
282 void GuiBibtex::databaseChanged()
284 bool readOnly = isBufferReadonly();
285 int count = databaseLW->count();
286 int row = databaseLW->currentRow();
287 deletePB->setEnabled(!readOnly && row != -1);
288 upPB->setEnabled(!readOnly && count > 1 && row > 0);
289 downPB->setEnabled(!readOnly && count > 1 && row < count - 1);
293 void GuiBibtex::availableChanged()
295 add_bc_.setValid(true);
299 void GuiBibtex::updateContents()
301 bool bibtopic = usingBibtopic();
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);
348 QStringList const str = bibStyles();
349 for (int i = 0; i != str.count(); ++i) {
350 QString item = changeExtension(str[i], "");
351 if (item == bibstyle)
353 styleCB->addItem(item);
356 if (item_nr == -1 && !bibstyle.isEmpty()) {
357 styleCB->addItem(bibstyle);
358 item_nr = styleCB->count() - 1;
362 styleCB->setCurrentIndex(item_nr);
364 styleCB->clearEditText();
368 void GuiBibtex::applyView()
372 unsigned int maxCount = databaseLW->count();
373 for (unsigned int i = 0; i < maxCount; i++) {
376 QString item = databaseLW->item(i)->text();
377 docstring bibfile = qstring_to_ucs4(item);
381 params_["bibfiles"] = dbs;
383 docstring const bibstyle = qstring_to_ucs4(styleCB->currentText());
384 bool const bibtotoc = bibtocCB->isChecked();
386 if (bibtotoc && !bibstyle.empty()) {
387 // both bibtotoc and style
388 params_["options"] = "bibtotoc," + bibstyle;
389 } else if (bibtotoc) {
390 // bibtotoc and no style
391 params_["options"] = from_ascii("bibtotoc");
393 // only style. An empty one is valid, because some
394 // documentclasses have an own \bibliographystyle{}
396 params_["options"] = bibstyle;
399 int btp = btPrintCO->currentIndex();
401 if (usingBibtopic()) {
402 // bibtopic allows three kinds of sections:
403 // 1. sections that include all cited references of the database(s)
404 // 2. sections that include all uncited references of the database(s)
405 // 3. sections that include all references of the database(s), cited or not
408 params_["btprint"] = from_ascii("btPrintCited");
411 params_["btprint"] = from_ascii("btPrintNotCited");
414 params_["btprint"] = from_ascii("btPrintAll");
420 params_["btprint"] = docstring();
424 params_["btprint"] = from_ascii("btPrintAll");
431 bool GuiBibtex::isValid()
433 return databaseLW->count() != 0;
437 QString GuiBibtex::browseBib(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 Databases (*.bib)"));
442 return browseRelToParent(in_name, bufferFilePath(),
443 qt_("Select a BibTeX database to add"), filter, false, label1, dir1);
447 QString GuiBibtex::browseBst(QString const & in_name) const
449 QString const label1 = qt_("Documents|#o#O");
450 QString const dir1 = toqstr(lyxrc.document_path);
451 QStringList const filter(qt_("BibTeX Styles (*.bst)"));
452 return browseRelToParent(in_name, bufferFilePath(),
453 qt_("Select a BibTeX style"), filter, false, label1, dir1);
457 QStringList GuiBibtex::bibStyles() const
459 QStringList data = texFileList("bstFiles.lst");
460 // test whether we have a valid list, otherwise run rescan
461 if (data.isEmpty()) {
463 data = texFileList("bstFiles.lst");
465 for (int i = 0; i != data.size(); ++i)
466 data[i] = onlyFileName(data[i]);
467 // sort on filename only (no path)
473 QStringList GuiBibtex::bibFiles() const
475 QStringList data = texFileList("bibFiles.lst");
476 // test whether we have a valid list, otherwise run rescan
477 if (data.isEmpty()) {
479 data = texFileList("bibFiles.lst");
481 for (int i = 0; i != data.size(); ++i)
482 data[i] = onlyFileName(data[i]);
483 // sort on filename only (no path)
489 void GuiBibtex::rescanBibStyles() const
491 rescanTexStyles("bst bib");
495 bool GuiBibtex::usingBibtopic() const
497 return buffer().params().use_bibtopic;
501 bool GuiBibtex::bibtotoc() const
503 return prefixIs(to_utf8(params_["options"]), "bibtotoc");
507 QString GuiBibtex::styleFile() const
509 // the different bibtex packages have (and need) their
510 // own "plain" stylefiles
511 QString defaultstyle = toqstr(buffer().params().defaultBiblioStyle());
513 QString bst = toqstr(params_["options"]);
516 int pos = bst.indexOf(',');
519 // docstring bibtotoc = from_ascii("bibtotoc");
520 // bst = split(bst, bibtotoc, ',');
521 bst = bst.mid(pos + 1);
527 // propose default style file for new insets
528 // existing insets might have (legally) no bst files
529 // (if the class already provides a style)
530 if (bst.isEmpty() && params_["bibfiles"].empty())
537 bool GuiBibtex::initialiseParams(std::string const & data)
539 InsetCommand::string2params(data, params_);
544 void GuiBibtex::dispatchParams()
546 std::string const lfun = InsetCommand::params2string(params_);
547 dispatch(FuncRequest(getLfun(), lfun));
552 Dialog * createGuiBibtex(GuiView & lv) { return new GuiBibtex(lv); }
555 } // namespace frontend
558 #include "moc_GuiBibtex.cpp"