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