]> git.lyx.org Git - lyx.git/blob - src/insets/insetexternal.C
Insetcite updates from Angus
[lyx.git] / src / insets / insetexternal.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright 1995 Matthias Ettrich
7  *          Copyright 1995-2000 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include FORMS_H_LOCATION
18 #include <cstdio>
19
20 #include "insetexternal.h"
21 #include "ExternalTemplate.h"
22 #include "lyx_gui_misc.h" // CancelCloseBoxCB
23 #include "BufferView.h"
24 #include "buffer.h"
25 #include "filedlg.h"
26 #include "lyx_main.h"
27 #include "LaTeXFeatures.h"
28 #include "support/filetools.h"
29 #include "support/lstrings.h"
30 #include "support/path.h"
31 #include "support/syscall.h"
32
33 using std::endl;
34
35
36 InsetExternal::InsetExternal() 
37         : form_external(0)
38 {
39         tempname = TmpFileName();
40 }
41
42
43 InsetExternal::~InsetExternal()
44 {
45         remove(tempname.c_str());
46 }
47
48
49 extern "C"
50 void ExternalTemplateCB(FL_OBJECT * ob, long data)
51 {
52         InsetExternal::templateCB(ob, data);
53 }
54
55
56 extern "C"
57 void ExternalBrowseCB(FL_OBJECT * ob, long data)
58 {
59         InsetExternal::browseCB(ob, data);
60 }
61
62
63 extern "C"
64 void ExternalEditCB(FL_OBJECT * ob, long data)
65 {
66         InsetExternal::editCB(ob, data);
67 }
68
69
70 extern "C"
71 void ExternalViewCB(FL_OBJECT * ob, long data)
72 {
73         InsetExternal::viewCB(ob, data);
74 }
75
76
77 extern "C"
78 void ExternalUpdateCB(FL_OBJECT * ob, long data)
79 {
80         InsetExternal::updateCB(ob, data);
81 }
82
83
84 extern "C"
85 void ExternalOKCB(FL_OBJECT * ob, long data)
86 {
87         InsetExternal::okCB(ob, data);
88 }
89
90
91 extern "C"
92 void ExternalCancelCB(FL_OBJECT * ob, long data)
93 {
94         InsetExternal::cancelCB(ob, data);
95 }
96
97
98 void InsetExternal::templateCB(FL_OBJECT * ob, long)
99 {
100         Holder * holder = static_cast<Holder*>(ob->form->u_vdata);
101         InsetExternal * inset = holder->inset;
102         ExternalTemplate et = inset->getTemplate(inset->getCurrentTemplate());
103         // Update the help text
104         fl_clear_browser(inset->form_external->helptext);
105         fl_addto_browser(inset->form_external->helptext, et.helpText.c_str());
106         fl_set_browser_topline(inset->form_external->helptext, 0);
107 }
108
109
110 void InsetExternal::browseCB(FL_OBJECT * ob, long)
111 {
112         Holder * holder = static_cast<Holder*>(ob->form->u_vdata);
113         InsetExternal * inset = holder->inset;
114
115         static string current_path;
116         static int once = 0;
117         LyXFileDlg fileDlg;
118         
119         string p = inset->filename;
120         string buf = MakeAbsPath(holder->view->buffer()->fileName());
121         string buf2 = OnlyPath(buf);
122         if (!p.empty()) {
123                 buf = MakeAbsPath(p, buf2);
124                 buf = OnlyPath(buf);
125         } else {
126                 buf = OnlyPath(holder->view->buffer()->fileName().c_str());
127         }
128        
129         fileDlg.SetButton(0, _("Document"), buf); 
130
131         /// Determine the template file extension
132         ExternalTemplate et = inset->getTemplate(inset->getCurrentTemplate());
133         string regexp = et.fileRegExp;
134         if (regexp.empty()) {
135                 regexp = "*";
136         }
137
138         bool error = false;
139         do {
140                 //      ProhibitInput(current_view);
141                 if (once) {
142                         p = fileDlg.Select(_("External inset file"),
143                                            current_path,
144                                            regexp, string());
145                 } else {
146                         p = fileDlg.Select(_("External inset file"), buf,
147                                            regexp, string());
148                 }
149                 //      AllowInput(current_view);
150
151                 if (p.empty()) return;
152
153                 buf = MakeRelPath(p, buf2);
154                 current_path = OnlyPath(p);
155                 once = 1;
156                 
157                 if (contains(p, "#") || contains(p, "~") || contains(p, "$")
158                     || contains(p, "%")) {
159                         WriteAlert(_("Filename can't contain any "
160                                      "of these characters:"),
161                                    // xgettext:no-c-format
162                                    _("'#', '~', '$' or '%'.")); 
163                         error = true;
164                 }
165         } while (error);
166
167         if (inset->form_external) 
168                 fl_set_input(inset->form_external->filename, buf.c_str());
169         
170 }
171
172
173 void InsetExternal::editCB(FL_OBJECT * ob, long)
174 {
175         Holder * holder = static_cast<Holder*>(ob->form->u_vdata);
176         InsetExternal * inset = holder->inset;
177         inset->doApply(holder->view);
178         inset->doEdit(holder->view);
179 }
180
181
182 void InsetExternal::viewCB(FL_OBJECT * ob, long)
183 {
184         Holder * holder = static_cast<Holder*>(ob->form->u_vdata);
185         InsetExternal * inset = holder->inset;
186         inset->doApply(holder->view);
187         inset->doView(holder->view);
188 }
189
190
191 void InsetExternal::updateCB(FL_OBJECT * ob, long)
192 {
193         Holder * holder = static_cast<Holder*>(ob->form->u_vdata);
194         InsetExternal * inset = holder->inset;
195         inset->doApply(holder->view);
196         inset->doUpdate(holder->view);
197 }
198
199
200 void InsetExternal::okCB(FL_OBJECT * ob, long data)
201 {
202         Holder * holder = static_cast<Holder*>(ob->form->u_vdata);
203         InsetExternal * inset = holder->inset;
204         inset->doApply(holder->view);
205         cancelCB(ob,data);
206 }
207
208
209 void InsetExternal::doApply(BufferView * bufview)
210 {
211         bool update = false;
212         if (templatename != getCurrentTemplate()) {
213                 templatename = getCurrentTemplate();
214                 update = true;
215         }
216         if (filename != fl_get_input(form_external->filename)) {
217                 filename = fl_get_input(form_external->filename);
218                 update = true;
219         }
220         if (parameters != fl_get_input(form_external->parameters)) {
221                 parameters = fl_get_input(form_external->parameters);
222                 update = true;
223         }
224
225         if (update) {
226                 // The text might have change,
227                 // so we should update the button look
228                 bufview->updateInset(this, true);
229         }
230 }
231
232
233 void InsetExternal::cancelCB(FL_OBJECT * ob, long)
234 {
235         Holder * holder = static_cast<Holder*>(ob->form->u_vdata);
236
237         InsetExternal * inset = holder->inset;
238         // BufferView * bv = holder->view;
239
240         if (inset->form_external) {
241                 fl_hide_form(inset->form_external->form_external);
242                 fl_free_form(inset->form_external->form_external);
243                 inset->form_external = 0;
244         }
245 }
246
247
248 char const * InsetExternal::EditMessage() const
249 {
250         ExternalTemplate const & et = getTemplate(templatename);
251         return doSubstitution(0, et.guiName).c_str();
252 }
253
254
255 void InsetExternal::Edit(BufferView * bv,
256                          int /*x*/, int /*y*/, unsigned int /*button*/)
257 {
258         static int ow = -1, oh;
259
260         if (bv->buffer()->isReadonly())
261                 WarnReadonly(bv->buffer()->fileName());
262
263         if (!form_external) {
264                 form_external = create_form_form_external();
265                 holder.inset = this;
266                 //              form_external->ok->u_vdata = &holder;
267                 form_external->form_external->u_vdata = &holder;
268                 fl_set_form_atclose(form_external->form_external,
269                                     CancelCloseBoxCB, 0);
270         }
271         holder.view = bv;
272         fl_addto_choice(form_external->templatechoice, getTemplateString().c_str());
273         fl_set_input(form_external->filename, filename.c_str());
274         fl_set_input(form_external->parameters, parameters.c_str());
275         if (!templatename.empty()) {
276                 fl_set_choice(form_external->templatechoice,
277                               getTemplateNumber(templatename));
278         }
279         // Update the help text
280         templateCB(form_external->templatechoice, 0);
281
282         ExternalTemplate const & et = getTemplate(templatename);
283         if (et.automaticProduction) {
284                 fl_deactivate_object(form_external->update);
285                 fl_set_object_lcol(form_external->update, FL_INACTIVE);
286         } else {
287                 fl_activate_object(form_external->update);
288                 fl_set_object_lcol(form_external->update, FL_BLACK);
289         }
290
291         if (form_external->form_external->visible) {
292                 fl_raise_form(form_external->form_external);
293         } else {
294                 fl_show_form(form_external->form_external,
295                              FL_PLACE_MOUSE | FL_FREE_SIZE,
296                              FL_FULLBORDER, _("Insert external inset"));
297                 if (ow < 0) {
298                         ow = form_external->form_external->w;
299                         oh = form_external->form_external->h;
300                 }
301                 fl_set_form_minsize(form_external->form_external, ow, oh);
302         }
303 }
304
305
306 void InsetExternal::Write(Buffer const *, std::ostream & os) const
307 {
308         os << "External " << templatename << ",\"" << filename 
309            << "\",\"" << parameters << "\"\n";
310 }
311
312
313 void InsetExternal::Read(Buffer const *, LyXLex & lex)
314 {
315         lex.EatLine();
316         string format = lex.GetString();
317         int pos1 = format.find(",");
318         templatename = format.substr(0, pos1);
319         int pos2 = format.find("\",\"", pos1);
320         filename = format.substr(pos1 + 2, pos2 - (pos1 + 2));
321         parameters = format.substr(pos2 + 3, format.length() - (pos2 + 4));
322
323         lyxerr << templatename << " " << filename << " " << parameters << endl;
324 }
325
326
327 int InsetExternal::write(string const & format,
328                          Buffer const * buf, std::ostream & os) const
329 {
330         ExternalTemplate const & et = getTemplate(templatename);
331         ExternalTemplate::Formats::const_iterator cit =
332                 et.formats.find(format);
333         if (cit == et.formats.end()) {
334                 lyxerr << "External template format '" << format
335                        << "' not specified in template " << templatename
336                        << endl;
337                 return 0;
338         }
339         
340         if (et.automaticProduction) {
341                 executeCommand(doSubstitution(buf,
342                                               (*cit).second.updateCommand),
343                                buf);
344         }
345         
346         os << doSubstitution(buf, (*cit).second.product);
347         return 0; // CHECK
348 }
349
350
351 int InsetExternal::Latex(Buffer const * buf,
352                          std::ostream & os, bool, bool) const
353 {
354         return write("LaTeX", buf, os);
355 }
356
357
358 int InsetExternal::Ascii(Buffer const * buf, std::ostream & os) const
359 {
360         return write("Ascii", buf, os);
361 }
362
363
364 int InsetExternal::Linuxdoc(Buffer const * buf, std::ostream & os) const
365 {
366         return write("LinuxDoc", buf, os);
367 }
368
369
370 int InsetExternal::DocBook(Buffer const * buf, std::ostream & os) const
371 {
372         return write("DocBook", buf, os);
373 }
374
375
376 void InsetExternal::Validate(LaTeXFeatures & features) const
377 {
378         ExternalTemplate const & et = getTemplate(templatename);
379         ExternalTemplate::Formats::const_iterator cit =
380                 et.formats.find("LaTeX");
381         if (cit == et.formats.end()) {
382                 return;
383         }
384         
385         if (!(*cit).second.requirement.empty()) {
386                 features.require((*cit).second.requirement);
387         }
388         if (!(*cit).second.preamble.empty()) {
389                 features.externalPreambles += (*cit).second.preamble + "\n";
390         }
391 }
392
393
394 Inset * InsetExternal::Clone() const
395 {
396         InsetExternal * inset = new InsetExternal();
397         inset->templatename = templatename;
398         inset->filename = filename;
399         inset->parameters = parameters;
400         return inset;
401 }
402
403
404 string InsetExternal::getScreenLabel() const
405 {
406         if (templatename.empty()) {
407                 return _("External");
408         } else {
409                 ExternalTemplate const & et = getTemplate(templatename);
410                 return doSubstitution(0, et.guiName);
411         }
412 }
413
414
415 void InsetExternal::doUpdate(BufferView const * bv) const
416 {
417         ExternalTemplate const & et = getTemplate(getCurrentTemplate());
418         ExternalTemplate::Formats::const_iterator cit =
419                 et.formats.find("LaTeX");
420         if (cit == et.formats.end())
421                 return;
422         
423         executeCommand(doSubstitution(bv->buffer(),
424                                       (*cit).second.updateCommand),
425                        bv->buffer());
426 }
427
428
429 void InsetExternal::doView(BufferView const * bv) const
430 {
431         automaticUpdate(bv);
432         ExternalTemplate const & et = getTemplate(getCurrentTemplate());
433         executeCommand(doSubstitution(bv->buffer(), et.viewCommand),
434                        bv->buffer());
435 }
436
437
438 void InsetExternal::doEdit(BufferView const * bv) const
439 {
440         automaticUpdate(bv);
441         ExternalTemplate const & et = getTemplate(getCurrentTemplate());
442         executeCommand(doSubstitution(bv->buffer(), et.editCommand),
443                        bv->buffer());
444 }
445
446
447 void InsetExternal::executeCommand(string const & s,
448                                    Buffer const * buffer) const
449 {
450         string buf = MakeAbsPath(buffer->fileName());
451         string path = OnlyPath(buf);
452         Path p(path);
453         Systemcalls one;
454         if (lyxerr.debugging()) {
455                 lyxerr << "Executing '" << s << "' in '"
456                        << path << "'" << endl;
457         }
458         one.startscript(Systemcalls::Wait, s);
459 }
460
461
462 void InsetExternal::automaticUpdate(BufferView const * bv) const
463 {
464         ExternalTemplate const & et = getTemplate(templatename);
465         if (et.automaticProduction) {
466                 doUpdate(bv);
467         }
468 }
469
470
471 string InsetExternal::doSubstitution(Buffer const * buffer,
472                                      string const & s) const
473 {
474         string result;
475         string basename = ChangeExtension(filename, string());
476         result = subst(s, "$$FName", filename);
477         result = subst(result, "$$Basename", basename);
478         result = subst(result, "$$Parameters", parameters);
479         result = ReplaceEnvironmentPath(result);
480         result = subst(result, "$$Tempname", tempname);
481         result = subst(result, "$$Sysdir", system_lyxdir);
482         
483         // Handle the $$Contents(filename) syntax
484         if (contains(result, "$$Contents(\"")) {
485
486                 int pos = result.find("$$Contents(\"");
487                 int end = result.find("\")", pos);
488                 string file = result.substr(pos + 12, end - (pos + 12));
489                 string contents;
490                 if (buffer) {
491                         // Make sure we are in the directory of the buffer
492                         string buf = MakeAbsPath(buffer->fileName());
493                         string path = OnlyPath(buf);
494                         Path p(path);
495                         contents = GetFileContents(file);
496                 } else {
497                         contents = GetFileContents(file);
498                 }
499                 result = subst(result,
500                                ("$$Contents(\"" + file + "\")").c_str(),
501                                contents);
502         }
503
504         return result;
505 }
506
507
508 string InsetExternal::getCurrentTemplate() const
509 {
510         return getTemplateName(fl_get_choice(form_external->templatechoice));
511 }
512
513
514 ExternalTemplate InsetExternal::getTemplate(string const & name) const
515 {
516         ExternalTemplateManager::Templates::const_iterator i = 
517                 ExternalTemplateManager::get().getTemplates().find(name);
518         // Make sure that the template exists in the map
519         if (i == ExternalTemplateManager::get().getTemplates().end()) {
520                 lyxerr << "Unknown external material template: "
521                        << name << endl;
522                 return ExternalTemplate();
523         }
524         return (*i).second;
525 }
526
527
528 int InsetExternal::getTemplateNumber(string const & name) const
529 {
530         int i = 1;
531         ExternalTemplateManager::Templates::const_iterator i1, i2;
532         i1 = ExternalTemplateManager::get().getTemplates().begin();
533         i2 = ExternalTemplateManager::get().getTemplates().end();
534         for (; i1 != i2; ++i1) {
535                 if ((*i1).second.lyxName == name)
536                         return i;
537                 ++i;
538         }
539         // This should never happen
540         Assert(false);
541         return 0;
542 }
543
544
545 string InsetExternal::getTemplateName(int i) const
546 {
547         ExternalTemplateManager::Templates::const_iterator i1;
548         i1 = ExternalTemplateManager::get().getTemplates().begin();
549         for (int n = 1; n < i; ++n) {
550                 ++i1;
551         }
552         return (*i1).second.lyxName;
553 }
554
555
556 string InsetExternal::getTemplateString() const
557 {
558         string result;
559         bool first = true;
560         ExternalTemplateManager::Templates::const_iterator i1, i2;
561         i1 = ExternalTemplateManager::get().getTemplates().begin();
562         i2 = ExternalTemplateManager::get().getTemplates().end();
563         for (; i1 != i2; ++i1) {
564                 if (!first) {
565                         result += "|";
566                 } else {
567                         first = false;
568                 }
569                 result += (*i1).second.lyxName;
570         }
571         return result;
572 }