]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiBibtex.cpp
start some work on file dialogs
[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(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         docstring const label1 = _("Documents|#o#O");
383         docstring const dir1 = 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"), filter, false, label1, dir1);
387 }
388
389
390 docstring const GuiBibtex::browseBst(docstring const & in_name) const
391 {
392         // FIXME UNICODE
393         docstring const label1 = _("Documents|#o#O");
394         docstring const dir1 = from_utf8(lyxrc.document_path);
395         FileFilterList const filter(_("BibTeX Styles (*.bst)"));
396         return browseRelFile(in_name, from_utf8(bufferFilepath()),
397                 _("Select a BibTeX style"), filter, false, label1, dir1);
398 }
399
400
401 void GuiBibtex::getBibStyles(vector<string> & data) const
402 {
403         data.clear();
404
405         getTexFileList("bstFiles.lst", data);
406         // test, if we have a valid list, otherwise run rescan
407         if (data.empty()) {
408                 rescanBibStyles();
409                 getTexFileList("bstFiles.lst", data);
410         }
411         vector<string>::iterator it  = data.begin();
412         vector<string>::iterator end = data.end();
413         for (; it != end; ++it) {
414                 *it = onlyFilename(*it);
415         }
416         // sort on filename only (no path)
417         std::sort(data.begin(), data.end());
418 }
419
420
421 void GuiBibtex::getBibFiles(vector<string> & data) const
422 {
423         data.clear();
424
425         getTexFileList("bibFiles.lst", data);
426         // test, if we have a valid list, otherwise run rescan
427         if (data.empty()) {
428                 rescanBibStyles();
429                 getTexFileList("bibFiles.lst", data);
430         }
431         vector<string>::iterator it  = data.begin();
432         vector<string>::iterator end = data.end();
433         for (; it != end; ++it) {
434                 *it = onlyFilename(*it);
435         }
436         // sort on filename only (no path)
437         std::sort(data.begin(), data.end());
438 }
439
440
441 void GuiBibtex::rescanBibStyles() const
442 {
443         rescanTexStyles();
444 }
445
446
447 bool GuiBibtex::usingBibtopic() const
448 {
449         return buffer().params().use_bibtopic;
450 }
451
452
453 bool GuiBibtex::bibtotoc() const
454 {
455         return prefixIs(to_utf8(params_["options"]), "bibtotoc");
456 }
457
458
459 string const GuiBibtex::getStylefile() const
460 {
461         // the different bibtex packages have (and need) their
462         // own "plain" stylefiles
463         biblio::CiteEngine const engine = buffer().params().getEngine();
464         docstring defaultstyle;
465         switch (engine) {
466         case biblio::ENGINE_BASIC:
467                 defaultstyle = from_ascii("plain");
468                 break;
469         case biblio::ENGINE_NATBIB_AUTHORYEAR:
470                 defaultstyle = from_ascii("plainnat");
471                 break;
472         case biblio::ENGINE_NATBIB_NUMERICAL:
473                 defaultstyle = from_ascii("plainnat");
474                 break;
475         case biblio::ENGINE_JURABIB:
476                 defaultstyle = from_ascii("jurabib");
477                 break;
478         }
479
480         docstring bst = params_["options"];
481         if (bibtotoc()){
482                 // bibstyle exists?
483                 if (contains(bst, ',')) {
484                         docstring bibtotoc = from_ascii("bibtotoc");
485                         bst = split(bst, bibtotoc, ',');
486                 } else
487                         bst.erase();
488         }
489
490         // propose default style file for new insets
491         // existing insets might have (legally) no bst files
492         // (if the class already provides a style)
493         if (bst.empty() && params_["bibfiles"].empty())
494                 bst = defaultstyle;
495
496         // FIXME UNICODE
497         return to_utf8(bst);
498 }
499
500
501 Dialog * createGuiBibtex(LyXView & lv) { return new GuiBibtex(lv); }
502
503
504 } // namespace frontend
505 } // namespace lyx
506
507 #include "GuiBibtex_moc.cpp"