]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormCitation.C
Anguses patch + some modifications for smart? inset-update.
[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
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         updateBrowser( dialog_->bibBrsr, bibkeys );
138         updateBrowser( dialog_->citeBrsr, citekeys );
139         fl_clear_browser( dialog_->infoBrsr );
140
141         // No keys have been selected yet, so...
142         setBibButtons( OFF );
143         setCiteButtons( OFF );
144
145         int noKeys = max( bibkeys.size(), citekeys.size() );
146
147         // Place bounds, so that 4 <= noKeys <= 15
148         noKeys = max( 4, min(15, noKeys) );
149
150         // Re-size the form to accommodate the new browser size
151         int size = 20 * noKeys;
152         bool bibPresent = ( bibkeys.size() > 0 );
153         setSize( size, bibPresent );
154
155         fl_set_input( dialog_->textAftr, textAfter.c_str() );
156 }
157
158
159 void FormCitation::updateCitekeys( string const & keysIn )
160 {
161         citekeys.clear();
162
163         string tmp;
164         string keys = keysIn;
165         keys = frontStrip( split(keys, tmp, ',') );
166         while( !tmp.empty() ) {
167                 citekeys.push_back( tmp );
168                 keys = frontStrip( split(keys, tmp, ',') );
169         }
170 }
171
172
173 void FormCitation::updateBrowser( FL_OBJECT * browser,
174                                   vector<string> const & keys ) const
175 {
176         fl_clear_browser( browser );
177
178         fl_freeze_form( browser->form );
179         for( unsigned int i = 0; i < keys.size(); ++i )
180                 fl_add_browser_line( browser, keys[i].c_str() );
181         fl_unfreeze_form( browser->form );
182 }
183
184
185 void FormCitation::setBibButtons( State status ) const
186 {
187         switch (status) {
188         case ON:
189                 fl_activate_object( dialog_->addBtn );
190                 fl_set_object_lcol( dialog_->addBtn, FL_BLACK );
191                 break;
192
193         case OFF:
194                 fl_deactivate_object( dialog_->addBtn );
195                 fl_set_object_lcol( dialog_->addBtn, FL_INACTIVE );
196                 break;
197
198         default:
199                 break;
200         }
201 }
202
203
204 void FormCitation::setCiteButtons( State status ) const
205 {
206         switch( status ) {
207         case ON:
208         {
209                 fl_activate_object( dialog_->delBtn );
210                 fl_set_object_lcol( dialog_->delBtn, FL_BLACK );
211
212                 int sel = fl_get_browser( dialog_->citeBrsr );
213
214                 if( sel != 1 ) {
215                         fl_activate_object( dialog_->upBtn );
216                         fl_set_object_lcol( dialog_->upBtn, FL_BLACK );
217                 } else {
218                         fl_deactivate_object( dialog_->upBtn );
219                         fl_set_object_lcol( dialog_->upBtn, FL_INACTIVE );
220                 }
221
222                 if( sel != fl_get_browser_maxline(dialog_->citeBrsr)) {
223                         fl_activate_object( dialog_->downBtn );
224                         fl_set_object_lcol( dialog_->downBtn, FL_BLACK );
225                 } else {
226                         fl_deactivate_object( dialog_->downBtn );
227                         fl_set_object_lcol( dialog_->downBtn, FL_INACTIVE );
228                 }
229
230                 break;
231         }
232         case OFF:
233         {
234                 fl_deactivate_object( dialog_->delBtn );
235                 fl_set_object_lcol( dialog_->delBtn, FL_INACTIVE );
236
237                 fl_deactivate_object( dialog_->upBtn );
238                 fl_set_object_lcol( dialog_->upBtn, FL_INACTIVE );
239
240                 fl_deactivate_object( dialog_->downBtn );
241                 fl_set_object_lcol( dialog_->downBtn, FL_INACTIVE );
242         }
243         default:
244                 break;
245         }
246 }
247
248
249 void FormCitation::setSize( int brsrHeight, bool bibPresent ) const
250 {
251         int const infoHeight  = 110;
252         int const otherHeight = 140;
253         brsrHeight = max( brsrHeight, 175 );
254         int formHeight = brsrHeight + otherHeight;
255
256         if( bibPresent ) formHeight += infoHeight + 30;
257         fl_set_form_size( dialog_->form_citation, 430, formHeight );
258
259         // No resizing is alowed in the y-direction
260         fl_set_form_minsize( dialog_->form_citation, 430, formHeight );
261         fl_set_form_maxsize( dialog_->form_citation, 1000, formHeight );
262
263         int ypos = 0;
264         fl_set_object_geometry( dialog_->box,      0,   ypos, 430, formHeight );
265         ypos += 30;
266         fl_set_object_geometry( dialog_->citeBrsr, 10,  ypos, 180, brsrHeight );
267         fl_set_object_geometry( dialog_->bibBrsr,  240, ypos, 180, brsrHeight );
268         fl_set_object_geometry( dialog_->addBtn,   200, ypos,  30, 30 );
269         ypos += 35;
270         fl_set_object_geometry( dialog_->delBtn,   200, ypos,  30, 30 );
271         ypos += 35;
272         fl_set_object_geometry( dialog_->upBtn,    200, ypos,  30, 30 );
273         ypos += 35;
274         fl_set_object_geometry( dialog_->downBtn,  200, ypos,  30, 30 );
275
276         ypos = brsrHeight+30; // base of Citation/Bibliography browsers
277
278         // awaiting natbib support
279         fl_hide_object( dialog_->style );
280
281         if( bibPresent ) {
282                 ypos += 30;
283                 fl_set_object_geometry( dialog_->infoBrsr, 10, ypos, 410, infoHeight );
284                 fl_show_object( dialog_->infoBrsr );
285                 ypos += infoHeight;
286         }
287         else
288                 fl_hide_object( dialog_->infoBrsr );
289
290         ypos += 20;
291         // awaiting natbib support
292         fl_hide_object( dialog_->textBefore );
293
294         fl_set_object_geometry( dialog_->textAftr, 100, ypos,   250, 30 );
295         fl_set_object_geometry( dialog_->ok,       230, ypos+50, 90, 30 );
296         fl_set_object_geometry( dialog_->cancel,   330, ypos+50, 90, 30 );
297 }
298
299
300 void FormCitation::input( State cb )
301 {
302         switch( cb ) {
303         case BIBBRSR:
304         {
305                 fl_deselect_browser( dialog_->citeBrsr );
306                 
307                 unsigned int sel = fl_get_browser( dialog_->bibBrsr );
308                 if( sel < 1 || sel > bibkeys.size() ) break;
309
310                 // Put into infoBrsr the additional info associated with
311                 // the selected bibBrsr key
312                 fl_clear_browser( dialog_->infoBrsr );
313                 fl_add_browser_line( dialog_->infoBrsr,
314                                      bibkeysInfo[sel-1].c_str() );
315
316                 // Highlight the selected bibBrsr key in citeBrsr if present
317                 vector<string>::iterator it =
318                         find( citekeys.begin(), citekeys.end(), bibkeys[sel-1] );
319
320                 if( it != citekeys.end() ) {
321                         int n = it - citekeys.begin();
322                         fl_select_browser_line( dialog_->citeBrsr, n+1 );
323                         fl_set_browser_topline( dialog_->citeBrsr, n+1 );
324                 }
325
326                 if( !lv_->buffer()->isReadonly() ) {
327                         if( it != citekeys.end() ) {
328                                 setBibButtons( OFF );
329                                 setCiteButtons( ON );
330                         } else {
331                                 setBibButtons( ON );
332                                 setCiteButtons( OFF );
333                         }
334                 }
335         }
336         break;
337         case CITEBRSR:
338         {
339                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
340                 if( sel < 1 || sel > citekeys.size() ) break;
341
342                 if( !lv_->buffer()->isReadonly() ) {
343                         setBibButtons( OFF );
344                         setCiteButtons( ON );
345                 }
346
347                 // Highlight the selected citeBrsr key in bibBrsr
348                 vector<string>::iterator it =
349                         find( bibkeys.begin(), bibkeys.end(), citekeys[sel-1] );
350
351                 if (it != bibkeys.end()) {
352                         int n = it - bibkeys.begin();
353                         fl_select_browser_line( dialog_->bibBrsr, n+1 );
354                         fl_set_browser_topline( dialog_->bibBrsr, n+1 );
355
356                         // Put into infoBrsr the additional info associated with
357                         // the selected citeBrsr key
358                         fl_clear_browser( dialog_->infoBrsr );
359                         fl_add_browser_line( dialog_->infoBrsr,
360                                              bibkeysInfo[n].c_str() );
361                 }
362         }
363         break;
364         case ADD:
365         {
366                 if( lv_->buffer()->isReadonly() ) break;
367
368                 unsigned int sel = fl_get_browser( dialog_->bibBrsr );
369                 if( sel < 1 || sel > bibkeys.size() ) break;
370
371                 // Add the selected bibBrsr key to citeBrsr
372                 fl_addto_browser( dialog_->citeBrsr,
373                                   bibkeys[sel-1].c_str() );
374                 citekeys.push_back( bibkeys[sel-1] );
375
376                 int n = citekeys.size();
377                 fl_select_browser_line( dialog_->citeBrsr, n );
378
379                 setBibButtons( OFF );
380                 setCiteButtons( ON );
381         }
382         break;
383         case DELETE:
384         {
385                 if( lv_->buffer()->isReadonly() ) break;
386
387                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
388                 if( sel < 1 || sel > citekeys.size() ) break;
389
390                 // Remove the selected key from citeBrsr
391                 fl_delete_browser_line( dialog_->citeBrsr, sel ) ;
392                 citekeys.erase( citekeys.begin() + sel-1 );
393
394                 setBibButtons( ON );
395                 setCiteButtons( OFF );
396         }
397         break;
398         case UP:
399         {
400                 if( lv_->buffer()->isReadonly() ) break;
401
402                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
403                 if( sel < 2 || sel > citekeys.size() ) break;
404
405                 // Move the selected key up one line
406                 vector<string>::iterator it = citekeys.begin() + sel-1;
407                 string tmp = *it;
408
409                 fl_delete_browser_line( dialog_->citeBrsr, sel );
410                 citekeys.erase( it );
411
412                 fl_insert_browser_line( dialog_->citeBrsr, sel-1, tmp.c_str() );
413                 fl_select_browser_line( dialog_->citeBrsr, sel-1 );
414                 citekeys.insert( it-1, tmp );
415                 setCiteButtons( ON );
416         }
417         break;
418         case DOWN:
419         {
420                 if( lv_->buffer()->isReadonly() ) break;
421
422                 unsigned int sel = fl_get_browser( dialog_->citeBrsr );
423                 if( sel < 1 || sel > citekeys.size()-1 ) break;
424
425                 // Move the selected key down one line
426                 vector<string>::iterator it = citekeys.begin() + sel-1;
427                 string tmp = *it;
428
429                 fl_delete_browser_line( dialog_->citeBrsr, sel );
430                 citekeys.erase( it );
431
432                 fl_insert_browser_line( dialog_->citeBrsr, sel+1, tmp.c_str() );
433                 fl_select_browser_line( dialog_->citeBrsr, sel+1 );
434                 citekeys.insert( it+1, tmp );
435                 setCiteButtons( ON );
436         }
437         break;
438         default:
439                 break;
440         }
441 }
442
443
444 void FormCitation::apply()
445 {
446         if( lv_->buffer()->isReadonly() ) return;
447
448         string tmp;
449         for( unsigned int i = 0; i < citekeys.size(); ++i ) {
450                 if (i > 0) tmp += ", ";
451                 tmp += citekeys[i];
452         }
453
454         textAfter = fl_get_input(dialog_->textAftr);
455
456         if( inset_ != 0 )
457         {
458                 inset_->setContents( tmp );
459                 inset_->setOptions( textAfter );
460                 lv_->view()->updateInset( inset_, true );
461         } else {
462                 string arg = tmp + '|' + textAfter;
463                 lv_->getLyXFunc()->Dispatch( LFUN_INSERT_CITATION, arg.c_str() );
464         }
465 }
466
467
468 void FormCitation::hide()
469 {
470         if (dialog_
471             && dialog_->form_citation
472             && dialog_->form_citation->visible) {
473                 fl_hide_form(dialog_->form_citation);
474                 u_.disconnect();
475                 h_.disconnect();
476         }
477
478         // free up the dialog for another inset
479         inset_ = 0;
480         dialogIsOpen = false;
481 }
482
483
484 void FormCitation::free()
485 {
486         // we don't need to delete u and h here because
487         // hide() does that after disconnecting.
488         if (dialog_) {
489                 if (dialog_->form_citation
490                     && dialog_->form_citation->visible) {
491                         hide();
492                 }
493                 fl_free_form(dialog_->form_citation);
494                 delete dialog_;
495                 dialog_ = 0;
496         }
497 }
498
499
500 int FormCitation::WMHideCB(FL_FORM * form, void *)
501 {
502         // Ensure that the signals (u and h) are disconnected even if the
503         // window manager is used to close the dialog.
504         FormCitation * pre = static_cast<FormCitation*>(form->u_vdata);
505         pre->hide();
506         return FL_CANCEL;
507 }
508
509
510 void FormCitation::OKCB(FL_OBJECT * ob, long)
511 {
512         FormCitation * pre = static_cast<FormCitation*>(ob->form->u_vdata);
513         pre->apply();
514         pre->hide();
515 }
516
517
518 void FormCitation::CancelCB(FL_OBJECT * ob, long)
519 {
520         FormCitation * pre = static_cast<FormCitation*>(ob->form->u_vdata);
521         pre->hide();
522 }
523
524
525 void FormCitation::InputCB(FL_OBJECT * ob, long data)
526 {
527         FormCitation * pre = static_cast<FormCitation*>(ob->form->u_vdata);
528         pre->input( static_cast<FormCitation::State>(data) );
529 }