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