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