]> git.lyx.org Git - lyx.git/blob - src/insets/insetbib.C
Add support for compilers which do not have cname headers
[lyx.git] / src / insets / insetbib.C
1
2 #include <config.h>
3
4 #include <cstdlib>
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 "debug.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 "support/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 = 0;
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(string const & key, string 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, 0);
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 string InsetCitation::getScreenLabel() const
195 {
196         string temp("[");
197
198         temp += contents;
199
200         if (!options.empty()) {
201                 temp += "," + options;
202         }
203
204         return temp + ']';
205 }
206
207
208 InsetBibKey::InsetBibKey(string const & key, string 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         string 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 string InsetBibKey::getScreenLabel() const
257 {
258         if (!options.empty())
259                 return options;
260     
261         return tostr(counter);
262 }
263
264
265 /*
266   The value in "Key:" isn't allways set right after a few bibkey insets have
267   been added/removed.  Perhaps the wrong object is deleted/used somewhere upwards?
268   (Joacim 1998-03-04)
269 */
270 void InsetBibKey::Edit(int, int)
271 {
272         if(current_view->currentBuffer()->isReadonly())
273                 WarnReadonly();
274         
275         if (!bibitem_form) {
276                 bibitem_form = create_form_bibitem_form();
277                 fl_set_form_atclose(bibitem_form->bibitem_form, 
278                                     CancelCloseBoxCB, 0);
279         }
280         bibitem_form->vdata = this;
281         // InsetBibtex uses the same form, with different labels
282         fl_set_object_label(bibitem_form->key, idex(_("Key:|#K")));
283         fl_set_button_shortcut(bibitem_form->key,scex(_("Key:|#K")),1);
284         fl_set_object_label(bibitem_form->label, idex(_("Label:|#L")));
285         fl_set_button_shortcut(bibitem_form->label,scex(_("Label:|#L")),1);
286         fl_set_input(bibitem_form->key, getContents().c_str());
287         fl_set_input(bibitem_form->label, getOptions().c_str());
288         if (bibitem_form->bibitem_form->visible) {
289                 fl_raise_form(bibitem_form->bibitem_form);
290         } else {
291                 fl_show_form(bibitem_form->bibitem_form,FL_PLACE_MOUSE,
292                              FL_FULLBORDER,
293                              _("Bibliography item"));
294         }   
295 }
296
297
298
299 InsetBibtex::InsetBibtex(string const & dbase, string const & style,
300                          Buffer *o)
301         :InsetCommand("BibTeX", dbase, style), owner(o)
302 {
303 }
304
305
306 InsetBibtex::~InsetBibtex()
307 {
308 }
309
310
311 string InsetBibtex::getScreenLabel() const
312 {
313         return _("BibTeX Generated References");
314 }
315
316
317 int InsetBibtex::Latex(FILE *file, signed char /*fragile*/)
318 {
319         string bib;
320         signed char dummy = 0;
321         int result = Latex(bib, dummy);
322         fprintf(file, "%s", bib.c_str());
323         return result;
324 }
325
326
327 int InsetBibtex::Latex(string &file, signed char /*fragile*/)
328 {
329         // this looks like an horrible hack and it is :) The problem
330         // is that owner is not initialized correctly when the bib
331         // inset is cut and pasted. Such hacks will not be needed
332         // later (JMarc)
333         if (!owner) {
334                 owner = current_view->currentBuffer();
335         }
336         // If we generate in a temp dir, we might need to give an
337         // absolute path there. This is a bit complicated since we can
338         // have a comma-separated list of bibliographies
339         string db_in, adb, db_out;
340         db_in = getContents();
341         db_in=split(db_in, adb, ',');
342         while(!adb.empty()) {
343                 if (!owner->niceFile &&
344                     IsFileReadable(MakeAbsPath(adb,owner->filepath)+".bib")) 
345                         adb = MakeAbsPath(adb,owner->filepath);
346                 db_out += adb;
347                 db_out += ',';
348                 db_in=split(db_in, adb,',');
349         }
350         db_out = strip(db_out, ',');
351         // Idem, but simpler
352         string style;
353         if (!owner->niceFile 
354             && IsFileReadable(MakeAbsPath(getOptions(), owner->filepath)
355                               + ".bst")) 
356                 style = MakeAbsPath(getOptions(), owner->filepath);
357         else
358                 style = getOptions();
359
360         file += "\\bibliographystyle{";
361         file += style;
362         file += "}\n";
363         file += "\\bibliography{";
364         file += db_out;
365         file += "}\n";
366         return 2;
367 }
368
369 // This method returns a comma separated list of Bibtex entries
370 string InsetBibtex::getKeys()
371 {
372         // This hack is copied from InsetBibtex::Latex.
373         // Is it still needed? Probably yes.
374         if (!owner) {
375                 owner = current_view->currentBuffer();
376         }
377
378         // We need to create absolute path names for bibliographies
379         // First look for bib-file in same directory as document,
380         // then in all directories listed in environment variable 
381         // BIBINPUTS
382         string bibfiles, linebuf, tmp, keys;
383         bibfiles = getContents();
384         bibfiles=split(bibfiles, tmp, ',');
385         while(!tmp.empty()) {
386                 if (IsFileReadable(MakeAbsPath(tmp,owner->filepath)+".bib"))
387                         tmp = MakeAbsPath(tmp,owner->filepath)+".bib";
388                 else {
389                         tmp = FileOpenSearch(GetEnvPath("BIBINPUTS"),tmp,"bib");
390                         if (tmp.empty())
391                                 tmp = FileOpenSearch(GetEnvPath("BIBINPUT"),
392                                                      tmp, "bib");
393                 }
394                 // If we didn't find a matching file name just fail silently
395                 if (!tmp.empty()) {
396       
397                         // This is a _very_ simple parser for Bibtex database files.
398                         // All it does is to look for lines starting in @ and not
399                         // being @preamble and @string entries.
400                         // It does NOT do any syntax checking!
401                         FilePtr file(tmp,FilePtr::read);
402                         char c;
403
404                         // On some systems where feof() is a macro,
405                         // the () after file is needed (JMarc)
406                         while (! feof(file())) {
407                                 c = fgetc(file);
408
409                                 // At end of each line check if line begins with '@'
410                                 if ( c == '\n') {
411                                         if (prefixIs(linebuf, "@") ) {
412                                                 subst(linebuf, '{','(');
413                                                 linebuf=split(linebuf, tmp,'(');
414                                                 tmp = lowercase(tmp);
415                                                 if (!prefixIs(tmp, "@string") && !prefixIs(tmp, "@preamble") ) {
416                                                         linebuf = split(linebuf, tmp,',');
417                                                         if (!tmp.empty())
418                                                                 keys += strip(tmp) + ",";
419                                                 }
420                                         }
421                                         linebuf.erase();
422                                 } else {
423                                         linebuf += c;
424                                 }
425                         }
426                 }
427                 // Get next file name
428                 bibfiles=split(bibfiles, tmp, ',');
429         }
430         return keys;
431 }
432
433 // BibTeX should have its own dialog. This is provisional.
434 void InsetBibtex::Edit(int, int)
435 {
436         if (!bibitem_form) {
437                 bibitem_form = create_form_bibitem_form();
438                 fl_set_form_atclose(bibitem_form->bibitem_form, 
439                                     CancelCloseBoxCB, 0);
440         }
441
442         bibitem_form->vdata = this;
443         fl_set_object_label(bibitem_form->key, _("Database:"));
444         fl_set_object_label(bibitem_form->label, _("Style:  "));
445         fl_set_input(bibitem_form->key, getContents().c_str());
446         fl_set_input(bibitem_form->label, getOptions().c_str());
447         if (bibitem_form->bibitem_form->visible) {
448                 fl_raise_form(bibitem_form->bibitem_form);
449         } else {
450                 fl_show_form(bibitem_form->bibitem_form,FL_PLACE_MOUSE, FL_FULLBORDER,
451                              _("BibTeX"));
452         }   
453 }
454
455
456 bool InsetBibtex::addDatabase(string const &db)
457 {
458         if (!contains(contents, db.c_str())) {
459                 if (!contents.empty()) 
460                         contents += ',';
461                 contents += db;
462                 return true;
463         }
464         return false;
465 }
466
467
468 bool InsetBibtex::delDatabase(string const &db)
469 {
470         if (contains(contents, db.c_str())) {
471                 string bd = db;
472                 int n = tokenPos(contents, ',', bd);
473                 if (n > 0) {
474                         string tmp(",");
475                         tmp += bd;
476                         subst(contents, tmp.c_str(), ",");
477                 } else if (n==0)
478                         contents = split(contents, bd, ',');
479                 else 
480                         return false;
481         }
482         return true;
483 }
484
485
486 // This function should be in LyXView when multiframe works ale970302
487 void BibitemUpdate(Combox* combox)
488 {
489         combox->clear();
490     
491         if (!current_view->available())
492                 return;
493
494         string tmp, bibkeys = current_view->currentBuffer()->getBibkeyList(',');
495         bibkeys=split(bibkeys, tmp,',');
496         while (!tmp.empty()) {
497           combox->addto(tmp.c_str());
498           bibkeys=split(bibkeys, tmp,',');
499         }
500 }
501
502
503
504 // ale070405 This function maybe shouldn't be here. We'll fix this at 0.13.
505 int bibitemMaxWidth(const class LyXFont &font)
506 {
507         int w = 0;
508         // Does look like a hack? It is! (but will change at 0.13)
509         LyXParagraph *par = current_view->currentBuffer()->paragraph;
510     
511         while (par) {
512                 if (par->bibkey) {
513                         int wx = par->bibkey->Width(font);
514                         if (wx>w) w = wx;
515                 }
516                 par = par->next;
517         }
518         return w;
519 }
520
521
522 // ale070405 
523 string bibitemWidthest()
524 {
525         int w = 0;
526         // Does look like a hack? It is! (but will change at 0.13)
527         LyXParagraph *par = current_view->currentBuffer()->paragraph;
528         InsetBibKey *bkey=0;
529         LyXFont font;
530       
531         while (par) {
532                 if (par->bibkey) {
533                         int wx = par->bibkey->Width(font);
534                         if (wx>w) {
535                                 w = wx;
536                                 bkey = par->bibkey;
537                         }
538                 }
539                 par = par->next;
540         }
541     
542         if (bkey && !bkey->getScreenLabel().empty())
543                 return bkey->getScreenLabel();
544     
545         return "99";
546 }