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