]> git.lyx.org Git - lyx.git/blob - src/insets/insetbib.C
Just some changes to be able to change TabularFeatures with the Table menu
[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                     IsFileReadable(MakeAbsPath(adb, owner->filepath)+".bib")) 
344                         adb = MakeAbsPath(adb, owner->filepath);
345                 db_out += adb;
346                 db_out += ',';
347                 db_in= split(db_in, adb,',');
348         }
349         db_out = strip(db_out, ',');
350         // Idem, but simpler
351         string style;
352         if (!owner->niceFile 
353             && IsFileReadable(MakeAbsPath(getOptions(), owner->filepath)
354                               + ".bst")) 
355                 style = MakeAbsPath(getOptions(), owner->filepath);
356         else
357                 style = getOptions();
358
359         os << "\\bibliographystyle{" << style << "}\n"
360            << "\\bibliography{" << db_out << "}\n";
361         return 2;
362 }
363
364
365 // This method returns a comma separated list of Bibtex entries
366 string InsetBibtex::getKeys(char delim)
367 {
368         // This hack is copied from InsetBibtex::Latex.
369         // Is it still needed? Probably yes.
370         // Why is this needed here when it already is in Latex?
371         // Anyway we need a different way to get to the
372         // buffer the inset is in. (Lgb)
373         
374         //if (!owner) {
375         //      owner = current_view->buffer();
376         //}
377         
378         string tmp, keys;
379         string bibfiles = getContents();
380         bibfiles = split(bibfiles, tmp, ',');
381         while(!tmp.empty()) {
382                 string fil = findtexfile(ChangeExtension(tmp, "bib", false),
383                                          "bib");
384                 lyxerr[Debug::LATEX] << "Bibfile: " << fil << endl;
385                 // If we didn't find a matching file name just fail silently
386                 if (!fil.empty()) {
387                         // This is a _very_ simple parser for Bibtex database
388                         // files. All it does is to look for lines starting
389                         // in @ and not being @preamble and @string entries.
390                         // It does NOT do any syntax checking!
391                         ifstream ifs(fil.c_str());
392                         string linebuf;
393                         while (getline(ifs, linebuf)) {
394                                 linebuf = frontStrip(linebuf);
395                                 if (prefixIs(linebuf, "@")) {
396                                         linebuf = subst(linebuf, '{', '(');
397                                         linebuf = split(linebuf, tmp, '(');
398                                         tmp = lowercase(tmp);
399                                         if (!prefixIs(tmp, "@string")
400                                             && !prefixIs(tmp, "@preamble")) {
401                                                 linebuf = split(linebuf,
402                                                                 tmp, ',');
403                                                 tmp = frontStrip(strip(tmp));
404                                                 if (!tmp.empty()) {
405                                                         keys += tmp;
406                                                         keys += delim;
407                                                 }
408                                         }
409                                 }
410                         }
411                 }
412                 // Get next file name
413                 bibfiles = split(bibfiles, tmp, ',');
414         }
415         return keys;
416 }
417
418
419 // BibTeX should have its own dialog. This is provisional.
420 void InsetBibtex::Edit(BufferView * bv, int, int, unsigned int)
421 {
422         if (!bibitem_form) {
423                 bibitem_form = create_form_bibitem_form();
424                 fl_set_form_atclose(bibitem_form->bibitem_form, 
425                                     CancelCloseBoxCB, 0);
426         }
427
428         holder.inset = this;
429         holder.view = bv;
430         bibitem_form->bibitem_form->u_vdata = &holder;
431
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 }