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