]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormCitation.C
2002-07-02 Lars Gullik Bj�nnes <larsbj@birdstep.com>
[lyx.git] / src / frontends / xforms / FormCitation.C
1 /**
2  * \file xforms/FormCitation.C
3  * Copyright 2000-2001 The LyX Team.
4  * See the file COPYING.
5  *
6  * \author Angus Leeming, a.leeming@ic.ac.uk
7  */
8
9 #include <config.h>
10 #include <algorithm>
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 #include "xformsBC.h"
17 #include "ControlCitation.h"
18 #include "FormCitation.h"
19 #include "forms/form_citation.h"
20 #include "Tooltips.h"
21 #include "helper_funcs.h"
22 #include "xforms_helpers.h"
23 #include FORMS_H_LOCATION
24
25 #include "gettext.h"
26 #include "support/LAssert.h"
27 #include "support/lstrings.h"
28
29 using std::find;
30 using std::max;
31 using std::min;
32 using std::pair;
33 using std::sort;
34 using std::vector;
35
36 namespace {
37
38 // shamelessly stolen from Menubar_pimpl.C
39 int string_width(string const & str)
40 {
41         return fl_get_string_widthTAB(FL_NORMAL_STYLE, FL_NORMAL_SIZE,
42                                       str.c_str(),
43                                       static_cast<int>(str.length()));
44 }
45
46
47 void fillChoice(FD_citation * dialog, vector<string> vec)
48 {
49         // Check whether the current contents of the browser will be
50         // changed by loading the contents of the vec...
51         vector<string> const choice_style =
52                 getVectorFromChoice(dialog->choice_style);
53
54         if (vec == choice_style)
55                 return;
56
57         // They will be changed. Proceed
58         string str = " ";
59         if (!vec.empty())
60                 str += getStringFromVector(vec, " | ") + " ";
61
62         fl_clear_choice(dialog->choice_style);
63         fl_addto_choice(dialog->choice_style, str.c_str());
64
65         setEnabled(dialog->choice_style, !vec.empty());
66         if (vec.empty())
67                 return;
68
69         // The width of the choice varies with the contents.
70         // Ensure that it is centred in the frame.
71
72         int width = 0;
73         for (vector<string>::const_iterator it = vec.begin();
74              it != vec.end(); ++it) {
75                 width = max(width, string_width(*it));
76         }
77
78         int const dx =
79                 max(5, int(0.5 * (dialog->frame_style->w - width)));
80
81         fl_set_object_geometry(dialog->choice_style,
82                                dialog->frame_style->x + dx,
83                                dialog->choice_style->y,
84                                width,
85                                dialog->choice_style->h);
86 }
87
88
89 void updateStyle(FD_citation * dialog, string command)
90 {
91         // Find the style of the citekeys
92         vector<biblio::CiteStyle> const & styles =
93                 ControlCitation::getCiteStyles();
94         biblio::CitationStyle cs = biblio::getCitationStyle(command);
95
96         vector<biblio::CiteStyle>::const_iterator cit =
97                 find(styles.begin(), styles.end(), cs.style);
98
99         // Use this to initialise the GUI
100         if (cit == styles.end()) {
101                 fl_set_choice(dialog->choice_style, 1);
102                 fl_set_button(dialog->check_full_author_list, 0);
103                 fl_set_button(dialog->check_force_uppercase, 0);
104         } else {
105                 int const i = int(cit - styles.begin());
106                 fl_set_choice(dialog->choice_style, i+1);
107                 fl_set_button(dialog->check_full_author_list,  cs.full);
108                 fl_set_button(dialog->check_force_uppercase, cs.forceUCase);
109         }
110 }
111
112 } // namespace anon
113
114
115 typedef FormCB<ControlCitation, FormDB<FD_citation> > base_class;
116
117
118 FormCitation::FormCitation(ControlCitation & c, Dialogs & d)
119         : base_class(c, d, _("Citation"), false)
120 {}
121
122
123 void FormCitation::apply()
124 {
125         string command = "cite";
126         if (dialog_->choice_style->active != 0) {
127                 vector<biblio::CiteStyle> const & styles =
128                         ControlCitation::getCiteStyles();
129
130                 int const choice =
131                         std::max(0, fl_get_choice(dialog_->choice_style) - 1);
132                 bool const full  =
133                         fl_get_button(dialog_->check_full_author_list);
134                 bool const force =
135                         fl_get_button(dialog_->check_force_uppercase);
136
137                 command = biblio::getCiteCommand(styles[choice], full, force);
138         }
139
140         controller().params().setCmdName(command);
141         controller().params().setContents(getStringFromVector(citekeys));
142
143         string const after  = fl_get_input(dialog_->input_after);
144         controller().params().setOptions(after);
145 }
146
147
148 void FormCitation::hide()
149 {
150         citekeys.clear();
151         bibkeys.clear();
152
153         FormBase::hide();
154 }
155
156
157 void FormCitation::build()
158 {
159         dialog_.reset(build_citation(this));
160
161         fl_set_input_return(dialog_->input_after,  FL_RETURN_CHANGED);
162         fl_set_input_return(dialog_->input_before, FL_RETURN_CHANGED);
163         fl_set_input_return(dialog_->input_search, FL_RETURN_END);
164
165         fl_set_button(dialog_->check_search_case, 0);
166         fl_set_button(dialog_->check_search_type, 0);
167
168         setPrehandler(dialog_->input_search);
169         setPrehandler(dialog_->input_before);
170         setPrehandler(dialog_->input_after);
171
172         // Manage the ok, apply, restore and cancel/close buttons
173         bc().setOK(dialog_->button_ok);
174         bc().setApply(dialog_->button_apply);
175         bc().setCancel(dialog_->button_close);
176         bc().setRestore(dialog_->button_restore);
177
178         bc().addReadOnly(dialog_->button_add);
179         bc().addReadOnly(dialog_->button_del);
180         bc().addReadOnly(dialog_->button_up);
181         bc().addReadOnly(dialog_->button_down);
182         bc().addReadOnly(dialog_->choice_style);
183         bc().addReadOnly(dialog_->input_before);
184         bc().addReadOnly(dialog_->input_after);
185         bc().addReadOnly(dialog_->check_full_author_list);
186         bc().addReadOnly(dialog_->check_force_uppercase);
187
188         //set up the tooltip mechanism
189         string str = _("Add the selected entry to the current citation reference.");
190         tooltips().init(dialog_->button_add, str);
191
192         str = _("Delete the selected entry from the current citation reference.");
193         tooltips().init(dialog_->button_del, str);
194
195         str = _("Move the selected entry upwards (in the current list).");
196         tooltips().init(dialog_->button_up, str);
197
198         str = _("Move the selected entry downwards (in the current list).");
199         tooltips().init(dialog_->button_down, str);
200
201         str = _("The entries which will be cited. Select them with the arrow buttons from the right browser window.");
202         tooltips().init(dialog_->browser_cite, str);
203
204         str = _("All entries in the database you have loaded (via \"Insert->Lists&TOC->BibTex Reference\"). Move the ones you want to cite with the arrow buttons into the left browser window.");
205         tooltips().init(dialog_->browser_bib, str);
206
207         str = _("Information about the selected entry");
208         tooltips().init(dialog_->browser_info, str);
209
210         str = _("Here you may select how the citation label should look inside the text (Natbib).");
211         tooltips().init(dialog_->choice_style, str);
212
213         str = _("Activate if you want to print all authors in a reference with more than three authors, and not \"<First Author> et al.\" (Natbib).");
214         tooltips().init(dialog_->check_full_author_list, str);
215
216         str = _("Activate if you want to print the first character of the author name as uppercase (\"Van Gogh\", not \"van Gogh\"). Useful at the beginning of sentences (Natbib).");
217         tooltips().init(dialog_->check_force_uppercase, str);
218
219         str = _("Optional text which appears before the citation reference, e.g. \"see <Ref>\"");
220         tooltips().init(dialog_->input_before, str);
221
222         str = _("Optional text which appears after the citation reference, e.g. \"pp. 12\"");
223         tooltips().init(dialog_->input_after, str);
224
225         str = _("Search your database (all fields will be searched).");
226         tooltips().init(dialog_->input_search, str);
227
228         str = _("Activate if you want to have case sensitive search: \"bibtex\" finds \"bibtex\", but not \"BibTeX\".");
229         tooltips().init(dialog_->check_search_case, str);
230
231         str = _("Activate if you want to enter Regular Expressions.");
232         tooltips().init(dialog_->check_search_type, str);
233 }
234
235
236 void FormCitation::findBiblio(biblio::Direction const dir)
237 {
238         string const str = fl_get_input(dialog_->input_search);
239         biblio::InfoMap const & theMap = controller().bibkeysInfo();
240         bool const caseSensitive =
241                 fl_get_button(dialog_->check_search_case);
242         biblio::Search const type =
243                 fl_get_button(dialog_->check_search_type) ?
244                 biblio::REGEX : biblio::SIMPLE;
245
246         vector<string>::const_iterator start = bibkeys.begin();
247         int const sel = fl_get_browser(dialog_->browser_bib);
248         if (sel >= 1 && sel <= int(bibkeys.size()))
249                 start += sel - 1;
250
251         // Find the NEXT instance...
252         (dir == biblio::FORWARD) ? ++start : --start;
253
254
255         vector<string>::const_iterator const cit =
256                 biblio::searchKeys(theMap, bibkeys, str,
257                                    start, type, dir, caseSensitive);
258
259         if (cit == bibkeys.end())
260                 return;
261
262         int const found = int(cit - bibkeys.begin()) + 1;
263         if (found == sel)
264                 return;
265
266         // Update the display
267         int const top = max(found - 5, 1);
268         fl_set_browser_topline(dialog_->browser_bib, top);
269         fl_select_browser_line(dialog_->browser_bib, found);
270         input(dialog_->browser_bib, 0);
271 }
272
273
274 ButtonPolicy::SMInput FormCitation::input(FL_OBJECT * ob, long)
275 {
276         ButtonPolicy::SMInput activate = ButtonPolicy::SMI_NOOP;
277
278         biblio::InfoMap const & theMap = controller().bibkeysInfo();
279
280         string topCitekey;
281         if (!citekeys.empty()) topCitekey = citekeys[0];
282
283         if (ob == dialog_->browser_bib) {
284                 fl_deselect_browser(dialog_->browser_cite);
285
286                 unsigned int const sel = fl_get_browser(dialog_->browser_bib);
287                 if (sel < 1 || sel > bibkeys.size())
288                         return ButtonPolicy::SMI_NOOP;
289
290                 // Put into browser_info the additional info associated with
291                 // the selected browser_bib key
292                 fl_clear_browser(dialog_->browser_info);
293
294                 string const tmp = formatted(biblio::getInfo(theMap,
295                                                              bibkeys[sel-1]),
296                                              dialog_->browser_info->w-10);
297                 fl_add_browser_line(dialog_->browser_info, tmp.c_str());
298
299                 // Highlight the selected browser_bib key in browser_cite if
300                 // present
301                 vector<string>::const_iterator cit =
302                         find(citekeys.begin(), citekeys.end(), bibkeys[sel-1]);
303
304                 if (cit != citekeys.end()) {
305                         int const n = int(cit - citekeys.begin());
306                         fl_select_browser_line(dialog_->browser_cite, n+1);
307                         fl_set_browser_topline(dialog_->browser_cite, n+1);
308                 }
309
310                 if (!controller().isReadonly()) {
311                         if (cit != citekeys.end()) {
312                                 setBibButtons(OFF);
313                                 setCiteButtons(ON);
314                         } else {
315                                 setBibButtons(ON);
316                                 setCiteButtons(OFF);
317                         }
318                 }
319
320         } else if (ob == dialog_->browser_cite) {
321                 unsigned int const sel = fl_get_browser(dialog_->browser_cite);
322                 if (sel < 1 || sel > citekeys.size())
323                         return ButtonPolicy::SMI_NOOP;
324
325                 if (!controller().isReadonly()) {
326                         setBibButtons(OFF);
327                         setCiteButtons(ON);
328                 }
329
330                 // Highlight the selected browser_cite key in browser_bib
331                 vector<string>::const_iterator cit =
332                         find(bibkeys.begin(), bibkeys.end(), citekeys[sel-1]);
333
334                 if (cit != bibkeys.end()) {
335                         int const n = int(cit - bibkeys.begin());
336                         fl_select_browser_line(dialog_->browser_bib, n+1);
337                         fl_set_browser_topline(dialog_->browser_bib, n+1);
338
339                         // Put into browser_info the additional info associated
340                         // with the selected browser_cite key
341                         fl_clear_browser(dialog_->browser_info);
342                         string const tmp =
343                                 formatted(biblio::getInfo(theMap,
344                                                           citekeys[sel-1]),
345                                           dialog_->browser_info->w-10);
346                         fl_add_browser_line(dialog_->browser_info, tmp.c_str());
347                 }
348
349         } else if (ob == dialog_->button_add) {
350                 unsigned int const sel = fl_get_browser(dialog_->browser_bib);
351                 if (sel < 1 || sel > bibkeys.size())
352                         return ButtonPolicy::SMI_NOOP;
353
354                 // Add the selected browser_bib key to browser_cite
355                 fl_addto_browser(dialog_->browser_cite,
356                                  bibkeys[sel-1].c_str());
357                 citekeys.push_back(bibkeys[sel-1]);
358
359                 int const n = int(citekeys.size());
360                 fl_select_browser_line(dialog_->browser_cite, n);
361
362                 setBibButtons(OFF);
363                 setCiteButtons(ON);
364                 activate = ButtonPolicy::SMI_VALID;
365
366         } else if (ob == dialog_->button_del) {
367                 unsigned int const sel = fl_get_browser(dialog_->browser_cite);
368                 if (sel < 1 || sel > citekeys.size())
369                         return ButtonPolicy::SMI_NOOP;
370
371                 // Remove the selected key from browser_cite
372                 fl_delete_browser_line(dialog_->browser_cite, sel) ;
373                 citekeys.erase(citekeys.begin() + sel-1);
374
375                 setBibButtons(ON);
376                 setCiteButtons(OFF);
377                 activate = ButtonPolicy::SMI_VALID;
378
379         } else if (ob == dialog_->button_up) {
380                 unsigned int const sel = fl_get_browser(dialog_->browser_cite);
381                 if (sel < 2 || sel > citekeys.size())
382                         return ButtonPolicy::SMI_NOOP;
383
384                 // Move the selected key up one line
385                 vector<string>::iterator it = citekeys.begin() + sel-1;
386                 string const tmp = *it;
387
388                 fl_delete_browser_line(dialog_->browser_cite, sel);
389                 citekeys.erase(it);
390
391                 fl_insert_browser_line(dialog_->browser_cite, sel-1, tmp.c_str());
392                 fl_select_browser_line(dialog_->browser_cite, sel-1);
393                 citekeys.insert(it-1, tmp);
394                 setCiteButtons(ON);
395                 activate = ButtonPolicy::SMI_VALID;
396
397         } else if (ob == dialog_->button_down) {
398                 unsigned int const sel = fl_get_browser(dialog_->browser_cite);
399                 if (sel < 1 || sel > citekeys.size()-1)
400                         return ButtonPolicy::SMI_NOOP;
401
402                 // Move the selected key down one line
403                 vector<string>::iterator it = citekeys.begin() + sel-1;
404                 string const tmp = *it;
405
406                 fl_delete_browser_line(dialog_->browser_cite, sel);
407                 citekeys.erase(it);
408
409                 fl_insert_browser_line(dialog_->browser_cite, sel+1, tmp.c_str());
410                 fl_select_browser_line(dialog_->browser_cite, sel+1);
411                 citekeys.insert(it+1, tmp);
412                 setCiteButtons(ON);
413                 activate = ButtonPolicy::SMI_VALID;
414
415         } else if (ob == dialog_->button_previous) {
416                 findBiblio(biblio::BACKWARD);
417         } else if (ob == dialog_->button_next) {
418                 findBiblio(biblio::FORWARD);
419         } else if (ob == dialog_->input_search) {
420                 findBiblio(biblio::FORWARD);
421         } else if (ob == dialog_->choice_style ||
422                    ob == dialog_->check_full_author_list ||
423                    ob == dialog_->check_force_uppercase ||
424                    ob == dialog_->input_before ||
425                    ob == dialog_->input_after) {
426                 activate = ButtonPolicy::SMI_VALID;
427         }
428
429         string currentCitekey;
430         if (!citekeys.empty())
431                 currentCitekey = citekeys[0];
432
433         if (topCitekey != currentCitekey) {
434                 int choice = std::max(1, fl_get_choice(dialog_->choice_style));
435                 fillChoice(dialog_.get(),
436                            controller().getCiteStrings(currentCitekey));
437                 fl_set_choice(dialog_->choice_style, choice);
438         }
439
440         return activate;
441 }
442
443
444 void FormCitation::update()
445 {
446         // Make the list of all available bibliography keys
447         bibkeys = biblio::getKeys(controller().bibkeysInfo());
448         updateBrowser(dialog_->browser_bib, bibkeys);
449
450         // Ditto for the keys cited in this inset
451         citekeys = getVectorFromString(controller().params().getContents());
452         updateBrowser(dialog_->browser_cite, citekeys);
453
454         // Use the first citekey to fill choice_style
455         string key;
456         if (!citekeys.empty()) key = citekeys[0];
457
458         fillChoice(dialog_.get(), controller().getCiteStrings(key));
459
460         // Use the citation command to update the GUI
461         updateStyle(dialog_.get(), controller().params().getCmdName());
462
463         bool const natbib = controller().usingNatbib();
464         setEnabled(dialog_->check_full_author_list, natbib);
465         setEnabled(dialog_->check_force_uppercase, natbib);
466         setEnabled(dialog_->choice_style, natbib);
467
468         // No keys have been selected yet, so...
469         fl_clear_browser(dialog_->browser_info);
470         setBibButtons(OFF);
471         setCiteButtons(OFF);
472
473         // Natbib can have comments before and after the citation.
474         // This is not yet supported. After only.
475         fl_set_input(dialog_->input_after,
476                      controller().params().getOptions().c_str());
477
478         fl_set_input(dialog_->input_before, _("Not yet supported"));
479         setEnabled(dialog_->input_before, false);
480 }
481
482
483 void FormCitation::updateBrowser(FL_OBJECT * browser,
484                                  vector<string> const & keys) const
485 {
486         // Check whether the current contents of the browser will be
487         // changed by loading the contents of the vec...
488         vector<string> browser_keys = getVectorFromBrowser(browser);
489
490         if (browser_keys == keys)
491                 return;
492
493         // They will be changed. Proceed.
494         fl_clear_browser(browser);
495
496         for (vector<string>::const_iterator it = keys.begin();
497              it < keys.end(); ++it) {
498                 string key = frontStrip(strip(*it));
499                 if (!key.empty())
500                         fl_add_browser_line(browser, key.c_str());
501         }
502 }
503
504
505 void FormCitation::setBibButtons(State status) const
506 {
507         setEnabled(dialog_->button_add, (status == ON));
508 }
509
510
511 void FormCitation::setCiteButtons(State status) const
512 {
513         int const sel     = fl_get_browser(dialog_->browser_cite);
514         int const maxline = fl_get_browser_maxline(dialog_->browser_cite);
515         bool const activate      = (status == ON);
516         bool const activate_up   = (activate && sel != 1);
517         bool const activate_down = (activate && sel != maxline);
518
519         setEnabled(dialog_->button_del,  activate);
520         setEnabled(dialog_->button_up,   activate_up);
521         setEnabled(dialog_->button_down, activate_down);
522 }