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