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