]> git.lyx.org Git - lyx.git/blob - src/insets/ExternalTemplate.C
5653623d4dbe2c2775239d9e2aa75d5ffe847452
[lyx.git] / src / insets / ExternalTemplate.C
1 /**
2  * \file ExternalTemplate.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup Nielsen
7  * \author Angus Leeming
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "ExternalTemplate.h"
15
16 #include "debug.h"
17 #include "lyxlex.h"
18
19 #include "support/filetools.h"
20 #include "support/lstrings.h"
21 #include "support/package.h"
22 #include "support/path.h"
23
24 namespace support = lyx::support;
25
26 using std::endl;
27 using std::for_each;
28
29 using std::string;
30 using std::ostream;
31 using std::vector;
32
33
34 namespace lyx {
35 namespace external {
36
37 namespace {
38
39 typedef Translator<TransformID, string> TransformIDTranslator;
40 TransformIDTranslator const & transformIDTranslator();
41
42 } // namespace anon
43
44
45 // We have to have dummy default commands for security reasons!
46 Template::Template()
47         : inputFormat("*")
48 {}
49
50
51 Template::Format::Format()
52 {}
53
54
55 TemplateManager::TemplateManager()
56 {
57         readTemplates(support::package().user_support());
58         if (lyxerr.debugging(Debug::EXTERNAL)) {
59                 dumpPreambleDefs(lyxerr);
60                 lyxerr << '\n';
61                 dumpTemplates(lyxerr);
62         }
63 }
64
65
66 class dumpPreambleDef {
67 public:
68         typedef TemplateManager::PreambleDefs::value_type value_type;
69
70         dumpPreambleDef(ostream & o) : ost(o) {}
71
72         void operator()(value_type const & vt) {
73                 ost << "PreambleDef " << vt.first << '\n'
74                     << vt.second
75                     << "PreambleDefEnd" << endl;
76         }
77
78 private:
79         ostream & ost;
80 };
81
82
83 class dumpTemplate {
84 public:
85         typedef TemplateManager::Templates::value_type value_type;
86
87         dumpTemplate(ostream & o) : ost(o) {}
88
89         void operator()(value_type const & vt) {
90                 Template const & et = vt.second;
91
92                 ost << "Template " << et.lyxName << '\n'
93                     << "\tGuiName " << et.guiName << '\n'
94                     << "\tHelpText\n"
95                     << et.helpText
96                     << "\tHelpTextEnd\n"
97                     << "\tInputFormat " << et.inputFormat << '\n'
98                     << "\tFileFilter " << et.fileRegExp << '\n'
99                     << "\tAutomaticProduction " << et.automaticProduction << '\n';
100
101                 typedef vector<TransformID> IDs;
102                 IDs::const_iterator it  = et.transformIds.begin();
103                 IDs::const_iterator end = et.transformIds.end();
104                 for (; it != end; ++it) {
105                         ost << "\tTransform "
106                             << transformIDTranslator().find(*it) << '\n';
107                 }
108
109                 et.dumpFormats(ost);
110                 ost << "TemplateEnd" << endl;
111
112         }
113
114 private:
115         ostream & ost;
116 };
117
118 class dumpFormat {
119 public:
120         typedef Template::Formats::value_type value_type;
121
122         dumpFormat(ostream & o) : ost(o) {}
123
124         void operator()(value_type const & vt) const {
125                 Template::Format const & ft = vt.second;
126                 ost << "\tFormat " << vt.first << '\n'
127                     << "\t\tProduct " << ft.product << '\n'
128                     << "\t\tUpdateFormat " << ft.updateFormat << '\n'
129                     << "\t\tUpdateResult " << ft.updateResult << '\n';
130
131                 vector<string>::const_iterator qit = ft.requirements.begin();
132                 vector<string>::const_iterator qend = ft.requirements.end();
133                 for (; qit != qend; ++qit) {
134                         lyxerr << "req:" << *qit << std::endl;
135                         ost << "\t\tRequirement " << *qit << '\n';
136                 }
137
138                 typedef vector<Template::Option> Options;
139                 Options::const_iterator oit  = ft.options.begin();
140                 Options::const_iterator oend = ft.options.end();
141                 for (; oit != oend; ++oit) {
142                         ost << "\t\tOption "
143                             << oit->name
144                             << ": "
145                             << oit->option
146                             << '\n';
147                 }
148
149                 vector<string>::const_iterator pit  = ft.preambleNames.begin();
150                 vector<string>::const_iterator pend = ft.preambleNames.end();
151                 for (; pit != pend; ++pit) {
152                         ost << "\t\tPreamble " << *pit << '\n';
153                 }
154
155                 typedef Template::Format::FileMap FileMap;
156                 FileMap::const_iterator rit  = ft.referencedFiles.begin();
157                 FileMap::const_iterator rend = ft.referencedFiles.end();
158                 for (; rit != rend; ++rit) {
159                         vector<string>::const_iterator fit  = rit->second.begin();
160                         vector<string>::const_iterator fend = rit->second.end();
161                         for (; fit != fend; ++fit) {
162                                 ost << "\t\tReferencedFile " << rit->first
163                                     << " \"" << *fit << "\"\n";
164                         }
165                 }
166
167                 ost << "\tFormatEnd\n";
168         }
169 private:
170         ostream & ost;
171 };
172
173
174 void Template::dumpFormats(ostream & os) const
175 {
176         for_each(formats.begin(), formats.end(), dumpFormat(os));
177 }
178
179
180 void TemplateManager::dumpPreambleDefs(ostream & os) const
181 {
182         for_each(preambledefs.begin(), preambledefs.end(), dumpPreambleDef(os));
183 }
184
185
186 void TemplateManager::dumpTemplates(ostream & os) const
187 {
188         for_each(templates.begin(), templates.end(), dumpTemplate(os));
189 }
190
191
192 TemplateManager & TemplateManager::get()
193 {
194         static TemplateManager externalTemplateManager;
195         return externalTemplateManager;
196 }
197
198
199 TemplateManager::Templates const &
200 TemplateManager::getTemplates() const
201 {
202         return templates;
203 }
204
205
206 Template const *
207 TemplateManager::getTemplateByName(string const & name) const
208 {
209         Templates::const_iterator it = templates.find(name);
210         return (it == templates.end()) ? 0 : &it->second;
211 }
212
213
214 string const
215 TemplateManager::getPreambleDefByName(string const & name) const
216 {
217         string const trimmed_name = support::trim(name);
218         if (trimmed_name.empty())
219                 return string();
220
221         PreambleDefs::const_iterator it = preambledefs.find(trimmed_name);
222         if (it == preambledefs.end())
223                 return string();
224
225         return it->second;
226 }
227
228
229 void TemplateManager::readTemplates(string const & path)
230 {
231         support::Path p(path);
232
233         enum TemplateTags {
234                 TM_PREAMBLEDEF = 1,
235                 TM_PREAMBLEDEF_END,
236                 TM_TEMPLATE,
237                 TM_TEMPLATE_END
238         };
239
240         keyword_item templatetags[] = {
241                 { "preambledef", TM_PREAMBLEDEF },
242                 { "preambledefend", TM_PREAMBLEDEF_END },
243                 { "template", TM_TEMPLATE },
244                 { "templateend", TM_TEMPLATE_END }
245         };
246
247         LyXLex lex(templatetags, TM_TEMPLATE_END);
248
249         string filename = support::LibFileSearch("", "external_templates");
250         if (filename.empty() || !lex.setFile(filename)) {
251                 lex.printError("external::TemplateManager::readTemplates: "
252                                "No template file");
253                 return;
254         }
255
256         char const * const preamble_end_tag =
257                 templatetags[TM_PREAMBLEDEF_END-1].tag;
258
259         while (lex.isOK()) {
260                 switch (lex.lex()) {
261                 case TM_PREAMBLEDEF: {
262                         lex.next();
263                         string const name = lex.getString();
264                         preambledefs[name] = lex.getLongString(preamble_end_tag);
265                 }
266                 break;
267
268                 case TM_TEMPLATE: {
269                         lex.next();
270                         string const name = lex.getString();
271                         Template & tmp = templates[name];
272                         tmp.lyxName = name;
273                         tmp.readTemplate(lex);
274                 }
275                 break;
276
277                 case TM_TEMPLATE_END:
278                         lex.printError("Warning: End outside Template.");
279                 break;
280
281                 case TM_PREAMBLEDEF_END:
282                         lex.printError("Warning: End outside PreambleDef.");
283                 break;
284                 }
285         }
286 }
287
288
289 namespace {
290
291 void add(vector<TransformID> & ids, string const & name)
292 {
293         TransformID id = transformIDTranslator().find(name);
294         if (int(id) == -1) {
295                 lyxerr << "external::Template::readTemplate\n"
296                        << "Transform " << name << " is not recognized"
297                        << std::endl;
298         } else {
299                 ids.push_back(id);
300         }
301 }
302
303 } // namespace anon
304
305
306 void Template::readTemplate(LyXLex & lex)
307 {
308         enum TemplateOptionTags {
309                 TO_GUINAME = 1,
310                 TO_HELPTEXT,
311                 TO_INPUTFORMAT,
312                 TO_FILTER,
313                 TO_AUTOMATIC,
314                 TO_TRANSFORM,
315                 TO_FORMAT,
316                 TO_END
317         };
318
319         keyword_item templateoptiontags[] = {
320                 { "automaticproduction", TO_AUTOMATIC },
321                 { "filefilter", TO_FILTER },
322                 { "format", TO_FORMAT },
323                 { "guiname", TO_GUINAME },
324                 { "helptext", TO_HELPTEXT },
325                 { "inputformat", TO_INPUTFORMAT },
326                 { "templateend", TO_END },
327                 { "transform", TO_TRANSFORM }
328         };
329
330         pushpophelper pph(lex, templateoptiontags, TO_END);
331
332         while (lex.isOK()) {
333                 switch (lex.lex()) {
334                 case TO_GUINAME:
335                         lex.next(true);
336                         guiName = lex.getString();
337                         break;
338
339                 case TO_HELPTEXT:
340                         helpText = lex.getLongString("HelpTextEnd");
341                         break;
342
343                 case TO_INPUTFORMAT:
344                         lex.next(true);
345                         inputFormat = lex.getString();
346                         break;
347
348                 case TO_FILTER:
349                         lex.next(true);
350                         fileRegExp = lex.getString();
351                         break;
352
353                 case TO_AUTOMATIC:
354                         lex.next();
355                         automaticProduction = lex.getBool();
356                         break;
357
358                 case TO_TRANSFORM:
359                         lex.next(true);
360                         add(transformIds, lex.getString());
361                         break;
362
363                 case TO_FORMAT:
364                         lex.next(true);
365                         formats[lex.getString()].readFormat(lex);
366                         break;
367
368                 case TO_END:
369                         return;
370
371                 default:
372                         lex.printError("external::Template::readTemplate: "
373                                        "Wrong tag: $$Token");
374                         BOOST_ASSERT(false);
375                         break;
376                 }
377         }
378 }
379
380
381 namespace {
382
383 void transform_not_found(std::ostream & os, string const & transform)
384 {
385         os << "external::Format::readFormat. Transformation \""
386            << transform << "\" is unrecognized." << std::endl;
387 }
388
389
390 void transform_class_not_found(std::ostream & os, string const & tclass)
391 {
392         os << "external::Format::readFormat. Transformation class \""
393            << tclass << "\" is unrecognized." << std::endl;
394 }
395
396
397 void setCommandFactory(Template::Format & format, string const & transform,
398                        string const & transformer_class)
399 {
400         bool class_found = false;
401         if (transform == "Resize" && transformer_class == "ResizeLatexCommand") {
402                 class_found = true;
403                 ResizeCommandFactory factory = ResizeLatexCommand::factory;
404                 format.command_transformers[Resize] =
405                         TransformStore(Resize, factory);
406
407         } else if (transform == "Rotate" &&
408                    transformer_class == "RotationLatexCommand") {
409                 class_found = true;
410                 RotationCommandFactory factory = RotationLatexCommand::factory;
411                 format.command_transformers[Rotate] =
412                         TransformStore(Rotate, factory);
413
414         } else
415                 transform_not_found(lyxerr, transform);
416
417         if (!class_found)
418                 transform_class_not_found(lyxerr, transformer_class);
419 }
420
421
422 void setOptionFactory(Template::Format & format, string const & transform,
423                 string const & transformer_class)
424 {
425         bool class_found = false;
426         if (transform == "Clip" && transformer_class == "ClipLatexOption") {
427                 class_found = true;
428                 ClipOptionFactory factory = ClipLatexOption::factory;
429                 format.option_transformers[Clip] =
430                                 TransformStore(Clip, factory);
431
432         } else if (transform == "Extra" && transformer_class == "ExtraOption") {
433                 class_found = true;
434                 ExtraOptionFactory factory = ExtraOption::factory;
435                 format.option_transformers[Extra] =
436                         TransformStore(Extra, factory);
437
438         } else if (transform == "Resize" &&
439                    transformer_class == "ResizeLatexOption") {
440                 class_found = true;
441                 ResizeOptionFactory factory = ResizeLatexOption::factory;
442                 format.option_transformers[Resize] =
443                         TransformStore(Resize, factory);
444
445         } else if (transform == "Rotate" &&
446                    transformer_class == "RotationLatexOption") {
447                 class_found = true;
448                 RotationOptionFactory factory = RotationLatexOption::factory;
449                 format.option_transformers[Rotate] =
450                         TransformStore(Rotate, factory);
451
452         } else
453                 transform_not_found(lyxerr, transform);
454
455         if (!class_found)
456                 transform_class_not_found(lyxerr, transformer_class);
457 }
458
459 } // namespace anon
460
461
462 void Template::Format::readFormat(LyXLex & lex)
463 {
464         enum FormatTags {
465                 FO_PRODUCT = 1,
466                 FO_UPDATEFORMAT,
467                 FO_UPDATERESULT,
468                 FO_REQUIREMENT,
469                 FO_OPTION,
470                 FO_PREAMBLE,
471                 FO_TRANSFORMCOMMAND,
472                 FO_TRANSFORMOPTION,
473                 FO_REFERENCEDFILE,
474                 FO_END
475         };
476
477         keyword_item formattags[] = {
478                 { "formatend", FO_END },
479                 { "option", FO_OPTION },
480                 { "preamble", FO_PREAMBLE },
481                 { "product", FO_PRODUCT },
482                 { "referencedfile", FO_REFERENCEDFILE },
483                 { "requirement", FO_REQUIREMENT },
484                 { "transformcommand", FO_TRANSFORMCOMMAND },
485                 { "transformoption", FO_TRANSFORMOPTION },
486                 { "updateformat", FO_UPDATEFORMAT },
487                 { "updateresult", FO_UPDATERESULT }
488         };
489
490         pushpophelper pph(lex, formattags, FO_END);
491
492         while (lex.isOK()) {
493                 switch (lex.lex()) {
494                 case FO_PRODUCT:
495                         lex.next(true);
496                         product = lex.getString();
497                         break;
498
499                 case FO_UPDATEFORMAT:
500                         lex.next(true);
501                         updateFormat = lex.getString();
502                         break;
503
504                 case FO_UPDATERESULT:
505                         lex.next(true);
506                         updateResult = lex.getString();
507                         break;
508
509                 case FO_REQUIREMENT:
510                         lex.next(true);
511                         requirements.push_back(lex.getString());
512                         break;
513
514                 case FO_PREAMBLE:
515                         lex.next(true);
516                         preambleNames.push_back(lex.getString());
517                         break;
518
519                 case FO_TRANSFORMCOMMAND: {
520                         lex.next(true);
521                         string const name = lex.getString();
522                         lex.next(true);
523                         setCommandFactory(*this, name, lex.getString());
524                         break;
525                 }
526
527                 case FO_TRANSFORMOPTION: {
528                         lex.next(true);
529                         string const name = lex.getString();
530                         lex.next(true);
531                         setOptionFactory(*this, name, lex.getString());
532                         break;
533                 }
534
535                 case FO_OPTION: {
536                         lex.next(true);
537                         string const name = lex.getString();
538                         lex.next(true);
539                         string const opt = lex.getString();
540                         options.push_back(Option(name, opt));
541                         break;
542                 }
543
544                 case FO_REFERENCEDFILE: {
545                         lex.next(true);
546                         string const format = lex.getString();
547                         lex.next(true);
548                         string const file = lex.getString();
549                         referencedFiles[format].push_back(file);
550                         break;
551                 }
552
553                 case FO_END:
554                         return;
555                 }
556         }
557 }
558
559 namespace {
560
561 TransformIDTranslator const initIDTranslator()
562 {
563         TransformIDTranslator translator(TransformID(-1), "");
564         translator.addPair(Rotate, "Rotate");
565         translator.addPair(Resize, "Resize");
566         translator.addPair(Clip,   "Clip");
567         translator.addPair(Extra,  "Extra");
568         return translator;
569 }
570
571
572 TransformIDTranslator const & transformIDTranslator()
573 {
574         static TransformIDTranslator const translator = initIDTranslator();
575         return translator;
576 }
577
578 } // namespace anon
579
580 } // namespace external
581 } // namespace lyx