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