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