]> git.lyx.org Git - lyx.git/blob - src/insets/insetcite.C
3e657546d368b44643a86c024334fed8f5cad2b8
[lyx.git] / src / insets / insetcite.C
1 #include <config.h>
2
3 #include <fstream>
4 #include <cstdlib>
5 #include <algorithm>
6
7 #ifdef __GNUG__
8 #pragma implementation
9 #endif
10
11 #include FORMS_H_LOCATION  
12 #include "insetcite.h"
13 #include "buffer.h"
14 #include "debug.h"
15 #include "lyx_gui_misc.h"
16 #include "BufferView.h"
17 #include "gettext.h"
18 #include "lyxtext.h"
19 #include "support/filetools.h"
20
21 using std::getline;
22 using std::vector;
23 using std::pair;
24 using std::max;
25 using std::min;
26 using std::find;
27
28 FD_citation_form * citation_form = 0;
29 FD_citation_form * create_form_citation_form(void);
30 void set_size_citation_form(FD_citation_form *, int, bool);
31
32 static vector<pair<string,string> > bibkeys_info;
33 static vector<string> bibkeys;
34 static vector<string> insetkeys;
35
36 extern "C" void citation_cb( FL_OBJECT *, long data )
37 {
38         InsetCitation::Holder * holder =
39                 static_cast<InsetCitation::Holder*>(citation_form->form->u_vdata);
40
41         holder->inset->callback( citation_form,
42                                  static_cast<InsetCitation::State>(data) );
43 }
44
45
46 FD_citation_form * create_form_citation_form(void)
47 {
48         FL_OBJECT * obj;
49         FD_citation_form * fdui = (FD_citation_form *) fl_calloc(1, sizeof(*fdui));
50
51         // NOTE: dialog geometry is set in setSize(). 
52         // Initial size is simply non-zero.
53         fdui->form = fl_bgn_form(FL_NO_BOX, 10, 10);
54         fdui->box = obj = fl_add_box(FL_UP_BOX, 0, 0, 10, 10, "");
55
56         fdui->citeBrsr = obj =
57           fl_add_browser(FL_HOLD_BROWSER, 0, 0, 10, 10, _("Citation keys"));
58         fl_set_object_lalign(obj, FL_ALIGN_TOP_LEFT);
59         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
60         fl_set_object_callback(obj, citation_cb, InsetCitation::CITEBRSR);
61
62         fdui->bibBrsr = obj =
63           fl_add_browser(FL_HOLD_BROWSER, 0, 0, 10, 10, _("Bibliography keys"));
64         fl_set_object_lalign(obj, FL_ALIGN_TOP_LEFT);
65         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
66         fl_set_object_callback(obj, citation_cb, InsetCitation::BIBBRSR);
67
68         fdui->addBtn = obj =
69           fl_add_button(FL_NORMAL_BUTTON, 0, 0, 10, 10, "@4->");
70         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
71         fl_set_object_callback(obj, citation_cb, InsetCitation::ADD);
72
73         fdui->delBtn = obj =
74           fl_add_button(FL_NORMAL_BUTTON, 0, 0, 10, 10, "@9+");
75         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
76         fl_set_object_callback(obj, citation_cb, InsetCitation::DELETE);
77
78         fdui->upBtn = obj =
79           fl_add_button(FL_NORMAL_BUTTON, 0, 0, 10, 10, "@8->");
80         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
81         fl_set_object_callback(obj, citation_cb, InsetCitation::UP);
82         
83         fdui->downBtn = obj =
84           fl_add_button(FL_NORMAL_BUTTON, 0, 0, 10, 10, "@2->");
85         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
86         fl_set_object_callback(obj, citation_cb, InsetCitation::DOWN);
87
88         fdui->infoBrsr = obj =
89           fl_add_browser(FL_NORMAL_BROWSER, 0, 0, 10, 10, _("Info"));
90           fl_set_object_lsize(obj, FL_NORMAL_SIZE) ;
91           fl_set_object_lalign(obj, FL_ALIGN_TOP_LEFT);
92
93         fdui->textAftr = obj =
94           fl_add_input(FL_NORMAL_INPUT, 0, 0, 10, 10, _("Text after"));
95         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
96
97         fdui->ok = obj =
98           fl_add_button(FL_RETURN_BUTTON, 0, 0, 10, 10, _("OK"));
99         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
100         fl_set_object_callback(obj, citation_cb, InsetCitation::OK);
101
102         fdui->cancel = obj =
103           fl_add_button(FL_NORMAL_BUTTON, 0, 0, 10, 10, idex(_("Cancel|^[")));
104         fl_set_button_shortcut(obj, scex(_("Cancel|^[")), 1);
105         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
106         fl_set_object_callback(obj, citation_cb, InsetCitation::CANCEL);
107
108         fl_end_form();
109   
110         return fdui;
111 }
112
113
114 InsetCitation::InsetCitation(string const & key, string const & note)
115         : InsetCommand("cite", key, note)
116 {
117 }
118
119
120 InsetCitation::~InsetCitation()
121 {
122         if(citation_form && citation_form->form
123            && citation_form->form->visible
124            && citation_form->form->u_vdata == &holder)
125                 fl_hide_form(citation_form->form);
126 }
127
128
129 void InsetCitation::Edit( BufferView * bv, int, int, unsigned int )
130 {
131         if ( !citation_form ) {
132                 citation_form = create_form_citation_form();
133                 fl_set_form_atclose( citation_form->form, 
134                                      CancelCloseBoxCB, 0 );
135         }
136
137         holder.inset = this;
138         holder.view = bv;
139                 
140         citation_form->form->u_vdata = &holder;
141
142         // update the browsers, noting the number of keys.
143         bibkeys_info = bv->buffer()->getBibkeyList();
144         bibkeys.clear();
145         insetkeys.clear();
146         for( unsigned int i = 0; i < bibkeys_info.size(); ++i )
147                 bibkeys.push_back(bibkeys_info[i].first);
148
149         string tmp;
150         string keys = getContents();
151         keys = frontStrip( split(keys, tmp, ',') );
152         while( !tmp.empty() ) {
153                 insetkeys.push_back( tmp );
154                 keys = frontStrip( split(keys, tmp, ',') );
155         }
156
157         updateBrowser( citation_form->bibBrsr, bibkeys );
158         updateBrowser( citation_form->citeBrsr, insetkeys );
159         fl_clear_browser( citation_form->infoBrsr );
160
161         // No keys have been selected yet, so...
162         setBibButtons(  citation_form, OFF );
163         setCiteButtons( citation_form, OFF );
164
165         int noKeys = max( bibkeys.size(), insetkeys.size() );
166
167         // Place bounds, so that 4 <= noKeys <= 15
168         noKeys = max( 4, min(15, noKeys) );
169
170         // Re-size the form to accommodate the new browser size
171         int size = 20 * noKeys;
172         bool bibPresent = ( bibkeys.size() > 0 );
173         setSize(citation_form, size, bibPresent);
174
175         fl_set_input( citation_form->textAftr, getOptions().c_str() );
176         if( holder.view->buffer()->isReadonly() )
177                 fl_deactivate_object( citation_form->textAftr );
178
179         if( citation_form->form->visible ) {
180                 fl_raise_form( citation_form->form );
181         } else {
182                 fl_show_form(citation_form->form,
183                              FL_PLACE_MOUSE | FL_FREE_SIZE,
184                              FL_FULLBORDER,
185                              _("Citation") );
186         }
187 }
188
189
190 void InsetCitation::updateBrowser( FL_OBJECT * browser,
191                                    vector<string> const & inkeys ) const
192 {
193         fl_clear_browser( browser );
194
195         fl_freeze_form( browser->form );
196         for( unsigned int i = 0; i < inkeys.size(); ++i )
197                 fl_add_browser_line( browser, inkeys[i].c_str() );
198         fl_unfreeze_form( browser->form );
199 }
200
201 void InsetCitation::callback( FD_citation_form * form, State cb )
202 {
203         switch( cb ) {
204         case BIBBRSR: {
205                 fl_deselect_browser( form->citeBrsr );
206                 
207                 unsigned int sel = fl_get_browser( form->bibBrsr );
208                 if( sel < 1 || sel > bibkeys.size() ) break;
209
210                 // Put into infoBrsr the additional info associated with
211                 // the selected bibBrsr key
212                 fl_clear_browser( form->infoBrsr );
213                 fl_add_browser_line( form->infoBrsr,
214                                      bibkeys_info[sel-1].second.c_str() );
215
216                 // Highlight the selected bibBrsr key in citeBrsr if present
217                 vector<string>::iterator it =
218                         find( insetkeys.begin(), insetkeys.end(), bibkeys[sel-1] );
219
220                 if( it != insetkeys.end() ) {
221                         int n = it - insetkeys.begin();
222                         fl_select_browser_line( form->citeBrsr, n+1 );
223                         fl_set_browser_topline( form->citeBrsr, n+1 );
224                 }
225
226                 if( !holder.view->buffer()->isReadonly() ) {
227                         if( it != insetkeys.end() ) {
228                                 setBibButtons(  form, OFF );
229                                 setCiteButtons( form, ON );
230                         } else {
231                                 setBibButtons(  form, ON );
232                                 setCiteButtons( form, OFF );
233                         }
234                 }
235                 break;
236
237         } case CITEBRSR: {
238                 unsigned int sel = fl_get_browser( form->citeBrsr );
239                 if( sel < 1 || sel > insetkeys.size() ) break;
240
241                 if( !holder.view->buffer()->isReadonly() ) {
242                         setBibButtons(  form, OFF );
243                         setCiteButtons( form, ON );
244                 }
245
246                 // Highlight the selected citeBrsr key in bibBrsr
247                 vector<string>::iterator it =
248                         find( bibkeys.begin(), bibkeys.end(), insetkeys[sel-1] );
249
250                 if (it != bibkeys.end()) {
251                         int n = it - bibkeys.begin();
252                         fl_select_browser_line( form->bibBrsr, n+1 );
253                         fl_set_browser_topline( form->bibBrsr, n+1 );
254
255                         // Put into infoBrsr the additional info associated with
256                         // the selected citeBrsr key
257                         fl_clear_browser( form->infoBrsr );
258                         fl_add_browser_line( form->infoBrsr,
259                                              bibkeys_info[n].second.c_str() );
260                 }
261                 break;
262
263         } case ADD: {
264                 if( holder.view->buffer()->isReadonly() ) break;
265
266                 unsigned int sel = fl_get_browser( form->bibBrsr );
267                 if( sel < 1 || sel > bibkeys.size() ) break;
268
269                 // Add the selected bibBrsr key to citeBrsr
270                 fl_addto_browser( form->citeBrsr,
271                                   bibkeys[sel-1].c_str() );
272                 insetkeys.push_back( bibkeys[sel-1] );
273
274                 int n = insetkeys.size();
275                 fl_select_browser_line( form->citeBrsr, n );
276
277                 setBibButtons(  form, OFF );
278                 setCiteButtons( form, ON );
279
280                 break;
281
282         } case DELETE: {
283                 if( holder.view->buffer()->isReadonly() ) break;
284
285                 unsigned int sel = fl_get_browser( form->citeBrsr );
286                 if( sel < 1 || sel > insetkeys.size() ) break;
287
288                 // Remove the selected key from citeBrsr
289                 fl_delete_browser_line( form->citeBrsr, sel ) ;
290                 insetkeys.erase( insetkeys.begin() + sel-1 );
291
292                 setBibButtons(  form, ON );
293                 setCiteButtons( form, OFF );
294                 break;
295
296         } case UP: {
297                 if( holder.view->buffer()->isReadonly() ) break;
298
299                 unsigned int sel = fl_get_browser( form->citeBrsr );
300                 if( sel < 2 || sel > insetkeys.size() ) break;
301
302                 // Move the selected key up one line
303                 vector<string>::iterator it = insetkeys.begin() + sel-1;
304                 string tmp = *it;
305
306                 fl_delete_browser_line( form->citeBrsr, sel );
307                 insetkeys.erase( it );
308
309                 fl_insert_browser_line( form->citeBrsr, sel-1, tmp.c_str() );
310                 fl_select_browser_line( form->citeBrsr, sel-1 );
311                 insetkeys.insert( it-1, tmp );
312                 setCiteButtons( form, ON );
313
314                 break;
315
316         } case DOWN: {
317                 if( holder.view->buffer()->isReadonly() ) break;
318
319                 unsigned int sel = fl_get_browser( form->citeBrsr );
320                 if( sel < 1 || sel > insetkeys.size()-1 ) break;
321
322                 // Move the selected key down one line
323                 vector<string>::iterator it = insetkeys.begin() + sel-1;
324                 string tmp = *it;
325
326                 fl_delete_browser_line( form->citeBrsr, sel );
327                 insetkeys.erase( it );
328
329                 fl_insert_browser_line( form->citeBrsr, sel+1, tmp.c_str() );
330                 fl_select_browser_line( form->citeBrsr, sel+1 );
331                 insetkeys.insert( it+1, tmp );
332                 setCiteButtons( form, ON );
333
334                 break;
335
336         } case OK: {
337                 // The inset contains a comma separated list of the keys
338                 // in citeBrsr
339                 if( !holder.view->buffer()->isReadonly() )
340                 {
341                         string tmp;
342                         for( unsigned int i = 0; i < insetkeys.size(); ++i ) {
343                                 if (i > 0)
344                                         tmp += ", ";
345                                 tmp += insetkeys[i];
346                         }
347                         setContents( tmp );
348                         setOptions( fl_get_input(form->textAftr) );
349                         // shouldn't mark the buffer dirty unless something
350                         // was actually altered
351                         holder.view->updateInset( this, true );
352                 }
353                 // fall through to Cancel
354
355         } case CANCEL: {
356                 fl_hide_form( form->form );
357                 break;
358
359         } default:
360                 break;
361         }
362 }
363
364
365 void InsetCitation::setSize( FD_citation_form * form,
366                              int brsrHeight, bool bibPresent ) const
367 {
368         int const infoHeight  = 110;
369         int const otherHeight = 140;
370         brsrHeight = max( brsrHeight, 175 );
371         int formHeight = brsrHeight + otherHeight;
372
373         if( bibPresent ) formHeight += infoHeight + 30;
374         fl_set_form_size( form->form, 430, formHeight );
375
376         int ypos = 0;
377         fl_set_object_geometry( form->box,      0,   ypos, 430, formHeight );
378         ypos += 30;
379         fl_set_object_geometry( form->citeBrsr, 10,  ypos, 180, brsrHeight );
380         fl_set_object_geometry( form->bibBrsr,  240, ypos, 180, brsrHeight );
381         fl_set_object_geometry( form->addBtn,   200, ypos,  30, 30 );
382         ypos += 35;
383         fl_set_object_geometry( form->delBtn,   200, ypos,  30, 30 );
384         ypos += 35;
385         fl_set_object_geometry( form->upBtn,    200, ypos,  30, 30 );
386         ypos += 35;
387         fl_set_object_geometry( form->downBtn,  200, ypos,  30, 30 );
388
389         ypos = brsrHeight+30; // base of Citation/Bibliography browsers
390
391         if( bibPresent ) {
392                 ypos += 30;
393                 fl_set_object_geometry( form->infoBrsr, 10, ypos, 410, infoHeight );
394                 fl_show_object( form->infoBrsr );
395                 ypos += infoHeight;
396         }
397         else
398                 fl_hide_object( form->infoBrsr );
399
400         ypos += 20;
401         fl_set_object_geometry( form->textAftr, 100, ypos,   250, 30 );
402         fl_set_object_geometry( form->ok,       230, ypos+50, 90, 30 );
403         fl_set_object_geometry( form->cancel,   330, ypos+50, 90, 30 );
404 }
405
406
407 void InsetCitation::setBibButtons( FD_citation_form * form, State status ) const
408 {
409         switch (status) {
410         case ON:
411         {
412                 fl_activate_object( form->addBtn );
413                 fl_set_object_lcol( form->addBtn, FL_BLACK );
414
415                 break;
416         }
417         case OFF:
418         {
419                 fl_deactivate_object( form->addBtn );
420                 fl_set_object_lcol( form->addBtn, FL_INACTIVE );
421         }
422         default:
423                 break;
424         }
425 }
426
427
428 void InsetCitation::setCiteButtons( FD_citation_form * form, State status ) const
429 {
430         switch( status ) {
431         case ON:
432         {
433                 fl_activate_object( form->delBtn );
434                 fl_set_object_lcol( form->delBtn, FL_BLACK );
435
436                 int sel = fl_get_browser( form->citeBrsr );
437
438                 if( sel != 1 ) {
439                         fl_activate_object( form->upBtn );
440                         fl_set_object_lcol( form->upBtn, FL_BLACK );
441                 } else {
442                         fl_deactivate_object( form->upBtn );
443                         fl_set_object_lcol( form->upBtn, FL_INACTIVE );
444                 }
445
446                 if( sel != fl_get_browser_maxline(form->citeBrsr)) {
447                         fl_activate_object( form->downBtn );
448                         fl_set_object_lcol( form->downBtn, FL_BLACK );
449                 } else {
450                         fl_deactivate_object( form->downBtn );
451                         fl_set_object_lcol( form->downBtn, FL_INACTIVE );
452                 }
453
454                 break;
455         }
456         case OFF:
457         {
458                 fl_deactivate_object( form->delBtn );
459                 fl_set_object_lcol( form->delBtn, FL_INACTIVE );
460
461                 fl_deactivate_object( form->upBtn );
462                 fl_set_object_lcol( form->upBtn, FL_INACTIVE );
463
464                 fl_deactivate_object( form->downBtn );
465                 fl_set_object_lcol( form->downBtn, FL_INACTIVE );
466         }
467         default:
468                 break;
469         }
470 }
471
472
473 string InsetCitation::getScreenLabel() const
474 {
475         string temp("[");
476
477         temp += getContents();
478
479         if( !getOptions().empty() ) {
480                 temp += ", " + getOptions();
481         }
482
483         return temp + ']';
484 }