]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiBibtex.cpp
Complete the removal of the embedding stuff. Maybe. It's hard to be sure we got every...
[lyx.git] / src / frontends / qt4 / GuiBibtex.cpp
1 /**
2  * \file GuiBibtex.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Herbert Voß
8  * \author Angus Leeming
9  * \author Jürgen Spitzmüller
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "GuiBibtex.h"
17
18 #include "Buffer.h"
19 #include "BufferParams.h"
20 #include "ui_BibtexAddUi.h"
21 #include "qt_helpers.h"
22 #include "Validator.h"
23 #include "LyXRC.h"
24
25 #include "ButtonPolicy.h"
26
27 #include "frontends/alert.h"
28
29 #include "insets/InsetBibtex.h"
30
31 #include "support/debug.h"
32 #include "support/ExceptionMessage.h"
33 #include "support/FileFilterList.h"
34 #include "support/FileName.h"
35 #include "support/filetools.h" // changeExtension
36 #include "support/gettext.h"
37 #include "support/lstrings.h"
38
39 #include <QPushButton>
40 #include <QListWidget>
41 #include <QCheckBox>
42 #include <QLineEdit>
43
44 using namespace std;
45 using namespace lyx::support;
46
47 namespace lyx {
48 namespace frontend {
49
50
51 GuiBibtex::GuiBibtex(GuiView & lv)
52         : GuiCommand(lv, "bibtex", qt_("BibTeX Bibliography"))
53 {
54         setupUi(this);
55
56         QDialog::setModal(true);
57
58         connect(okPB, SIGNAL(clicked()),
59                 this, SLOT(slotOK()));
60         connect(closePB, SIGNAL(clicked()),
61                 this, SLOT(slotClose()));
62         connect(stylePB, SIGNAL(clicked()),
63                 this, SLOT(browsePressed()));
64         connect(deletePB, SIGNAL(clicked()),
65                 this, SLOT(deletePressed()));
66         connect(upPB, SIGNAL(clicked()),
67                 this, SLOT(upPressed()));
68         connect(downPB, SIGNAL(clicked()),
69                 this, SLOT(downPressed()));
70         connect(styleCB, SIGNAL(editTextChanged(QString)),
71                 this, SLOT(change_adaptor()));
72         connect(databaseLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
73                 this, SLOT(databaseChanged()));
74         connect(bibtocCB, SIGNAL(clicked()),
75                 this, SLOT(change_adaptor()));
76         connect(btPrintCO, SIGNAL(activated(int)),
77                 this, SLOT(change_adaptor()));
78         connect(addBibPB, SIGNAL(clicked()),
79                 this, SLOT(addPressed()));
80
81         add_ = new GuiBibtexAddDialog(this);
82         add_bc_.setPolicy(ButtonPolicy::OkCancelPolicy);
83         add_bc_.setOK(add_->addPB);
84         add_bc_.setCancel(add_->closePB);
85         add_bc_.addCheckedLineEdit(add_->bibED, 0);
86
87         connect(add_->bibED, SIGNAL(textChanged(QString)),
88                 this, SLOT(bibEDChanged()));
89         connect(add_->addPB, SIGNAL(clicked()),
90                 this, SLOT(addDatabase()));
91         connect(add_->addPB, SIGNAL(clicked()),
92                 add_, SLOT(accept()));
93         connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
94                 this, SLOT(addDatabase()));
95         connect(add_->bibLW, SIGNAL(itemActivated(QListWidgetItem *)),
96                 add_, SLOT(accept()));
97         connect(add_->bibLW, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
98                 this, SLOT(availableChanged()));
99         connect(add_->browsePB, SIGNAL(clicked()),
100                 this, SLOT(browseBibPressed()));
101         connect(add_->closePB, SIGNAL(clicked()),
102                 add_, SLOT(reject()));
103
104         bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
105         bc().setOK(okPB);
106         bc().setCancel(closePB);
107         bc().addReadOnly(databaseLW);
108         bc().addReadOnly(stylePB);
109         bc().addReadOnly(styleCB);
110         bc().addReadOnly(bibtocCB);
111         bc().addReadOnly(addBibPB);
112         // Delete/Up/Down are handled with more conditions in
113         // databaseChanged().
114
115         // Make sure the delete/up/down buttons are disabled if necessary.
116         databaseChanged();
117 }
118
119
120 void GuiBibtex::bibEDChanged()
121 {
122         // Indicate to the button controller that the contents have
123         // changed. The actual test of validity is carried out by
124         // the checkedLineEdit.
125         add_bc_.setValid(true);
126 }
127
128
129 void GuiBibtex::change_adaptor()
130 {
131         changed();
132 }
133
134
135 void GuiBibtex::browsePressed()
136 {
137         QString const file = browseBst(QString());
138
139         if (file.isEmpty())
140                 return;
141
142         QString const filen = changeExtension(file, "");
143         bool present = false;
144         unsigned int pres = 0;
145
146         for (int i = 0; i != styleCB->count(); ++i) {
147                 if (styleCB->itemText(i) == filen) {
148                         present = true;
149                         pres = i;
150                 }
151         }
152
153         if (!present)
154                 styleCB->insertItem(0, filen);
155
156         styleCB->setCurrentIndex(pres);
157         changed();
158 }
159
160
161 void GuiBibtex::browseBibPressed()
162 {
163         QString const file = browseBib(QString()).trimmed();
164
165         if (file.isEmpty())
166                 return;
167
168         QString const f = changeExtension(file, "");
169         bool present = false;
170
171         for (int i = 0; i < add_->bibLW->count(); ++i) {
172                 if (add_->bibLW->item(i)->text() == f)
173                         present = true;
174         }
175
176         if (!present) {
177                 add_->bibLW->addItem(f);
178                 changed();
179         }
180
181         add_->bibED->setText(f);
182 }
183
184
185 void GuiBibtex::addPressed()
186 {
187         add_bc_.setValid(false);
188         add_->exec();
189 }
190
191
192 void GuiBibtex::addDatabase()
193 {
194         int const sel = add_->bibLW->currentRow();
195         QString const file = add_->bibED->text().trimmed();
196
197         if (sel < 0 && file.isEmpty())
198                 return;
199
200         // Add the selected browser_bib keys to browser_database
201         // multiple selections are possible
202         for (int i = 0; i != add_->bibLW->count(); ++i) {
203                 QListWidgetItem * const item = add_->bibLW->item(i);
204                 if (add_->bibLW->isItemSelected(item)) {
205                         add_->bibLW->setItemSelected(item, false);
206                         QList<QListWidgetItem *> matches =
207                                 databaseLW->findItems(item->text(), Qt::MatchExactly);
208                         if (matches.empty()) {
209                                 QString label = item->text();
210                                 QListWidgetItem * db = new QListWidgetItem(label);
211                                 db->setFlags(db->flags() | Qt::ItemIsSelectable);
212                                 databaseLW->addItem(db);
213                         }
214                 }
215         }
216
217         if (!file.isEmpty()) {
218                 add_->bibED->clear();
219                 QString const f = changeExtension(file, "");
220                 QList<QListWidgetItem *> matches =
221                         databaseLW->findItems(f, Qt::MatchExactly);
222                 if (matches.empty()) {
223                         QListWidgetItem * db = new QListWidgetItem(f);
224                         db->setFlags(db->flags() | Qt::ItemIsSelectable);
225                         databaseLW->addItem(db);
226                 }
227         }
228
229         databaseChanged();
230         changed();
231 }
232
233
234 void GuiBibtex::deletePressed()
235 {
236         QListWidgetItem *cur = databaseLW->takeItem(databaseLW->currentRow());
237         if (cur) {
238                 delete cur;
239                 databaseChanged();
240                 changed();
241         }
242 }
243
244
245 void GuiBibtex::upPressed()
246 {
247         int row = databaseLW->currentRow();
248         QListWidgetItem *cur = databaseLW->takeItem(row);
249         databaseLW->insertItem(row - 1, cur);
250         databaseLW->setCurrentItem(cur);
251         changed();
252 }
253
254
255 void GuiBibtex::downPressed()
256 {
257         int row = databaseLW->currentRow();
258         QListWidgetItem *cur = databaseLW->takeItem(row);
259         databaseLW->insertItem(row + 1, cur);
260         databaseLW->setCurrentItem(cur);
261         changed();
262 }
263
264
265 void GuiBibtex::databaseChanged()
266 {
267         bool readOnly = isBufferReadonly();
268         int count = databaseLW->count();
269         int row = databaseLW->currentRow();
270         deletePB->setEnabled(!readOnly && row != -1);
271         upPB->setEnabled(!readOnly && count > 1 && row > 0);
272         downPB->setEnabled(!readOnly && count > 1 && row < count - 1);
273 }
274
275
276 void GuiBibtex::availableChanged()
277 {
278         add_bc_.setValid(true);
279 }
280
281
282 void GuiBibtex::updateContents()
283 {
284         bool bibtopic = usingBibtopic();
285
286         databaseLW->clear();
287
288         docstring bibs = params_["bibfiles"];
289         docstring bib;
290
291         while (!bibs.empty()) {
292                 bibs = split(bibs, bib, ',');
293                 bib = trim(bib);
294                 if (!bib.empty()) {
295                         QListWidgetItem * db = new QListWidgetItem(toqstr(bib));
296                         db->setFlags(db->flags() | Qt::ItemIsSelectable);
297                         databaseLW->addItem(db);
298                 }
299         }
300
301         add_->bibLW->clear();
302
303         QStringList bibfiles = bibFiles();
304         for (int i = 0; i != bibfiles.count(); ++i)
305                 add_->bibLW->addItem(changeExtension(bibfiles[i], ""));
306
307         QString bibstyle = styleFile();
308
309         bibtocCB->setChecked(bibtotoc() && !bibtopic);
310         bibtocCB->setEnabled(!bibtopic);
311
312         if (!bibtopic && btPrintCO->count() == 3)
313                 btPrintCO->removeItem(1);
314         else if (bibtopic && btPrintCO->count() < 3)
315                 btPrintCO->insertItem(1, qt_("all uncited references", 0));
316
317         docstring btprint = params_["btprint"];
318         int btp = 0;
319         if ((bibtopic && btprint == "btPrintNotCited") ||
320            (!bibtopic && btprint == "btPrintAll"))
321                 btp = 1;
322         else if (bibtopic && btprint == "btPrintAll")
323                 btp = 2;
324
325         btPrintCO->setCurrentIndex(btp);
326
327         styleCB->clear();
328
329         int item_nr = -1;
330
331         QStringList str = bibStyles();
332         for (int i = 0; i != str.count(); ++i) {
333                 QString item = changeExtension(str[i], "");
334                 if (item == bibstyle)
335                         item_nr = i;
336                 styleCB->addItem(item);
337         }
338
339         if (item_nr == -1 && !bibstyle.isEmpty()) {
340                 styleCB->addItem(bibstyle);
341                 item_nr = styleCB->count() - 1;
342         }
343
344         if (item_nr != -1)
345                 styleCB->setCurrentIndex(item_nr);
346         else
347                 styleCB->clearEditText();
348 }
349
350
351 void GuiBibtex::applyView()
352 {
353         docstring dbs;
354
355         unsigned int maxCount = databaseLW->count();
356         for (unsigned int i = 0; i < maxCount; i++) {
357                 if (i != 0)
358                         dbs += ',';
359                 QString item = databaseLW->item(i)->text();
360                 docstring bibfile = qstring_to_ucs4(item);
361                 dbs += bibfile;
362         }
363
364         params_["bibfiles"] = dbs;
365
366         docstring const bibstyle = qstring_to_ucs4(styleCB->currentText());
367         bool const bibtotoc = bibtocCB->isChecked();
368
369         if (bibtotoc && !bibstyle.empty()) {
370                 // both bibtotoc and style
371                 params_["options"] = "bibtotoc," + bibstyle;
372         } else if (bibtotoc) {
373                 // bibtotoc and no style
374                 params_["options"] = from_ascii("bibtotoc");
375         } else {
376                 // only style. An empty one is valid, because some
377                 // documentclasses have an own \bibliographystyle{}
378                 // command!
379                 params_["options"] = bibstyle;
380         }
381
382         int btp = btPrintCO->currentIndex();
383
384         if (usingBibtopic()) {
385                 // bibtopic allows three kinds of sections:
386                 // 1. sections that include all cited references of the database(s)
387                 // 2. sections that include all uncited references of the database(s)
388                 // 3. sections that include all references of the database(s), cited or not
389                 switch (btp) {
390                 case 0:
391                         params_["btprint"] = from_ascii("btPrintCited");
392                         break;
393                 case 1:
394                         params_["btprint"] = from_ascii("btPrintNotCited");
395                         break;
396                 case 2:
397                         params_["btprint"] = from_ascii("btPrintAll");
398                         break;
399                 }
400         } else {
401                 switch (btp) {
402                 case 0:
403                         params_["btprint"] = docstring();
404                         break;
405                 case 1:
406                         // use \nocite{*}
407                         params_["btprint"] = from_ascii("btPrintAll");
408                         break;
409                 }               
410         }
411 }
412
413
414 bool GuiBibtex::isValid()
415 {
416         return databaseLW->count() != 0;
417 }
418
419
420 QString GuiBibtex::browseBib(QString const & in_name) const
421 {
422         QString const label1 = qt_("Documents|#o#O");
423         QString const dir1 = toqstr(lyxrc.document_path);
424         FileFilterList const filter(_("BibTeX Databases (*.bib)"));
425         return browseRelFile(in_name, bufferFilepath(),
426                 qt_("Select a BibTeX database to add"), filter, false, label1, dir1);
427 }
428
429
430 QString GuiBibtex::browseBst(QString const & in_name) const
431 {
432         QString const label1 = qt_("Documents|#o#O");
433         QString const dir1 = toqstr(lyxrc.document_path);
434         FileFilterList const filter(_("BibTeX Styles (*.bst)"));
435         return browseRelFile(in_name, bufferFilepath(),
436                 qt_("Select a BibTeX style"), filter, false, label1, dir1);
437 }
438
439
440 QStringList GuiBibtex::bibStyles() const
441 {
442         QStringList data = texFileList("bstFiles.lst");
443         // test whether we have a valid list, otherwise run rescan
444         if (data.isEmpty()) {
445                 rescanBibStyles();
446                 data = texFileList("bstFiles.lst");
447         }
448         for (int i = 0; i != data.size(); ++i)
449                 data[i] = onlyFilename(data[i]);
450         // sort on filename only (no path)
451         data.sort();
452         return data;
453 }
454
455
456 QStringList GuiBibtex::bibFiles() const
457 {
458         QStringList data = texFileList("bibFiles.lst");
459         // test whether we have a valid list, otherwise run rescan
460         if (data.isEmpty()) {
461                 rescanBibStyles();
462                 data = texFileList("bibFiles.lst");
463         }
464         for (int i = 0; i != data.size(); ++i)
465                 data[i] = onlyFilename(data[i]);
466         // sort on filename only (no path)
467         data.sort();
468         return data;
469 }
470
471
472 void GuiBibtex::rescanBibStyles() const
473 {
474         rescanTexStyles();
475 }
476
477
478 bool GuiBibtex::usingBibtopic() const
479 {
480         return buffer().params().use_bibtopic;
481 }
482
483
484 bool GuiBibtex::bibtotoc() const
485 {
486         return prefixIs(to_utf8(params_["options"]), "bibtotoc");
487 }
488
489
490 QString GuiBibtex::styleFile() const
491 {
492         // the different bibtex packages have (and need) their
493         // own "plain" stylefiles
494         biblio::CiteEngine const engine = buffer().params().citeEngine();
495         QString defaultstyle;
496         switch (engine) {
497         case biblio::ENGINE_BASIC:
498                 defaultstyle = "plain";
499                 break;
500         case biblio::ENGINE_NATBIB_AUTHORYEAR:
501                 defaultstyle = "plainnat";
502                 break;
503         case biblio::ENGINE_NATBIB_NUMERICAL:
504                 defaultstyle = "plainnat";
505                 break;
506         case biblio::ENGINE_JURABIB:
507                 defaultstyle = "jurabib";
508                 break;
509         }
510
511         QString bst = toqstr(params_["options"]);
512         if (bibtotoc()){
513                 // bibstyle exists?
514                 int pos = bst.indexOf(',');
515                 if (pos != -1) {
516                         // FIXME: check
517                         // docstring bibtotoc = from_ascii("bibtotoc");
518                         // bst = split(bst, bibtotoc, ',');
519                         bst = bst.mid(pos);     
520                 } else {
521                         bst.clear();
522                 }
523         }
524
525         // propose default style file for new insets
526         // existing insets might have (legally) no bst files
527         // (if the class already provides a style)
528         if (bst.isEmpty() && params_["bibfiles"].empty())
529                 bst = defaultstyle;
530
531         return bst;
532 }
533
534
535 Dialog * createGuiBibtex(GuiView & lv) { return new GuiBibtex(lv); }
536
537
538 } // namespace frontend
539 } // namespace lyx
540
541 #include "GuiBibtex_moc.cpp"