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