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