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