]> git.lyx.org Git - lyx.git/blob - src/insets/insetbib.C
last updates from 1.0.4, no more updates expected from that branch now
[lyx.git] / src / insets / insetbib.C
1
2 #include <config.h>
3
4 #include <stdlib.h>
5
6 #ifdef __GNUG__
7 #pragma implementation
8 #endif
9
10 #include FORMS_H_LOCATION  
11 #include "insetbib.h"
12 #include "combox.h"
13 #include "buffer.h"
14 #include "error.h"
15 #include "lyx_gui_misc.h"
16 #include "BufferView.h"
17 #include "gettext.h"
18 #include "bibforms.h"
19 #include "lyxtext.h"
20 #include "filetools.h"
21
22 extern BufferView *current_view;
23
24 FD_citation_form *citation_form=0;
25 FD_bibitem_form *bibitem_form=0;
26 static Combox *bibcombox = NULL;
27
28 extern void UpdateInset(Inset* inset, bool mark_dirty = true);
29 void BibitemUpdate(Combox *);
30 void bibitem_cb(FL_OBJECT *, long);
31 FD_citation_form * create_form_citation_form(void);
32 FD_bibitem_form * create_form_bibitem_form(void);
33
34
35 void bibitem_cb(FL_OBJECT *, long data)
36 {
37         switch (data) {
38 //       case 0: fl_hide_form(citation_form->citation_form);
39 //               break;
40 //       case 1: 
41         case 1: // OK, citation
42         {
43 //               InsetCommand *inset = (InsetCommand*)citation_form->vdata;
44 //               inset->setContents(bibcombox->getline());
45 //               inset->setOptions(fl_get_input(citation_form->label));
46 //               fl_hide_form(citation_form->citation_form);
47 //               UpdateInset(inset);
48 //               break;
49                 if(!current_view->currentBuffer()->isReadonly()) {
50                         InsetCommand *inset = (InsetCommand*)citation_form->vdata;
51                         inset->setContents(bibcombox->getline());
52                         inset->setOptions(fl_get_input(citation_form->label));
53                         fl_hide_form(citation_form->citation_form);
54                         // shouldn't mark the buffer dirty unless something
55                         // was actually altered
56                         UpdateInset(inset);
57                         break;
58                 }
59                 // fall through to Cancel on RO-mode
60         }       
61 //       case 2:  fl_hide_form(bibitem_form->bibitem_form);
62         case 0: fl_hide_form(citation_form->citation_form);
63                 break;
64 //       case 3:
65
66         case 3: // OK, bibitem
67         {
68 //               InsetCommand *inset = (InsetCommand *)bibitem_form->vdata;
69 //               inset->setContents(fl_get_input(bibitem_form->key));
70 //               inset->setOptions(fl_get_input(bibitem_form->label));
71 //               fl_hide_form(bibitem_form->bibitem_form);
72 //              // Does look like a hack? It is! (but will change at 0.13)
73 //               current_view->currentBuffer()->text->RedoParagraph();
74 //               current_view->currentBuffer()->update(1);
75 //               break;
76                 if(!current_view->currentBuffer()->isReadonly()) {
77                         InsetCommand *inset = (InsetCommand *)bibitem_form->vdata;
78                         inset->setContents(fl_get_input(bibitem_form->key));
79                         inset->setOptions(fl_get_input(bibitem_form->label));
80                         fl_hide_form(bibitem_form->bibitem_form);
81                         // Does look like a hack? It is! (but will change at 0.13)
82                         current_view->currentBuffer()->text->RedoParagraph();
83                         current_view->currentBuffer()->update(1);
84                         break;
85                 } // fall through to Cancel on RO-mode
86         }
87         case 2: // Cancel, bibitem
88                 fl_hide_form(bibitem_form->bibitem_form); // Cancel, bibitem
89                 break;
90         }
91 }
92
93 FD_citation_form *create_form_citation_form(void)
94 {
95         FL_OBJECT *obj;
96         FD_citation_form *fdui = (FD_citation_form *) fl_calloc(1, sizeof(FD_citation_form));
97
98         fdui->citation_form = fl_bgn_form(FL_NO_BOX, 220, 130);
99         obj = fl_add_box(FL_UP_BOX,0,0,220,130,"");
100         fdui->key = obj = fl_add_text(FL_NORMAL_TEXT,20,10,60,30,_("Key:"));
101           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
102           fl_set_object_lalign(obj,FL_ALIGN_RIGHT);
103
104         bibcombox = new Combox(FL_COMBOX_INPUT);
105         bibcombox->add(80,10,130,30, 120);
106
107         obj = fl_add_button(FL_RETURN_BUTTON,20,90,90,30,_("OK"));
108           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
109           fl_set_object_callback(obj,bibitem_cb,1);
110         obj = fl_add_button(FL_NORMAL_BUTTON,120,90,90,30,idex(_("Cancel|^[")));
111           fl_set_button_shortcut(obj,scex(_("Cancel|^[")),1);
112           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
113           fl_set_object_callback(obj,bibitem_cb,0);
114         fdui->label = obj = fl_add_input(FL_NORMAL_INPUT,80,50,130,30,idex(_("Remark:|#R")));
115           fl_set_input_shortcut(obj,scex(_("Remark:|#R")),1);
116           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
117         fl_end_form();
118
119         //fdui->citation_form->fdui = fdui;
120
121         return fdui;
122 }
123 /*---------------------------------------*/
124
125 FD_bibitem_form *create_form_bibitem_form(void)
126 {
127         FL_OBJECT *obj;
128         FD_bibitem_form *fdui = (FD_bibitem_form *) fl_calloc(1, sizeof(FD_bibitem_form));
129
130         fdui->bibitem_form = fl_bgn_form(FL_NO_BOX, 220, 130);
131         obj = fl_add_box(FL_UP_BOX,0,0,220,130,"");
132         fdui->key = obj = fl_add_input(FL_NORMAL_INPUT,80,10,130,30,idex(_("Key:|#K")));
133           fl_set_input_shortcut(obj,scex(_("Key:|#K")),1);
134           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
135         obj = fl_add_button(FL_RETURN_BUTTON,20,90,90,30,_("OK"));
136           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
137           fl_set_object_callback(obj,bibitem_cb,3);
138         obj = fl_add_button(FL_NORMAL_BUTTON,120,90,90,30,idex(_("Cancel|^[")));
139           fl_set_button_shortcut(obj,scex(_("Cancel|^[")),1);
140           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
141           fl_set_object_callback(obj,bibitem_cb,2);
142         fdui->label = obj = fl_add_input(FL_NORMAL_INPUT,80,50,130,30,idex(_("Label:|#L")));
143           fl_set_input_shortcut(obj,scex(_("Label:|#L")),1);
144           fl_set_object_lsize(obj,FL_NORMAL_SIZE);
145         fl_end_form();
146
147         //fdui->bibitem_form->fdui = fdui;
148
149         return fdui;
150 }
151 /*---------------------------------------*/
152
153
154 InsetCitation::InsetCitation(LString const & key, LString const & note):
155         InsetCommand("cite", key, note)
156 {
157
158 }
159 InsetCitation::~InsetCitation()
160 {
161         if(citation_form && citation_form->citation_form
162            && citation_form->citation_form->visible
163            && citation_form->vdata == this)
164                 fl_hide_form(citation_form->citation_form);
165 }
166
167
168 void InsetCitation::Edit(int, int)
169 {
170         if(current_view->currentBuffer()->isReadonly())
171                 WarnReadonly();
172
173         if (!citation_form) {
174                 citation_form = create_form_citation_form();
175                 fl_set_form_atclose(citation_form->citation_form, 
176                                     CancelCloseBoxCB, NULL);
177         }
178         citation_form->vdata = this;
179
180         BibitemUpdate(bibcombox);
181         if (!bibcombox->select_text(getContents().c_str()))
182                 bibcombox->addline(getContents().c_str());
183             
184         fl_set_input(citation_form->label, getOptions().c_str());
185         if (citation_form->citation_form->visible) {
186                 fl_raise_form(citation_form->citation_form);
187         } else {
188                 fl_show_form(citation_form->citation_form,FL_PLACE_MOUSE, FL_FULLBORDER,
189                              _("Citation"));
190         }   
191 }
192
193
194 LString InsetCitation::getScreenLabel() const
195 {
196         LString temp('[');
197
198         temp+=contents;
199
200         if (!options.empty()) {
201                 temp+=","+options;
202         }
203
204         return temp+']';
205 }
206
207
208 InsetBibKey::InsetBibKey(LString const & key, LString const & label):
209         InsetCommand("bibitem", key, label)
210 {
211         counter = 1;
212         if (key.empty())
213                 contents = ' ';
214 }
215
216
217 InsetBibKey::InsetBibKey(InsetBibKey const *b):
218         InsetCommand("bibitem", b->contents, b->options)
219 {
220         counter = b->counter;
221 }
222
223 InsetBibKey::~InsetBibKey()
224 {
225         if(bibitem_form && bibitem_form->bibitem_form
226            && bibitem_form->bibitem_form->visible)
227                                 fl_hide_form(bibitem_form->bibitem_form);
228 }
229
230 void InsetBibKey::setCounter(int c) 
231
232         counter = c; 
233     
234         if (contents.empty())
235                 contents += counter;
236 }
237
238
239 // I'm sorry but this is still necessary because \bibitem is used also
240 // as a LyX 2.x command, and lyxlex is not enough smart to understand
241 // real LaTeX commands. Yes, that could be fixed, but would be a waste 
242 // of time cause LyX3 won't use lyxlex anyway.  (ale)
243 void InsetBibKey::Write(FILE *file)
244 {
245         LString s;
246         if (!options.empty()) {
247                 s += '[';
248                 s += options + ']';
249         }
250         s += '{';
251         s += contents + '}';
252         fprintf(file,"\\bibitem %s\n", s.c_str());
253 }
254
255
256 LString InsetBibKey::getScreenLabel() const
257 {
258         if (!options.empty())
259                 return options;
260     
261         LString s;
262         return s + counter;
263 }
264
265
266 /*
267   The value in "Key:" isn't allways set right after a few bibkey insets have
268   been added/removed.  Perhaps the wrong object is deleted/used somewhere upwards?
269   (Joacim 1998-03-04)
270 */
271 void InsetBibKey::Edit(int, int)
272 {
273         if(current_view->currentBuffer()->isReadonly())
274                 WarnReadonly();
275         
276         if (!bibitem_form) {
277                 bibitem_form = create_form_bibitem_form();
278                 fl_set_form_atclose(bibitem_form->bibitem_form, 
279                                     CancelCloseBoxCB, NULL);
280         }
281         bibitem_form->vdata = this;
282         // InsetBibtex uses the same form, with different labels
283         fl_set_object_label(bibitem_form->key, idex(_("Key:|#K")));
284         fl_set_button_shortcut(bibitem_form->key,scex(_("Key:|#K")),1);
285         fl_set_object_label(bibitem_form->label, idex(_("Label:|#L")));
286         fl_set_button_shortcut(bibitem_form->label,scex(_("Label:|#L")),1);
287         fl_set_input(bibitem_form->key, getContents().c_str());
288         fl_set_input(bibitem_form->label, getOptions().c_str());
289         if (bibitem_form->bibitem_form->visible) {
290                 fl_raise_form(bibitem_form->bibitem_form);
291         } else {
292                 fl_show_form(bibitem_form->bibitem_form,FL_PLACE_MOUSE,
293                              FL_FULLBORDER,
294                              _("Bibliography item"));
295         }   
296 }
297
298
299
300 InsetBibtex::InsetBibtex(LString const & dbase, LString const & style,
301                          Buffer *o)
302         :InsetCommand("BibTeX", dbase, style), owner(o)
303 {
304 }
305
306
307 InsetBibtex::~InsetBibtex()
308 {
309 }
310
311
312 LString InsetBibtex::getScreenLabel() const
313 {
314         return _("BibTeX Generated References");
315 }
316
317
318 int InsetBibtex::Latex(FILE *file, signed char /*fragile*/)
319 {
320         LString bib;
321         signed char dummy = 0;
322         int result = Latex(bib, dummy);
323         fprintf(file, "%s", bib.c_str());
324         return result;
325 }
326
327
328 int InsetBibtex::Latex(LString &file, signed char /*fragile*/)
329 {
330         // this looks like an horrible hack and it is :) The problem
331         // is that owner is not initialized correctly when the bib
332         // inset is cut and pasted. Such hacks will not be needed
333         // later (JMarc)
334         if (!owner) {
335                 owner = current_view->currentBuffer();
336         }
337         // If we generate in a temp dir, we might need to give an
338         // absolute path there. This is a bit complicated since we can
339         // have a comma-separated list of bibliographies
340         LString db_in, adb, db_out;
341         db_in = getContents();
342         db_in.split(adb, ',');
343         while(!adb.empty()) {
344                 if (!owner->niceFile &&
345                     IsFileReadable(MakeAbsPath(adb,owner->filepath)+".bib")) 
346                         adb = MakeAbsPath(adb,owner->filepath);
347                 db_out += adb;
348                 db_out += ',';
349                 db_in.split(adb,',');
350         }
351         db_out.strip(',');
352
353         // Idem, but simpler
354         LString style;
355         if (!owner->niceFile 
356             && IsFileReadable(MakeAbsPath(getOptions(), owner->filepath)
357                               + ".bst")) 
358                 style = MakeAbsPath(getOptions(), owner->filepath);
359         else
360                 style = getOptions();
361
362         file += "\\bibliographystyle{";
363         file += style;
364         file += "}\n";
365         file += "\\bibliography{";
366         file += db_out;
367         file += "}\n";
368         return 2;
369 }
370
371 // This method returns a comma separated list of Bibtex entries
372 LString InsetBibtex::getKeys()
373 {
374         // This hack is copied from InsetBibtex::Latex.
375         // Is it still needed? Probably yes.
376         if (!owner) {
377                 owner = current_view->currentBuffer();
378         }
379
380         // We need to create absolute path names for bibliographies
381         // First look for bib-file in same directory as document,
382         // then in all directories listed in environment variable 
383         // BIBINPUTS
384         LString bibfiles, linebuf, tmp, keys;
385         bibfiles = getContents();
386         bibfiles.split(tmp, ',');
387         while(!tmp.empty()) {
388                 if (IsFileReadable(MakeAbsPath(tmp,owner->filepath)+".bib"))
389                         tmp = MakeAbsPath(tmp,owner->filepath)+".bib";
390                 else {
391                         tmp = FileOpenSearch(getEnvPath("BIBINPUTS"),tmp,"bib");
392                         if (tmp.empty())
393                                 tmp = FileOpenSearch(getEnvPath("BIBINPUT"),
394                                                      tmp, "bib");
395                 }
396                 // If we didn't find a matching file name just fail silently
397                 if (!tmp.empty()) {
398       
399                         // This is a _very_ simple parser for Bibtex database files.
400                         // All it does is to look for lines starting in @ and not
401                         // being @preamble and @string entries.
402                         // It does NOT do any syntax checking!
403                         FilePtr file(tmp,FilePtr::read);
404                         char c;
405
406                         // On some systems where feof() is a macro,
407                         // the () after file is needed (JMarc)
408                         while (! feof(file())) {
409                                 c = fgetc(file);
410
411                                 // At end of each line check if line begins with '@'
412                                 if ( c == '\n') {
413                                         if ( linebuf.prefixIs("@") ) {
414                                                 linebuf.subst('{','(');
415                                                 linebuf.split(tmp,'(');
416                                                 tmp.lowercase();
417                                                 if ( ! tmp.prefixIs("@string") && !tmp.prefixIs("@preamble") ) {
418                                                         linebuf.split(tmp,',');
419                                                         if (!tmp.empty())
420                                                                 keys +=tmp.strip()+",";
421                                                 }
422                                         }
423                                         linebuf.clean();
424                                 } else {
425                                         linebuf += c;
426                                 }
427                         }
428                 }
429                 // Get next file name
430                 bibfiles.split(tmp, ',');
431         }
432         return keys;
433 }
434
435 // BibTeX should have its own dialog. This is provisional.
436 void InsetBibtex::Edit(int, int)
437 {
438         if (!bibitem_form) {
439                 bibitem_form = create_form_bibitem_form();
440                 fl_set_form_atclose(bibitem_form->bibitem_form, 
441                                     CancelCloseBoxCB, NULL);
442         }
443
444         bibitem_form->vdata = this;
445         fl_set_object_label(bibitem_form->key, _("Database:"));
446         fl_set_object_label(bibitem_form->label, _("Style:  "));
447         fl_set_input(bibitem_form->key, getContents().c_str());
448         fl_set_input(bibitem_form->label, getOptions().c_str());
449         if (bibitem_form->bibitem_form->visible) {
450                 fl_raise_form(bibitem_form->bibitem_form);
451         } else {
452                 fl_show_form(bibitem_form->bibitem_form,FL_PLACE_MOUSE, FL_FULLBORDER,
453                              _("BibTeX"));
454         }   
455 }
456
457
458 bool InsetBibtex::addDatabase(LString const &db)
459 {
460         if (!contents.contains(db.c_str())) {
461                 if (!contents.empty()) 
462                         contents += ',';
463                 contents += db;
464                 return true;
465         }
466         return false;
467 }
468
469
470 bool InsetBibtex::delDatabase(LString const &db)
471 {
472         if (contents.contains(db.c_str())) {
473                 LString bd = db;
474                 int n = contents.tokenPos(',', bd);
475                 if (n > 0) {
476                         LString tmp(',');
477                         tmp += bd;
478                         contents.subst(tmp.c_str(), ",");
479                 } else if (n==0)
480                         contents.split(bd, ',');
481                 else 
482                         return false;
483         }
484         return true;
485 }
486
487
488 // This function should be in LyXView when multiframe works ale970302
489 void BibitemUpdate(Combox* combox)
490 {
491         combox->clear();
492     
493         if (!current_view->available())
494                 return;
495
496         LString tmp, bibkeys = current_view->currentBuffer()->getBibkeyList(',');
497         bibkeys.split(tmp,',');
498         while (!tmp.empty()) {
499           combox->addto(tmp.c_str());
500           bibkeys.split(tmp,',');
501         }
502 }
503
504
505
506 // ale070405 This function maybe shouldn't be here. We'll fix this at 0.13.
507 int bibitemMaxWidth(const class LyXFont &font)
508 {
509         int w = 0;
510         // Does look like a hack? It is! (but will change at 0.13)
511         LyXParagraph *par = current_view->currentBuffer()->paragraph;
512     
513         while (par) {
514                 if (par->bibkey) {
515                         int wx = par->bibkey->Width(font);
516                         if (wx>w) w = wx;
517                 }
518                 par = par->next;
519         }
520         return w;
521 }
522
523
524 // ale070405 
525 LString bibitemWidthest()
526 {
527         int w = 0;
528         // Does look like a hack? It is! (but will change at 0.13)
529         LyXParagraph *par = current_view->currentBuffer()->paragraph;
530         InsetBibKey *bkey=0;
531         LyXFont font;
532       
533         while (par) {
534                 if (par->bibkey) {
535                         int wx = par->bibkey->Width(font);
536                         if (wx>w) {
537                                 w = wx;
538                                 bkey = par->bibkey;
539                         }
540                 }
541                 par = par->next;
542         }
543     
544         if (bkey && !bkey->getScreenLabel().empty())
545                 return bkey->getScreenLabel();
546     
547         return "99";
548 }