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