]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormCitation.C
patch from Angus and patch from Kayvan
[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 The LyX Team.
8  *
9  * ======================================================
10  */
11
12 #include <config.h>
13 #include "gettext.h"
14 #include FORMS_H_LOCATION
15 #include "BufferView.h"
16 #include "Dialogs.h"
17 #include "FormCitation.h"
18 #include "LyXView.h"
19 #include "buffer.h"
20 #include "form_citation.h"
21 #include "lyxfunc.h"
22 #include "xform_macros.h"
23 #include "insets/insetcite.h"
24 #include "support/filetools.h"
25
26 #ifdef __GNUG__
27 #pragma implementation
28 #endif
29
30 using std::vector;
31 using std::pair;
32 using std::max;
33 using std::min;
34 using std::find;
35
36 C_RETURNCB(FormCitation, WMHideCB)
37 C_GENERICCB(FormCitation, OKCB)
38 C_GENERICCB(FormCitation, CancelCB)
39 C_GENERICCB(FormCitation, InputCB)
40
41 FormCitation::FormCitation(LyXView * lv, Dialogs * d)
42         : dialog_(0), lv_(lv), d_(d), u_(0), h_(0), ih_(0),
43           inset_(0), dialogIsOpen(false)
44 {
45         // let the dialog be shown
46         // These are permanent connections so we won't bother
47         // storing a copy because we won't be disconnecting.
48         d->showCitation.connect(slot(this, &FormCitation::showInset));
49         d->createCitation.connect(slot(this, &FormCitation::createInset));
50 }
51
52
53 FormCitation::~FormCitation()
54 {
55         free();
56 }
57
58
59 void FormCitation::build()
60 {
61         dialog_ = build_citation();
62 }
63
64
65 void FormCitation::showInset( InsetCitation * inset )
66 {
67         if( dialogIsOpen || inset == 0 ) return;
68
69         inset_ = inset;
70         ih_ = inset_->hide.connect(slot(this, &FormCitation::hide));
71
72         textAfter = inset->getOptions();
73         updateCitekeys(inset->getContents());
74         show();
75 }
76
77
78 void FormCitation::createInset( string const & arg )
79 {
80         if( dialogIsOpen ) return;
81
82         string keys;
83         if (contains(arg, "|")) {
84                 keys = token(arg, '|', 0);
85                 textAfter = token(arg, '|', 1);
86         } else {
87                 keys = arg;
88                 textAfter.erase();
89         }
90
91         updateCitekeys(keys);
92         show();
93 }
94
95
96 void FormCitation::show()
97 {
98         if (!dialog_) {
99                 build();
100                 fl_set_form_atclose(dialog_->form_citation,
101                                     C_FormCitationWMHideCB, 0);
102         }
103
104         update();  // make sure its up-to-date
105
106         dialogIsOpen = true;
107         if (dialog_->form_citation->visible) {
108                 fl_raise_form(dialog_->form_citation);
109         } else {
110                 fl_show_form(dialog_->form_citation,
111                              FL_PLACE_MOUSE | FL_FREE_SIZE,
112                              FL_TRANSIENT,
113                              _("Citation"));
114                 u_ = d_->updateBufferDependent.
115                          connect(slot(this, &FormCitation::update));
116                 h_ = d_->hideBufferDependent.
117                          connect(slot(this, &FormCitation::hide));
118         }
119 }
120
121
122 void FormCitation::update()
123 {
124         bibkeys.clear();
125         bibkeysInfo.clear();
126
127         vector<pair<string,string> > blist =
128                 lv_->buffer()->getBibkeyList();
129
130         for( unsigned int i = 0; i < blist.size(); ++i ) {
131                 bibkeys.push_back(blist[i].first);
132                 bibkeysInfo.push_back(blist[i].second);
133         }
134
135         blist.clear();
136
137         fl_freeze_form( dialog_->form_citation );
138
139         updateBrowser( dialog_->bibBrsr, bibkeys );
140         updateBrowser( dialog_->citeBrsr, citekeys );
141         fl_clear_browser( dialog_->infoBrsr );
142
143         // No keys have been selected yet, so...
144         setBibButtons( OFF );
145         setCiteButtons( OFF );
146
147         int noKeys = max( bibkeys.size(), citekeys.size() );
148
149         // Place bounds, so that 4 <= noKeys <= 15
150         noKeys = max( 4, min(15, noKeys) );
151
152         // Re-size the form to accommodate the new browser size
153         int size = 20 * noKeys;
154         bool bibPresent = ( bibkeys.size() > 0 );
155         setSize( size, bibPresent );
156
157         fl_set_input( dialog_->textAftr, textAfter.c_str() );
158
159         fl_unfreeze_form( dialog_->form_citation );
160 }
161
162
163 void FormCitation::updateCitekeys( string const & keysIn )
164 {
165         citekeys.clear();
166
167         string tmp;
168         string keys = keysIn;
169         keys = frontStrip( split(keys, tmp, ',') );
170         while( !tmp.empty() ) {
171                 citekeys.push_back( tmp );
172                 keys = frontStrip( split(keys, tmp, ',') );
173         }
174 }
175
176
177 void FormCitation::updateBrowser( FL_OBJECT * browser,
178                                   vector<string> const & keys ) const
179 {
180         fl_clear_browser( browser );
181
182         for( unsigned int i = 0; i < keys.size(); ++i )
183                 fl_add_browser_line( browser, keys[i].c_str() );
184 }
185
186
187 void FormCitation::setBibButtons( State status ) const
188 {
189         switch (status) {
190         case ON:
191                 fl_activate_object( dialog_->addBtn );
192                 fl_set_object_lcol( dialog_->addBtn, FL_BLACK );
193                 break;
194
195         case OFF:
196                 fl_deactivate_object( dialog_->addBtn );
197                 fl_set_object_lcol( dialog_->addBtn, FL_INACTIVE );
198                 break;
199
200         default:
201                 break;
202         }
203 }
204
205
206 void FormCitation::setCiteButtons( State status ) const
207 {
208         switch( status ) {
209         case ON:
210         {
211                 fl_activate_object( dialog_->delBtn );
212                 fl_set_object_lcol( dialog_->delBtn, FL_BLACK );
213
214                 int sel = fl_get_browser( dialog_->citeBrsr );
215
216                 if( sel != 1 ) {
217                         fl_activate_object( dialog_->upBtn );
218                         fl_set_object_lcol( dialog_->upBtn, FL_BLACK );
219                 } else {
220                         fl_deactivate_object( dialog_->upBtn );
221                         fl_set_object_lcol( dialog_->upBtn, FL_INACTIVE );
222                 }
223
224                 if( sel != fl_get_browser_maxline(dialog_->citeBrsr)) {
225                         fl_activate_object( dialog_->downBtn );
226                         fl_set_object_lcol( dialog_->downBtn, FL_BLACK );
227                 } else {
228                         fl_deactivate_object( dialog_->downBtn );
229                         fl_set_object_lcol( dialog_->downBtn, FL_INACTIVE );
230                 }
231
232                 break;
233         }
234         case OFF:
235         {
236                 fl_deactivate_object( dialog_->delBtn );
237                 fl_set_object_lcol( dialog_->delBtn, FL_INACTIVE );
238
239                 fl_deactivate_object( dialog_->upBtn );
240                 fl_set_object_lcol( dialog_->upBtn, FL_INACTIVE );
241
242                 fl_deactivate_object( dialog_->downBtn );
243                 fl_set_object_lcol( dialog_->downBtn, FL_INACTIVE );
244         }
245         default:
246                 break;
247         }
248 }
249
250
251 void FormCitation::setSize( int brsrHeight, bool bibPresent ) const
252 {
253         int const infoHeight  = 110;
254         int const otherHeight = 140;
255         brsrHeight = max( brsrHeight, 175 );
256         int formHeight = brsrHeight + otherHeight;
257
258         if( bibPresent ) formHeight += infoHeight + 30;
259         fl_set_form_size( dialog_->form_citation, 430, formHeight );
260
261         // No resizing is alowed in the y-direction
262         fl_set_form_minsize( dialog_->form_citation, 430, formHeight );
263         fl_set_form_maxsize( dialog_->form_citation, 1000, formHeight );
264
265         int ypos = 0;
266         fl_set_object_geometry( dialog_->box,      0,   ypos, 430, formHeight );
267         ypos += 30;
268         fl_set_object_geometry( dialog_->citeBrsr, 10,  ypos, 180, brsrHeight );
269         fl_set_object_geometry( dialog_->bibBrsr,  240, ypos, 180, brsrHeight );
270
271         fl_set_object_position( dialog_->addBtn,  200, ypos );
272         ypos += 35;
273         fl_set_object_position( dialog_->delBtn,  200, ypos );
274         ypos += 35;
275         fl_set_object_position( dialog_->upBtn,   200, ypos );
276         ypos += 35;
277         fl_set_object_position( dialog_->downBtn, 200, ypos );
278
279         ypos = brsrHeight+30; // base of Citation/Bibliography browsers
280
281         // awaiting natbib support
282         fl_hide_object( dialog_->style );
283
284         if( bibPresent ) {
285                 ypos += 30;
286                 fl_set_object_position( dialog_->infoBrsr, 10, ypos );
287                 fl_show_object( dialog_->infoBrsr );
288                 ypos += infoHeight;
289         }
290         else
291                 fl_hide_object( dialog_->infoBrsr );
292
293         ypos += 20;
294         // awaiting natbib support
295         fl_hide_object( dialog_->textBefore );
296
297         fl_set_object_position( dialog_->textAftr, 100, ypos );
298         fl_set_object_position( dialog_->ok,       230, ypos+50 );
299         fl_set_object_position( dialog_->cancel,   330, ypos+50 );
300 }
301
302
303 void FormCitation::input( State cb )
304 {
305         switch( cb ) {
306         case BIBBRSR:
307         {
308                 fl_deselect_browser( dialog_->citeBrsr );
309                 
310                 unsigned int sel = fl_get_browser( dialog_->bibBrsr );
311                 if( sel < 1 || sel > bibkeys.size() ) break;
312
313                 // Put into infoBrsr the additional info associated with
314                 // the selected bibBrsr key
315                 fl_clear_browser( dialog_->infoBrsr );
316                 fl_add_browser_line( dialog_->infoBrsr,
317                                      bibkeysInfo[sel-1].c_str() );
318
319                 // Highlight the selected bibBrsr key in citeBrsr if present
320                 vector<string>::iterator it =
321                         find( citekeys.begin(), citekeys.end(), bibkeys[sel-1] );
322
323                 if( it != citekeys.end() ) {
324                         int n = it - citekeys.begin();
325                         fl_select_browser_line( dialog_->citeBrsr, n+1 );
326                         fl_set_browser_topline( dialog_->citeBrsr, n+1 );
327                 }
328
329                 if( !lv_->buffer()->isReadonly() ) {
330                         if( it != citekeys.end() ) {
331                                 setBibButtons( OFF );
332                                 setCiteButtons( ON );
333                         } else {
334                                 setBibButtons( ON );
335                                 setCiteButtons( OFF );
336                         }
337                 }
338         }
339         break;
340         case CITEBRSR:
341         {
342                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
343                 if( sel < 1 || sel > citekeys.size() ) break;
344
345                 if( !lv_->buffer()->isReadonly() ) {
346                         setBibButtons( OFF );
347                         setCiteButtons( ON );
348                 }
349
350                 // Highlight the selected citeBrsr key in bibBrsr
351                 vector<string>::iterator it =
352                         find( bibkeys.begin(), bibkeys.end(), citekeys[sel-1] );
353
354                 if (it != bibkeys.end()) {
355                         int n = it - bibkeys.begin();
356                         fl_select_browser_line( dialog_->bibBrsr, n+1 );
357                         fl_set_browser_topline( dialog_->bibBrsr, n+1 );
358
359                         // Put into infoBrsr the additional info associated with
360                         // the selected citeBrsr key
361                         fl_clear_browser( dialog_->infoBrsr );
362                         fl_add_browser_line( dialog_->infoBrsr,
363                                              bibkeysInfo[n].c_str() );
364                 }
365         }
366         break;
367         case ADD:
368         {
369                 if( lv_->buffer()->isReadonly() ) break;
370
371                 unsigned int sel = fl_get_browser( dialog_->bibBrsr );
372                 if( sel < 1 || sel > bibkeys.size() ) break;
373
374                 // Add the selected bibBrsr key to citeBrsr
375                 fl_addto_browser( dialog_->citeBrsr,
376                                   bibkeys[sel-1].c_str() );
377                 citekeys.push_back( bibkeys[sel-1] );
378
379                 int n = citekeys.size();
380                 fl_select_browser_line( dialog_->citeBrsr, n );
381
382                 setBibButtons( OFF );
383                 setCiteButtons( ON );
384         }
385         break;
386         case DELETE:
387         {
388                 if( lv_->buffer()->isReadonly() ) break;
389
390                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
391                 if( sel < 1 || sel > citekeys.size() ) break;
392
393                 // Remove the selected key from citeBrsr
394                 fl_delete_browser_line( dialog_->citeBrsr, sel ) ;
395                 citekeys.erase( citekeys.begin() + sel-1 );
396
397                 setBibButtons( ON );
398                 setCiteButtons( OFF );
399         }
400         break;
401         case UP:
402         {
403                 if( lv_->buffer()->isReadonly() ) break;
404
405                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
406                 if( sel < 2 || sel > citekeys.size() ) break;
407
408                 // Move the selected key up one line
409                 vector<string>::iterator it = citekeys.begin() + sel-1;
410                 string tmp = *it;
411
412                 fl_delete_browser_line( dialog_->citeBrsr, sel );
413                 citekeys.erase( it );
414
415                 fl_insert_browser_line( dialog_->citeBrsr, sel-1, tmp.c_str() );
416                 fl_select_browser_line( dialog_->citeBrsr, sel-1 );
417                 citekeys.insert( it-1, tmp );
418                 setCiteButtons( ON );
419         }
420         break;
421         case DOWN:
422         {
423                 if( lv_->buffer()->isReadonly() ) break;
424
425                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
426                 if( sel < 1 || sel > citekeys.size()-1 ) break;
427
428                 // Move the selected key down one line
429                 vector<string>::iterator it = citekeys.begin() + sel-1;
430                 string tmp = *it;
431
432                 fl_delete_browser_line( dialog_->citeBrsr, sel );
433                 citekeys.erase( it );
434
435                 fl_insert_browser_line( dialog_->citeBrsr, sel+1, tmp.c_str() );
436                 fl_select_browser_line( dialog_->citeBrsr, sel+1 );
437                 citekeys.insert( it+1, tmp );
438                 setCiteButtons( ON );
439         }
440         break;
441         default:
442                 break;
443         }
444 }
445
446
447 void FormCitation::apply()
448 {
449         if( lv_->buffer()->isReadonly() ) return;
450
451         string contents;
452         for( unsigned int i = 0; i < citekeys.size(); ++i ) {
453                 if (i > 0) contents += ", ";
454                 contents += citekeys[i];
455         }
456
457         textAfter = fl_get_input(dialog_->textAftr);
458
459         if( inset_ != 0 )
460         {
461                 inset_->setContents( contents );
462                 inset_->setOptions( textAfter );
463                 lv_->view()->updateInset( inset_, true );
464         } else {
465                 InsetCommandParams p( "cite", contents, textAfter );
466                 lv_->getLyXFunc()->Dispatch( LFUN_INSERT_CITATION,
467                                              p.getAsString().c_str() );
468         }
469 }
470
471
472 void FormCitation::hide()
473 {
474         if (dialog_
475             && dialog_->form_citation
476             && dialog_->form_citation->visible) {
477                 fl_hide_form(dialog_->form_citation);
478                 u_.disconnect();
479                 h_.disconnect();
480         }
481
482         // free up the dialog for another inset
483         inset_ = 0;
484         ih_.disconnect();
485         dialogIsOpen = false;
486 }
487
488
489 void FormCitation::free()
490 {
491         // we don't need to delete u and h here because
492         // hide() does that after disconnecting.
493         if (dialog_) {
494                 if (dialog_->form_citation
495                     && dialog_->form_citation->visible) {
496                         hide();
497                 }
498                 fl_free_form(dialog_->form_citation);
499                 delete dialog_;
500                 dialog_ = 0;
501         }
502 }
503
504
505 int FormCitation::WMHideCB(FL_FORM * form, void *)
506 {
507         // Ensure that the signals (u and h) are disconnected even if the
508         // window manager is used to close the dialog.
509         FormCitation * pre = static_cast<FormCitation*>(form->u_vdata);
510         pre->hide();
511         return FL_CANCEL;
512 }
513
514
515 void FormCitation::OKCB(FL_OBJECT * ob, long)
516 {
517         FormCitation * pre = static_cast<FormCitation*>(ob->form->u_vdata);
518         pre->apply();
519         pre->hide();
520 }
521
522
523 void FormCitation::CancelCB(FL_OBJECT * ob, long)
524 {
525         FormCitation * pre = static_cast<FormCitation*>(ob->form->u_vdata);
526         pre->hide();
527 }
528
529
530 void FormCitation::InputCB(FL_OBJECT * ob, long data)
531 {
532         FormCitation * pre = static_cast<FormCitation*>(ob->form->u_vdata);
533         pre->input( static_cast<FormCitation::State>(data) );
534 }