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