]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormBibtex.C
src/support/ChangeLog
[lyx.git] / src / frontends / xforms / FormBibtex.C
1 /**
2  * \file FormBibtex.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author John Levon
8  * \author Herbert Voss
9  * \author Rob Lahaye
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "FormBibtex.h"
17 #include "forms/form_bibtex.h"
18 #include "ControlBibtex.h"
19
20 #include "xformsBC.h"
21 #include "Tooltips.h"
22 #include "xforms_helpers.h"
23 #include "lyx_forms.h"
24 #include "combox.h"
25
26 #include "tex_helpers.h"
27
28 #include "gettext.h"
29 #include "support/filetools.h"
30 #include "support/lstrings.h"
31
32 namespace support = lyx::support;
33
34 using std::vector;
35
36
37 namespace {
38
39 struct SameName {
40         SameName(string const & name) : name_(name) {}
41         bool operator()(string const & abs_name) {
42                 return name_ == support::OnlyFilename(abs_name);
43         }
44 private:
45         string name_;
46 };
47
48
49 string const get_absolute_filename(string const & file,
50                                    string const & buffer_path,
51                                    vector<string> const & bibfiles)
52 {
53         if (support::AbsolutePath(file))
54                 return file;
55
56         string const try1 = support::MakeAbsPath(file, buffer_path);
57         if (support::IsFileReadable(try1))
58                 return try1;
59
60         string const name = support::OnlyFilename(file);
61
62         vector<string>::const_iterator it  = bibfiles.begin();
63         vector<string>::const_iterator end = bibfiles.end();
64         it = std::find_if(it, end, SameName(name));
65         if (it == end)
66                 return try1;
67         return *it;
68 }
69
70
71 bool find_file_in_browser(FL_OBJECT * browser,
72                           string const & name,
73                           string const & buffer_path,
74                           vector<string> const & bibfiles)
75 {
76         vector<string> browser_vec = getVector(browser);
77         vector<string>::iterator begin = browser_vec.begin();
78         vector<string>::iterator end   = browser_vec.end();
79         vector<string>::iterator it    = begin;
80         for (; it != end; ++it) {
81                 *it = get_absolute_filename(*it, buffer_path, bibfiles);
82         }
83
84         string const abs_name = get_absolute_filename(name, buffer_path, bibfiles);
85         
86         it = std::find(begin, end, abs_name);
87         return it != end;
88 }
89
90
91 int find_style_in_combox(FL_OBJECT * combox, string const & name)
92 {
93         int const size = fl_get_combox_maxitems(combox);
94         for (int i = 1; i <= size; ++i) {
95                 char const * const tmp = fl_get_combox_line(combox, i);
96                 string const str = tmp ? support::trim(tmp) : string();
97                 if (str == name)
98                         return i;
99         }
100         return 0;
101 }
102
103 } // namespace anon
104
105
106 typedef FormController<ControlBibtex, FormView<FD_bibtex> > base_class;
107
108 FormBibtex::FormBibtex(Dialog & parent)
109         : base_class(parent, _("BibTeX Database"))
110 {}
111
112
113 void FormBibtex::build()
114 {
115         dialog_.reset(build_bibtex(this));
116
117         // Manage the ok and cancel/close buttons
118         bcview().setOK(dialog_->button_ok);
119         bcview().setCancel(dialog_->button_close);
120
121         // disable for read-only documents
122         bcview().addReadOnly(dialog_->browser_databases);
123         bcview().addReadOnly(dialog_->button_browse_db);
124         bcview().addReadOnly(dialog_->button_delete_db);
125         bcview().addReadOnly(dialog_->radio_absolute_path);
126         bcview().addReadOnly(dialog_->radio_relative_path);
127         bcview().addReadOnly(dialog_->radio_name_only);
128         bcview().addReadOnly(dialog_->input_database);
129         bcview().addReadOnly(dialog_->button_add_db);
130         bcview().addReadOnly(dialog_->combox_style);
131         bcview().addReadOnly(dialog_->button_browse);
132         bcview().addReadOnly(dialog_->check_bibtotoc);
133
134         // callback for double click in browser
135         fl_set_browser_dblclick_callback(dialog_->browser_databases,
136                                          C_FormDialogView_InputCB, 2);
137
138         fl_set_input_return(dialog_->input_database, FL_RETURN_ALWAYS);
139
140         storage_.init(dialog_->radio_absolute_path, ABSOLUTE_PATH);
141         storage_.init(dialog_->radio_relative_path, RELATIVE_PATH);
142         storage_.init(dialog_->radio_name_only,     NAME_ONLY);
143
144         // set up the tooltips
145         string str = _("Selected BibTeX databases. Double click to edit");
146         tooltips().init(dialog_->browser_databases, str);
147
148 #if FL_VERSION == 0 || (FL_REVISION == 0 && FL_FIXLEVEL == 0)
149         // Work-around xforms' bug; enable tooltips for browser widgets.
150         setPrehandler(dialog_->browser_databases);
151 #endif
152         str = _("Add a BibTeX database file");
153         tooltips().init(dialog_->button_browse_db, str);
154
155         str = _("Remove the selected database");
156         tooltips().init(dialog_->button_delete_db, str);
157
158         str = _("Store the absolute path to the file");
159         tooltips().init(dialog_->radio_absolute_path, str);
160
161         str = _("Store the relative path to the file");
162         tooltips().init(dialog_->radio_relative_path, str);
163
164         str = _("Store the file name only. Use TeX magic to find it");
165         tooltips().init(dialog_->radio_name_only, str);
166
167         str = _("Input BibTeX database file");
168         tooltips().init(dialog_->input_database, str);
169
170         str = _("Add the BibTeX database file in the input field");
171         tooltips().init(dialog_->button_add_db, str);
172
173         str = _("The BibTeX style");
174         tooltips().init(dialog_->combox_style, str);
175
176         str = _("Choose a style file");
177         tooltips().init(dialog_->button_browse, str);
178
179         str = _("Add bibliography to the table of contents");
180         tooltips().init(dialog_->check_bibtotoc, str);
181 }
182
183
184 void FormBibtex::update()
185 {
186         controller().getBibFiles(bib_files_namesonly_);
187         getTexFileList("bibFiles.lst", bib_files_);
188
189         browser_deactivated();
190
191         InsetBibtexParams const & params = controller().params();
192
193         fl_clear_browser(dialog_->browser_databases);
194         vector<support::FileName>::const_iterator fit  = params.databases.begin();
195         vector<support::FileName>::const_iterator fend = params.databases.end();
196         for (; fit != fend; ++fit) {
197                 string const db = fit->outputFilename(kernel().bufferFilepath());
198                 fl_add_browser_line(dialog_->browser_databases, db.c_str());
199         }
200
201         fl_set_button(dialog_->check_bibtotoc, params.bibtotoc);
202
203         fl_clear_combox(dialog_->combox_style);
204
205         int item_nr = 0;
206         vector<string> styles;
207         controller().getBibStyles(styles);
208         vector<string>::const_iterator sit  = styles.begin();
209         vector<string>::const_iterator send = styles.end();
210         for (; sit != send; ++sit) {
211                 string const item = support::ChangeExtension(*sit, "");
212                 fl_addto_combox(dialog_->combox_style, item.c_str());
213                 if (item == params.style)
214                         item_nr = fl_get_combox_maxitems(dialog_->combox_style);
215         }
216
217         if (item_nr == 0) {
218                 fl_addto_combox(dialog_->combox_style, params.style.c_str());
219                 item_nr = fl_get_combox_maxitems(dialog_->combox_style);
220         }
221
222         fl_set_combox(dialog_->combox_style, item_nr);
223 }
224
225
226 void FormBibtex::apply()
227 {
228         InsetBibtexParams params;
229
230         FL_OBJECT * browser = dialog_->browser_databases;
231         int const size = fl_get_browser_maxline(browser);
232         for (int i = 0; i < size; ++i) {
233                 string const text = fl_get_browser_line(browser, i+1);
234                 support::FileName file;
235                 file.set(text, kernel().bufferFilepath());
236                 params.databases.push_back(file);
237         }
238
239         params.style = support::trim(fl_get_combox_text(dialog_->combox_style));
240         params.bibtotoc = fl_get_button(dialog_->check_bibtotoc);
241
242         controller().params() = params;
243 }
244
245
246 ButtonPolicy::SMInput FormBibtex::input(FL_OBJECT * ob, long ob_value)
247 {
248         ButtonPolicy::SMInput activate = ButtonPolicy::SMI_NOOP;
249
250         if (ob == dialog_->browser_databases && ob_value == 2) {
251                 activate = browser_double_click();
252
253         } else if (ob == dialog_->browser_databases) {
254                 activate = browser_selected();
255
256         } else if (ob == dialog_->button_browse_db) {
257                 activate = database_browse();
258
259         } else if (ob == dialog_->button_delete_db) {
260                 activate = browser_delete();
261
262         } else if (ob == dialog_->radio_absolute_path) {
263                 activate = set_path(ABSOLUTE_PATH);
264
265         } else if (ob == dialog_->radio_relative_path) {
266                 activate = set_path(RELATIVE_PATH);
267
268         } else if (ob == dialog_->radio_name_only) {
269                 activate = set_path(NAME_ONLY);
270
271         } else if (ob == dialog_->input_database) {
272                 input_database();
273
274         } else if (ob == dialog_->button_add_db) {
275                 activate = add_database();
276
277         } else if (ob == dialog_->button_browse) {
278                 activate = style_browse();
279
280         } else if (ob == dialog_->combox_style || ob == dialog_->check_bibtotoc) {
281                 activate = ButtonPolicy::SMI_VALID;
282         }
283
284         return activate;
285 }
286
287
288 ButtonPolicy::SMInput FormBibtex::add_database()
289 {
290         FL_OBJECT * input   = dialog_->input_database;
291         FL_OBJECT * browser = dialog_->browser_databases;
292
293         string const db = getString(input);
294
295         bool const activate =
296                 !db.empty() &&
297                 !find_file_in_browser(browser, db, kernel().bufferFilepath(),
298                                       bib_files_);
299
300         if (activate)
301                 fl_add_browser_line(browser, db.c_str());
302
303         fl_set_input(input, "");
304         setEnabled(dialog_->button_add_db, false);
305
306         return activate ? ButtonPolicy::SMI_VALID : ButtonPolicy::SMI_NOOP;
307 }
308
309
310 namespace {
311
312 bool inTeXSearchPath(string const & db, vector<string> const & tex_bib_files)
313 {
314         vector<string>::const_iterator it  = tex_bib_files.begin();
315         vector<string>::const_iterator end = tex_bib_files.end();
316         return std::find(it, end, db) != end;
317 }
318
319
320 FormBibtex::PathStyle storageStyle(string const & db,
321                                    vector<string> const & tex_bib_files)
322 {
323         if (support::AbsolutePath(db))
324                 return FormBibtex::ABSOLUTE_PATH;
325
326         string const name = support::OnlyFilename(db);
327         if (db == name && inTeXSearchPath(name, tex_bib_files))
328                 return FormBibtex::NAME_ONLY;
329
330         return FormBibtex::RELATIVE_PATH;
331 }
332
333 } // namespace anon
334
335
336 ButtonPolicy::SMInput FormBibtex::browser_selected()
337 {
338         FL_OBJECT * browser = dialog_->browser_databases;
339
340         int const sel = fl_get_browser(browser);
341         if (sel < 1 || sel > fl_get_browser_maxline(browser))
342                 return ButtonPolicy::SMI_NOOP;
343
344         setEnabled(dialog_->button_delete_db, true);
345         storage_.setEnabled(true);
346         fl_set_input(dialog_->input_database, "");
347
348         string const db = fl_get_browser_line(browser, sel);
349         storage_.set(storageStyle(db, bib_files_namesonly_));
350
351         return ButtonPolicy::SMI_NOOP;
352 }
353
354
355 ButtonPolicy::SMInput FormBibtex::browser_double_click()
356 {
357         FL_OBJECT * browser = dialog_->browser_databases;
358
359         int const sel = fl_get_browser(browser);
360         if (sel < 1 || sel > fl_get_browser_maxline(browser))
361                 return ButtonPolicy::SMI_NOOP;
362
363         string const db = fl_get_browser_line(browser, sel);
364         fl_set_input(dialog_->input_database, db.c_str());
365         setEnabled(dialog_->button_add_db, true);
366
367         // Reset the browser so that the following single-click
368         // callback doesn't do anything
369         fl_deselect_browser(browser);
370
371         return ButtonPolicy::SMI_NOOP;
372 }
373
374
375 ButtonPolicy::SMInput FormBibtex::browser_add_db(string const & name)
376 {
377         FL_OBJECT * browser = dialog_->browser_databases;
378
379         if (find_file_in_browser(browser, name, kernel().bufferFilepath(),
380                                  bib_files_))
381                 return ButtonPolicy::SMI_NOOP;
382
383         input_clear();
384
385         fl_add_browser_line(browser, name.c_str());
386         int const line = fl_get_browser_maxline(browser);
387         fl_select_browser_line(browser, line);
388
389         browser_selected();
390         return ButtonPolicy::SMI_VALID;
391 }
392
393
394 ButtonPolicy::SMInput FormBibtex::browser_delete()
395 {
396         FL_OBJECT * browser = dialog_->browser_databases;
397
398         int const sel = fl_get_browser(browser);
399         if (sel < 1 || sel > fl_get_browser_maxline(browser))
400                 return ButtonPolicy::SMI_NOOP;
401
402         fl_delete_browser_line(browser, sel);
403         browser_deactivated();
404         return ButtonPolicy::SMI_VALID;
405 }
406
407
408 ButtonPolicy::SMInput FormBibtex::set_path(PathStyle style)
409 {
410         FL_OBJECT * browser = dialog_->browser_databases;
411
412         int const sel = fl_get_browser(browser);
413         if (sel < 1 || sel > fl_get_browser_maxline(browser))
414                 return ButtonPolicy::SMI_NOOP;
415
416         string const db = fl_get_browser_line(browser, sel);
417         string const abs_name =
418                 get_absolute_filename(db, kernel().bufferFilepath(), bib_files_);
419
420         switch (style) {
421         case ABSOLUTE_PATH:
422                 fl_replace_browser_line(browser, sel, abs_name.c_str());
423                 break;
424         case RELATIVE_PATH: 
425         {
426                 string const rel_name =
427                         support::MakeRelPath(abs_name, kernel().bufferFilepath());
428                 fl_replace_browser_line(browser, sel, rel_name.c_str());
429                 break;
430         }
431         case NAME_ONLY:
432         {
433                 string const name = support::OnlyFilename(abs_name);
434                 fl_replace_browser_line(browser, sel, name.c_str());
435                 break;
436         }
437         }
438         
439         return ButtonPolicy::SMI_VALID;
440 }
441
442
443 ButtonPolicy::SMInput FormBibtex::database_browse()
444 {
445         ButtonPolicy::SMInput activate = ButtonPolicy::SMI_NOOP;
446                 
447         FL_OBJECT * browser = dialog_->browser_databases;
448         // When browsing, take the first file only
449         string const in_name = fl_get_browser_maxline(browser) > 0 ?
450                 fl_get_browser_line(browser, 1) : string();
451
452         string const out_name =
453                 controller().Browse("", _("Select Database"),
454                                     _("*.bib| BibTeX Databases (*.bib)"));
455
456         if (!out_name.empty() &&
457             out_name != in_name &&
458             !find_file_in_browser(browser, out_name,
459                                   kernel().bufferFilepath(),
460                                   bib_files_))
461                 activate = browser_add_db(out_name);
462         return activate;
463 }
464
465
466 ButtonPolicy::SMInput FormBibtex::style_browse()
467 {
468         FL_OBJECT * combox = dialog_->combox_style;
469
470         string const in_name = fl_get_combox_text(combox);
471         string const style =
472                 controller().Browse(in_name, _("Select BibTeX-Style"),
473                                     _("*.bst| BibTeX Styles (*.bst)"));
474
475         int const sel = find_style_in_combox(combox, style);
476         if (sel)
477                 fl_set_combox(combox, sel);
478         else {
479                 fl_addto_combox(combox, style.c_str());
480                 fl_set_combox(combox, fl_get_combox_maxitems(combox));
481         }
482
483         return ButtonPolicy::SMI_VALID;
484 }
485
486
487 void FormBibtex::browser_deactivated()
488 {
489         setEnabled(dialog_->button_delete_db, false);
490         input_clear();
491         storage_.unset();
492         storage_.setEnabled(false);
493 }
494
495
496 void FormBibtex::input_clear()
497 {
498         fl_set_input(dialog_->input_database, "");
499         setEnabled(dialog_->button_add_db, false);
500 }
501
502
503 void FormBibtex::input_database()
504 {
505         FL_OBJECT * input = dialog_->input_database;
506         setEnabled(dialog_->button_add_db, !getString(input).empty());
507 }