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