]> git.lyx.org Git - lyx.git/blob - src/insets/insetbib.C
Fix small bug in reading \set_color in lyxrc
[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 "buffer.h"
13 #include "debug.h"
14 #include "lyx_gui_misc.h"
15 #include "BufferView.h"
16 #include "gettext.h"
17 #include "bibforms.h"
18 #include "lyxtext.h"
19 #include "support/filetools.h"
20 #include "support/path.h"
21
22 using std::ostream;
23 using std::ifstream;
24 using std::getline;
25 using std::endl;
26 using std::vector;
27 using std::pair;
28
29 extern BufferView * current_view;
30
31 FD_bibitem_form * bibitem_form = 0;
32
33 FD_bibitem_form * create_form_bibitem_form(void);
34
35
36 extern "C"
37 void bibitem_cb(FL_OBJECT *, long data)
38 {
39         InsetBibKey::Holder * holder =
40                 static_cast<InsetBibKey::Holder*>
41                 (bibitem_form->bibitem_form->u_vdata);
42         
43         holder->inset->callback( bibitem_form, data );
44 }
45
46
47 FD_bibitem_form * create_form_bibitem_form(void)
48 {
49         FL_OBJECT * obj;
50         FD_bibitem_form * fdui = (FD_bibitem_form *) fl_calloc(1, sizeof(FD_bibitem_form));
51
52         fdui->bibitem_form = fl_bgn_form(FL_NO_BOX, 220, 130);
53         obj = fl_add_box(FL_UP_BOX, 0, 0, 220, 130, "");
54         fdui->key = obj = fl_add_input(FL_NORMAL_INPUT, 80, 10, 130, 30, idex(_("Key:|#K")));
55         fl_set_input_shortcut(obj, scex(_("Key:|#K")), 1);
56         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
57         obj = fl_add_button(FL_RETURN_BUTTON, 20, 90, 90, 30, _("OK"));
58         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
59         fl_set_object_callback(obj, bibitem_cb, 1);
60         obj = fl_add_button(FL_NORMAL_BUTTON, 120, 90, 90, 30, idex(_("Cancel|^[")));
61         fl_set_button_shortcut(obj, scex(_("Cancel|^[")), 1);
62         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
63         fl_set_object_callback(obj, bibitem_cb, 0);
64         fdui->label = obj = fl_add_input(FL_NORMAL_INPUT, 80, 50, 130, 30, idex(_("Label:|#L")));
65         fl_set_input_shortcut(obj, scex(_("Label:|#L")), 1);
66         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
67         fl_end_form();
68
69         //fdui->bibitem_form->fdui = fdui;
70
71         return fdui;
72 }
73
74
75 InsetBibKey::InsetBibKey(string const & key, string const & label)
76         : InsetCommand("bibitem", key, label)
77 {
78         counter = 1;
79         if (key.empty())
80                 setCmdName(" ");
81 }
82
83
84 InsetBibKey::InsetBibKey(InsetBibKey const * b)
85         : InsetCommand("bibitem", b->getContents(), b->getOptions())
86 {
87         counter = b->counter;
88 }
89
90
91 InsetBibKey::~InsetBibKey()
92 {
93         if(bibitem_form && bibitem_form->bibitem_form
94            && bibitem_form->bibitem_form->visible
95            && bibitem_form->bibitem_form->u_vdata == &holder)
96                 fl_hide_form(bibitem_form->bibitem_form);
97 }
98
99
100 void InsetBibKey::callback( FD_bibitem_form * form, long data )
101 {
102         switch (data) {
103         case 1:
104                 if(!holder.view->buffer()->isReadonly()) {
105                         setContents(fl_get_input(form->key));
106                         setOptions(fl_get_input(form->label));
107                         // shouldn't mark the buffer dirty unless
108                         // something was actually altered
109                         holder.view->updateInset( this, true );
110                 } // fall through to Cancel
111         case 0:
112                 fl_hide_form(form->bibitem_form);
113                 break;
114         }
115 }
116
117
118 void InsetBibKey::setCounter(int c) 
119
120         counter = c; 
121     
122         if (getCmdName().empty())
123                 setCmdName( tostr(counter) );
124 }
125
126
127 // I'm sorry but this is still necessary because \bibitem is used also
128 // as a LyX 2.x command, and lyxlex is not enough smart to understand
129 // real LaTeX commands. Yes, that could be fixed, but would be a waste 
130 // of time cause LyX3 won't use lyxlex anyway.  (ale)
131 void InsetBibKey::Write(Buffer const *, ostream & os) const
132 {
133         os << "\\bibitem ";
134         if (! getOptions().empty()) {
135                 os << '['
136                    << getOptions() << ']';
137         }
138         os << '{'
139            << getContents() << "}\n";
140 }
141
142
143 // This is necessary here because this is written without begin_inset
144 // This should be changed!!! (Jug)
145 void InsetBibKey::Read(Buffer const *, LyXLex & lex)
146 {    
147         string token;
148
149         if (lex.EatLine()) {
150                 token = lex.GetString();
151                 scanCommand(token);
152         } else
153                 lex.printError("InsetCommand: Parse error: `$$Token'");
154 }
155
156
157 string InsetBibKey::getScreenLabel() const
158 {
159         if (! getOptions().empty())
160                 return getOptions();
161     
162         return tostr(counter);
163 }
164
165
166 /**
167   The value in "Key:" isn't allways set right after a few bibkey insets have
168   been added/removed.  Perhaps the wrong object is deleted/used somewhere
169   upwards?
170   (Joacim 1998-03-04)
171 */
172 void InsetBibKey::Edit(BufferView * bv, int, int, unsigned int)
173 {
174         if(bv->buffer()->isReadonly())
175                 WarnReadonly(bv->buffer()->fileName());
176         
177         if (!bibitem_form) {
178                 bibitem_form = create_form_bibitem_form();
179                 fl_set_form_atclose(bibitem_form->bibitem_form, 
180                                     CancelCloseBoxCB, 0);
181         }
182
183         holder.inset = this;
184         holder.view = bv;
185         
186         bibitem_form->bibitem_form->u_vdata = &holder;
187         // InsetBibtex uses the same form, with different labels
188         fl_set_object_label(bibitem_form->key, idex(_("Key:|#K")));
189         fl_set_button_shortcut(bibitem_form->key, scex(_("Key:|#K")), 1);
190         fl_set_object_label(bibitem_form->label, idex(_("Label:|#L")));
191         fl_set_button_shortcut(bibitem_form->label, scex(_("Label:|#L")), 1);
192         fl_set_input(bibitem_form->key, getContents().c_str());
193         fl_set_input(bibitem_form->label, getOptions().c_str());
194         if (bibitem_form->bibitem_form->visible) {
195                 fl_raise_form(bibitem_form->bibitem_form);
196         } else {
197                 fl_show_form(bibitem_form->bibitem_form, FL_PLACE_MOUSE,
198                              FL_FULLBORDER,
199                              _("Bibliography item"));
200         }   
201 }
202
203
204 InsetBibtex::InsetBibtex(string const & dbase, string const & style,
205                          Buffer * o)
206         : InsetCommand("BibTeX", dbase, style), owner(o)
207 {}
208
209
210 InsetBibtex::~InsetBibtex()
211 {
212         if(bibitem_form && bibitem_form->bibitem_form
213            && bibitem_form->bibitem_form->visible
214            && bibitem_form->bibitem_form->u_vdata == &holder)
215                 fl_hide_form(bibitem_form->bibitem_form);
216 }
217
218
219 string InsetBibtex::getScreenLabel() const
220 {
221         return _("BibTeX Generated References");
222 }
223
224
225 int InsetBibtex::Latex(Buffer const *, ostream & os,
226                        bool /*fragile*/, bool/*fs*/) const
227 {
228         // this looks like an horrible hack and it is :) The problem
229         // is that owner is not initialized correctly when the bib
230         // inset is cut and pasted. Such hacks will not be needed
231         // later (JMarc)
232         if (!owner) {
233                 owner = current_view->buffer();
234         }
235         // If we generate in a temp dir, we might need to give an
236         // absolute path there. This is a bit complicated since we can
237         // have a comma-separated list of bibliographies
238         string adb, db_out;
239         string db_in = getContents();
240         db_in = split(db_in, adb, ',');
241         while(!adb.empty()) {
242                 if (!owner->niceFile &&
243                     IsFileReadable(MakeAbsPath(adb, owner->filepath)+".bib")) 
244                          adb = MakeAbsPath(adb, owner->filepath);
245
246                 db_out += adb;
247                 db_out += ',';
248                 db_in= split(db_in, adb,',');
249         }
250         db_out = strip(db_out, ',');
251         // Idem, but simpler
252         string style;
253         if (!owner->niceFile 
254             && IsFileReadable(MakeAbsPath(getOptions(), owner->filepath)
255                               + ".bst")) 
256                 style = MakeAbsPath(getOptions(), owner->filepath);
257         else
258                 style = getOptions();
259
260         os << "\\bibliographystyle{" << style << "}\n"
261            << "\\bibliography{" << db_out << "}\n";
262         return 2;
263 }
264
265
266 // This method returns a comma separated list of Bibtex entries
267 vector<pair<string,string> > InsetBibtex::getKeys() const
268 {
269         // This hack is copied from InsetBibtex::Latex.
270         // Is it still needed? Probably yes.
271         // Why is this needed here when it already is in Latex?
272         // Anyway we need a different way to get to the
273         // buffer the inset is in. (Lgb)
274         
275         //if (!owner) {
276         //      owner = current_view->buffer();
277         //}
278         
279         Path p(owner->filepath);
280
281         vector<pair<string,string> > keys;
282         string tmp;
283         string bibfiles = getContents();
284         bibfiles = split(bibfiles, tmp, ',');
285         while(!tmp.empty()) {
286                 string fil = findtexfile(ChangeExtension(tmp, "bib"),
287                                          "bib");
288                 lyxerr[Debug::LATEX] << "Bibfile: " << fil << endl;
289                 // If we didn't find a matching file name just fail silently
290                 if (!fil.empty()) {
291                         // This is a _very_ simple parser for Bibtex database
292                         // files. All it does is to look for lines starting
293                         // in @ and not being @preamble and @string entries.
294                         // It does NOT do any syntax checking!
295                         ifstream ifs(fil.c_str());
296                         string linebuf0;
297                         while (getline(ifs, linebuf0)) {
298                                 string linebuf = frontStrip(strip(linebuf0));
299                                 if( linebuf.empty() ) continue;
300                                 if (prefixIs(linebuf, "@")) {
301                                         linebuf = subst(linebuf, '{', '(');
302                                         linebuf = split(linebuf, tmp, '(');
303                                         tmp = lowercase(tmp);
304                                         if (!prefixIs(tmp, "@string")
305                                             && !prefixIs(tmp, "@preamble")) {
306                                                 linebuf = split(linebuf, tmp, ',');
307                                                 tmp = frontStrip(tmp);
308                                                 if (!tmp.empty()) {
309                                                         keys.push_back(pair<string,string>(tmp,string()));
310                                                 }
311                                         }
312                                 } else if( !keys.empty() ) {
313                                         keys.back().second += linebuf + "\n";
314                                 }
315                         }
316                 }
317                 // Get next file name
318                 bibfiles = split(bibfiles, tmp, ',');
319         }
320         return keys;
321 }
322
323
324 // BibTeX should have its own dialog. This is provisional.
325 void InsetBibtex::Edit(BufferView * bv, int, int, unsigned int)
326 {
327         if (!bibitem_form) {
328                 bibitem_form = create_form_bibitem_form();
329                 fl_set_form_atclose(bibitem_form->bibitem_form, 
330                                     CancelCloseBoxCB, 0);
331         }
332
333         holder.inset = this;
334         holder.view = bv;
335         bibitem_form->bibitem_form->u_vdata = &holder;
336
337         fl_set_object_label(bibitem_form->key, _("Database:"));
338         fl_set_object_label(bibitem_form->label, _("Style:  "));
339         fl_set_input(bibitem_form->key, getContents().c_str());
340         fl_set_input(bibitem_form->label, getOptions().c_str());
341         if (bibitem_form->bibitem_form->visible) {
342                 fl_raise_form(bibitem_form->bibitem_form);
343         } else {
344                 fl_show_form(bibitem_form->bibitem_form,
345                              FL_PLACE_MOUSE, FL_FULLBORDER,
346                              _("BibTeX"));
347         }   
348 }
349
350
351 bool InsetBibtex::addDatabase(string const & db)
352 {
353         if (!contains(getContents(), db.c_str())) {
354                 if (!getContents().empty()) 
355                         addContents(",");
356                 addContents(db);
357                 return true;
358         }
359         return false;
360 }
361
362
363 bool InsetBibtex::delDatabase(string const & db)
364 {
365         if (contains(getContents(), db.c_str())) {
366                 string bd = db;
367                 int n = tokenPos(getContents(), ',', bd);
368                 if (n > 0) {
369                         // Weird code, would someone care to explain this?(Lgb)
370                         string tmp(", ");
371                         tmp += bd;
372                         setContents(subst(getContents(), tmp.c_str(), ", "));
373                 } else if (n == 0)
374                         setContents(split(getContents(), bd, ','));
375                 else 
376                         return false;
377         }
378         return true;
379 }
380
381
382 // ale070405 This function maybe shouldn't be here. We'll fix this at 0.13.
383 int bibitemMaxWidth(BufferView * bv, LyXFont const & font)
384 {
385         int w = 0;
386         // Does look like a hack? It is! (but will change at 0.13)
387         LyXParagraph * par = current_view->buffer()->paragraph;
388     
389         while (par) {
390                 if (par->bibkey) {
391                         int wx = par->bibkey->width(bv, font);
392                         if (wx > w) w = wx;
393                 }
394                 par = par->next;
395         }
396         return w;
397 }
398
399
400 // ale070405
401 string bibitemWidest(BufferView * bv)
402 {
403         int w = 0;
404         // Does look like a hack? It is! (but will change at 0.13)
405         LyXParagraph * par = current_view->buffer()->paragraph;
406         InsetBibKey * bkey = 0;
407         LyXFont font;
408       
409         while (par) {
410                 if (par->bibkey) {
411                         int wx = par->bibkey->width(bv, font);
412                         if (wx > w) {
413                                 w = wx;
414                                 bkey = par->bibkey;
415                         }
416                 }
417                 par = par->next;
418         }
419     
420         if (bkey && !bkey->getScreenLabel().empty())
421                 return bkey->getScreenLabel();
422     
423         return "99";
424 }