]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
Comments
[features.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "LaTeXPackages.h"
28 #include "Layout.h"
29 #include "Lexer.h"
30 #include "LyXRC.h"
31 #include "TextClass.h"
32
33 #include "insets/InsetLayout.h"
34
35 #include "support/debug.h"
36 #include "support/docstream.h"
37 #include "support/FileName.h"
38 #include "support/filetools.h"
39 #include "support/gettext.h"
40 #include "support/lstrings.h"
41 #include "support/regex.h"
42
43 #include <algorithm>
44
45
46 using namespace std;
47 using namespace lyx::support;
48
49
50 namespace lyx {
51
52 /////////////////////////////////////////////////////////////////////
53 //
54 // Strings
55 //
56 /////////////////////////////////////////////////////////////////////
57
58 //\NeedsTeXFormat{LaTeX2e}
59 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
60 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
61
62 static docstring const lyx_def = from_ascii(
63         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
64
65 static docstring const lyx_hyperref_def = from_ascii(
66         "\\providecommand{\\LyX}{\\texorpdfstring%\n"
67         "  {L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}\n"
68         "  {LyX}}");
69
70 static docstring const noun_def = from_ascii(
71         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
72
73 static docstring const lyxarrow_def = from_ascii(
74         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
75         "\\@ifstar\n"
76         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
77         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
78
79 // for quotes without babel. This does not give perfect results, but
80 // anybody serious about non-english quotes should use babel (JMarc).
81
82 static docstring const quotedblbase_def = from_ascii(
83         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
84         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
85         "  \\penalty10000\\hskip0em\\relax%\n"
86         "}");
87
88 static docstring const quotesinglbase_def = from_ascii(
89         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
90         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
91         "  \\penalty10000\\hskip0em\\relax%\n"
92         "}");
93
94 static docstring const guillemotleft_def = from_ascii(
95         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
96         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
97         "\\penalty10000\\hskip0pt\\relax%\n"
98         "}");
99
100 static docstring const guillemotright_def = from_ascii(
101         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
102         "  \\penalty10000\\hskip0pt%\n"
103         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
104         "}");
105
106 static docstring const guilsinglleft_def = from_ascii(
107         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
108         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
109         "  \\penalty10000\\hskip0pt\\relax%\n"
110         "}");
111
112 static docstring const guilsinglright_def = from_ascii(
113         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
114         "  \\penalty10000\\hskip0pt%\n"
115         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
116         "}");
117
118 static docstring const paragraphleftindent_def = from_ascii(
119         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
120         "{\n"
121         "  \\begin{list}{}{%\n"
122         "    \\setlength{\\topsep}{0pt}%\n"
123         "    \\addtolength{\\leftmargin}{#1}\n"
124 // ho hum, yet more things commented out with no hint as to why they
125 // weren't just removed
126 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
127 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
128 //      "%%    \\setlength\\listparindent\\parindent%\n"
129 //      "%%    \\setlength\\itemindent\\parindent%\n"
130         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
131         "  }\n"
132         "  \\item[]\n"
133         "}\n"
134         "{\\end{list}}\n");
135
136 static docstring const floatingfootnote_def = from_ascii(
137         "%% Special footnote code from the package 'stblftnt.sty'\n"
138         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
139         "\\let\\SF@@footnote\\footnote\n"
140         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
141         "    \\expandafter\\SF@@footnote\n"
142         "  \\else\n"
143         "    \\expandafter\\SF@gobble@opt\n"
144         "  \\fi\n"
145         "}\n"
146         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
147         "  \\SF@gobble@twobracket\n"
148         "  \\@gobble\n"
149         "}\n"
150         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
151         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
152         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
153
154 static docstring const binom_def = from_ascii(
155         "%% Binom macro for standard LaTeX users\n"
156         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
157
158 static docstring const mathcircumflex_def = from_ascii(
159         "%% For printing a cirumflex inside a formula\n"
160         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
161
162 static docstring const tabularnewline_def = from_ascii(
163         "%% Because html converters don't know tabularnewline\n"
164         "\\providecommand{\\tabularnewline}{\\\\}\n");
165
166 static docstring const lyxgreyedout_def = from_ascii(
167         "%% The greyedout annotation environment\n"
168         "\\newenvironment{lyxgreyedout}\n"
169         "  {\\textcolor{note_fontcolor}\\bgroup\\ignorespaces}\n"
170         "  {\\ignorespacesafterend\\egroup}\n");
171
172 // We want to omit the file extension for includegraphics, but this does not
173 // work when the filename contains other dots.
174 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
175 static docstring const lyxdot_def = from_ascii(
176         "%% A simple dot to overcome graphicx limitations\n"
177         "\\newcommand{\\lyxdot}{.}\n");
178
179 static docstring const changetracking_dvipost_def = from_ascii(
180         "%% Change tracking with dvipost\n"
181         "\\dvipostlayout\n"
182         "\\dvipost{osstart color push Red}\n"
183         "\\dvipost{osend color pop}\n"
184         "\\dvipost{cbstart color push Blue}\n"
185         "\\dvipost{cbend color pop}\n"
186         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
187         "\\newcommand{\\lyxdeleted}[3]{%\n"
188         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
189
190 static docstring const changetracking_xcolor_ulem_def = from_ascii(
191         "%% Change tracking with ulem\n"
192         "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
193         "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
194
195 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
196         "%% Change tracking with ulem\n"
197         "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
198         "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
199
200 static docstring const changetracking_none_def = from_ascii(
201         "\\newcommand{\\lyxadded}[3]{#3}\n"
202         "\\newcommand{\\lyxdeleted}[3]{}\n");
203
204 static docstring const textgreek_def = from_ascii(
205         "\\DeclareRobustCommand{\\greektext}{%\n"
206         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
207         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
208         "\\DeclareFontEncoding{LGR}{}{}\n"
209         "\\DeclareTextSymbol{\\~}{LGR}{126}");
210
211 static docstring const textcyr_def = from_ascii(
212         "\\DeclareRobustCommand{\\cyrtext}{%\n"
213         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
214         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
215         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
216
217 static docstring const lyxmathsym_def = from_ascii(
218         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
219         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
220
221 static docstring const papersizedvi_def = from_ascii(
222         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
223
224 static docstring const papersizepdf_def = from_ascii(
225         "\\pdfpageheight\\paperheight\n"
226         "\\pdfpagewidth\\paperwidth\n");
227
228 static docstring const cedilla_def = from_ascii(
229         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
230         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
231
232 static docstring const subring_def = from_ascii(
233         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
234         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
235
236 static docstring const subdot_def = from_ascii(
237         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
238         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
239
240 static docstring const subhat_def = from_ascii(
241         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
242         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
243
244 static docstring const subtilde_def = from_ascii(
245         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
246         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
247
248 static docstring const dacute_def = from_ascii(
249         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
250
251 static docstring const tipasymb_def = from_ascii(
252         "\\DeclareFontEncoding{T3}{}{}\n"
253         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
254
255 static docstring const dgrave_def = from_ascii(
256         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
257
258 static docstring const rcap_def = from_ascii(
259         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
260
261 static docstring const ogonek_def = from_ascii(
262         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
263         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
264         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
265         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
266         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
267
268 static docstring const lyxref_def = from_ascii(
269                 "\\RS@ifundefined{subref}\n"
270                 "  {\\def\\RSsubtxt{section~}\\newref{sub}{name = \\RSsubtxt}}\n"
271                 "  {}\n"
272                 "\\RS@ifundefined{thmref}\n"
273                 "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
274                 "  {}\n"
275                 "\\RS@ifundefined{lemref}\n"
276                 "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n" 
277                 "  {}\n");
278
279
280 /////////////////////////////////////////////////////////////////////
281 //
282 // LaTeXFeatures
283 //
284 /////////////////////////////////////////////////////////////////////
285
286
287 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
288                              OutputParams const & r)
289         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
290 {}
291
292
293 LaTeXFeatures::LangPackage LaTeXFeatures::langPackage(bool englishbabel) const
294 {
295         string const local_lp = bufferParams().lang_package;
296
297         // Locally, custom is just stored as a string
298         // in bufferParams().lang_package.
299         if (local_lp != "auto"
300             && local_lp != "babel"
301             && local_lp != "default"
302             && local_lp != "none")
303                  return LANG_PACK_CUSTOM;
304
305         if (local_lp == "none")
306                 return LANG_PACK_NONE;
307
308         /* If "auto" is selected, we load polyglossia if required,
309          * else we select babel.
310          * If babel is selected (either directly or via the "auto"
311          * mechanism), we really do only require it if we have
312          * a language that needs it.
313          * English alone normally does not require babel (since it is
314          * the default language of LaTeX). However, in some cases we
315          * need to surpass this exception (see Font::validate).
316          */
317         bool const polyglossia_required =
318                 isRequired("polyglossia")
319                 && isAvailable("polyglossia")
320                 && !params_.documentClass().provides("babel")
321                 && this->hasOnlyPolyglossiaLanguages();
322         bool const babel_required = 
323                 ((englishbabel || bufferParams().language->lang() != "english")
324                  && !bufferParams().language->babel().empty())
325                 || !this->getBabelLanguages().empty();
326
327         if (local_lp == "auto") {
328                 // polyglossia requirement has priority over babel
329                 if (polyglossia_required)
330                         return LANG_PACK_POLYGLOSSIA;
331                 else if (babel_required)
332                         return LANG_PACK_BABEL;
333         }
334
335         if (local_lp == "babel") {
336                 if (babel_required)
337                         return LANG_PACK_BABEL;
338         }
339
340         if (local_lp == "default") {
341                 switch (lyxrc.language_package_selection) {
342                 case LyXRC::LP_AUTO:
343                         // polyglossia requirement has priority over babel
344                         if (polyglossia_required)
345                                 return LANG_PACK_POLYGLOSSIA;
346                         else if (babel_required)
347                                 return LANG_PACK_BABEL;
348                         break;
349                 case LyXRC::LP_BABEL:
350                         if (babel_required)
351                                 return LANG_PACK_BABEL;
352                         break;
353                 case LyXRC::LP_CUSTOM:
354                         return LANG_PACK_CUSTOM;
355                 case LyXRC::LP_NONE:
356                         return LANG_PACK_NONE;
357                 }
358         }
359
360         return LANG_PACK_NONE;
361 }
362
363
364 void LaTeXFeatures::require(string const & name)
365 {
366         features_.insert(name);
367 }
368
369
370 void LaTeXFeatures::require(set<string> const & names)
371 {
372         features_.insert(names.begin(), names.end());
373 }
374
375
376 void LaTeXFeatures::useLayout(docstring const & layoutname)
377 {
378         // Some code to avoid loops in dependency definition
379         static int level = 0;
380         const int maxlevel = 30;
381         if (level > maxlevel) {
382                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
383                        << "recursion attained by layout "
384                        << to_utf8(layoutname) << endl;
385                 return;
386         }
387
388         DocumentClass const & tclass = params_.documentClass();
389         if (tclass.hasLayout(layoutname)) {
390                 // Is this layout already in usedLayouts?
391                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
392                     != usedLayouts_.end())
393                         return;
394
395                 Layout const & layout = tclass[layoutname];
396                 require(layout.requires());
397
398                 if (!layout.depends_on().empty()) {
399                         ++level;
400                         useLayout(layout.depends_on());
401                         --level;
402                 }
403                 usedLayouts_.push_back(layoutname);
404         } else {
405                 lyxerr << "LaTeXFeatures::useLayout: layout `"
406                        << to_utf8(layoutname) << "' does not exist in this class"
407                        << endl;
408         }
409
410         --level;
411 }
412
413
414 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
415 {
416         docstring const & lname = lay.name();
417         DocumentClass const & tclass = params_.documentClass();
418
419         // this is a default inset layout, nothing useful here
420         if (!tclass.hasInsetLayout(lname))
421                 return;
422         // Is this layout already in usedInsetLayouts?
423         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
424                         != usedInsetLayouts_.end())
425                 return;
426
427         require(lay.requires());
428         usedInsetLayouts_.push_back(lname);
429 }
430
431
432 bool LaTeXFeatures::isRequired(string const & name) const
433 {
434         return features_.find(name) != features_.end();
435 }
436
437
438 bool LaTeXFeatures::mustProvide(string const & name) const
439 {
440         return isRequired(name) && !params_.documentClass().provides(name);
441 }
442
443
444 bool LaTeXFeatures::isAvailable(string const & name)
445 {
446         string::size_type const i = name.find("->");
447         if (i != string::npos) {
448                 string const from = name.substr(0,i);
449                 string const to = name.substr(i+2);
450                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
451                 return theConverters().isReachable(from, to);
452         }
453         return LaTeXPackages::isAvailable(name);
454 }
455
456
457 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
458 {
459         SnippetList::const_iterator begin = preamble_snippets_.begin();
460         SnippetList::const_iterator end   = preamble_snippets_.end();
461         if (find(begin, end, preamble) == end)
462                 preamble_snippets_.push_back(preamble);
463 }
464
465
466 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
467 {
468         SnippetList::const_iterator begin = css_snippets_.begin();
469         SnippetList::const_iterator end   = css_snippets_.end();
470         if (find(begin, end, snippet) == end)
471                 css_snippets_.push_back(snippet);
472 }
473
474
475 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
476 {
477         if (!usedFloats_[name])
478                 usedFloats_[name] = subfloat;
479         if (subfloat)
480                 require("subfig");
481         // We only need float.sty if we use non builtin floats, or if we
482         // use the "H" modifier. This includes modified table and
483         // figure floats. (Lgb)
484         Floating const & fl = params_.documentClass().floats().getType(name);
485         if (!fl.floattype().empty() && fl.usesFloatPkg()) {
486                 require("float");
487         }
488 }
489
490
491 void LaTeXFeatures::useLanguage(Language const * lang)
492 {
493         if (!lang->babel().empty() || !lang->polyglossia().empty())
494                 UsedLanguages_.insert(lang);
495         if (!lang->requires().empty())
496                 require(lang->requires());
497         // CJK languages do not have a babel name.
498         // They use the CJK package
499         if (lang->encoding()->package() == Encoding::CJK)
500                 require("CJK");
501         // japanese package is special
502         if (lang->encoding()->package() == Encoding::japanese)
503                 require("japanese");
504 }
505
506
507 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
508 {
509         IncludedFiles_[key] = name;
510 }
511
512
513 bool LaTeXFeatures::hasLanguages() const
514 {
515         return !UsedLanguages_.empty();
516 }
517
518
519 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
520 {
521         LanguageList::const_iterator const begin = UsedLanguages_.begin();
522         for (LanguageList::const_iterator cit = begin;
523              cit != UsedLanguages_.end();
524              ++cit) {
525                 if ((*cit)->polyglossia().empty())
526                         return false;
527         }
528         return true;
529 }
530
531
532 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
533 {
534         LanguageList::const_iterator const begin = UsedLanguages_.begin();
535         for (LanguageList::const_iterator cit = begin;
536              cit != UsedLanguages_.end();
537              ++cit) {
538                 if ((*cit)->babel().empty() && !(*cit)->polyglossia().empty() && (*cit)->requires().empty())
539                         return true;
540         }
541         return false;
542 }
543
544
545 string LaTeXFeatures::getBabelLanguages() const
546 {
547         ostringstream languages;
548
549         bool first = true;
550         LanguageList::const_iterator const begin = UsedLanguages_.begin();
551         for (LanguageList::const_iterator cit = begin;
552              cit != UsedLanguages_.end();
553              ++cit) {
554                 if ((*cit)->babel().empty())
555                         continue;
556                 if (!first)
557                         languages << ',';
558                 else
559                         first = false;
560                 languages << (*cit)->babel();
561         }
562         return languages.str();
563 }
564
565
566 std::map<std::string, std::string> LaTeXFeatures::getPolyglossiaLanguages() const
567 {
568         std::map<std::string, std::string> languages;
569
570         LanguageList::const_iterator const begin = UsedLanguages_.begin();
571         for (LanguageList::const_iterator cit = begin;
572              cit != UsedLanguages_.end();
573              ++cit) {
574                 languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts();
575         }
576         return languages;
577 }
578
579
580 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
581 {
582         // This does only find encodings of languages supported by babel, but
583         // that does not matter since we don't have a language with an
584         // encoding supported by inputenc but without babel support.
585         set<string> encodings;
586         LanguageList::const_iterator it  = UsedLanguages_.begin();
587         LanguageList::const_iterator end = UsedLanguages_.end();
588         for (; it != end; ++it)
589                 if ((*it)->encoding()->latexName() != doc_encoding &&
590                     ((*it)->encoding()->package() == Encoding::inputenc
591                      || (*it)->encoding()->package() == Encoding::japanese))
592                         encodings.insert((*it)->encoding()->latexName());
593         return encodings;
594 }
595
596 namespace {
597
598 char const * simplefeatures[] = {
599 // note that the package order here will be the same in the LaTeX-output
600         "array",
601         "verbatim",
602         "longtable",
603         "rotating",
604         "latexsym",
605         "pifont",
606         // subfig is handled in BufferParams.cpp
607         "varioref",
608         "prettyref",
609         "refstyle",
610         /*For a successful cooperation of the `wrapfig' package with the
611           `float' package you should load the `wrapfig' package *after*
612           the `float' package. See the caption package documentation
613           for explanation.*/
614         "float",
615         "rotfloat",
616         "wrapfig",
617         "booktabs",
618         "dvipost",
619         "fancybox",
620         "calc",
621         "units",
622         "tipa",
623         "tipx",
624         "framed",
625         "soul",
626         "textcomp",
627         "pmboxdraw",
628         "bbding",
629         "ifsym",
630         "marvosym",
631         "txfonts",
632         "pxfonts",
633         "mathdesign",
634         "mathrsfs",
635         "mathabx",
636         "mathtools",
637         "cancel",
638         "ascii",
639         "url",
640         "covington",
641         "csquotes",
642         "enumitem",
643         "endnotes",
644         "hhline",
645         "ifthen",
646         // listings is handled in BufferParams.cpp
647         "bm",
648         "pdfpages",
649         "amscd",
650         "slashed",
651         "multirow",
652         "tfrupee"
653 };
654
655 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
656
657 }
658
659
660 string const LaTeXFeatures::getColorOptions() const
661 {
662         ostringstream colors;
663
664         // Handling the color packages separately is needed to be able to load them
665         // before babel when hyperref is loaded with the colorlinks option
666         // for more info see Bufferparams.cpp
667
668         // [x]color.sty
669         if (mustProvide("color") || mustProvide("xcolor")) {
670                 string const package =
671                         (mustProvide("xcolor") ? "xcolor" : "color");
672                 if (params_.graphics_driver == "default"
673                         || params_.graphics_driver == "none")
674                         colors << "\\usepackage{" << package << "}\n";
675                 else
676                         colors << "\\usepackage["
677                                  << params_.graphics_driver
678                                  << "]{" << package << "}\n";
679         }
680
681         // pdfcolmk must be loaded after color
682         if (mustProvide("pdfcolmk"))
683                 colors << "\\usepackage{pdfcolmk}\n";
684
685         // the following 3 color commands must be set after color
686         // is loaded and before pdfpages, therefore add the command
687         // here define the set color
688         if (mustProvide("pagecolor")) {
689                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
690                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
691                 // set the page color
692                 colors << "\\pagecolor{page_backgroundcolor}\n";
693         }
694
695         if (mustProvide("fontcolor")) {
696                 colors << "\\definecolor{document_fontcolor}{rgb}{";
697                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
698                 // set the color
699                 colors << "\\color{document_fontcolor}\n";
700         }
701
702         if (mustProvide("lyxgreyedout")) {
703                 colors << "\\definecolor{note_fontcolor}{rgb}{";
704                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
705                 // the color will be set together with the definition of
706                 // the lyxgreyedout environment (see lyxgreyedout_def)
707         }
708
709         // color for shaded boxes
710         if (isRequired("framed") && mustProvide("color")) {
711                 colors << "\\definecolor{shadecolor}{rgb}{";
712                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
713                 // this color is automatically used by the LaTeX-package "framed"
714         }
715
716         return colors.str();
717 }
718
719
720 string const LaTeXFeatures::getPackages() const
721 {
722         ostringstream packages;
723         DocumentClass const & tclass = params_.documentClass();
724
725         // FIXME: currently, we can only load packages and macros known
726         // to LyX.
727         // However, with the Require tag of layouts/custom insets,
728         // also unknown packages can be requested. They are silently
729         // swallowed now. We should change this eventually.
730
731         //
732         //  These are all the 'simple' includes.  i.e
733         //  packages which we just \usepackage{package}
734         //
735         for (int i = 0; i < nb_simplefeatures; ++i) {
736                 if (mustProvide(simplefeatures[i]))
737                         packages << "\\usepackage{"
738                                  << simplefeatures[i] << "}\n";
739         }
740
741         //
742         // The rest of these packages are somewhat more complicated
743         // than those above.
744         //
745
746         // if fontspec is used, AMS packages have to be loaded before
747         // fontspec (in BufferParams)
748         string const amsPackages = loadAMSPackages();
749         if (!params_.useNonTeXFonts && !amsPackages.empty())
750                 packages << amsPackages;
751
752         // fixltx2e must be loaded after amsthm, since amsthm produces an error with
753         // the redefined \[ command (bug 7233). Load it as early as possible, since
754         // other packages might profit from it.
755         if (mustProvide("fixltx2e"))
756                 packages << "\\usepackage{fixltx2e}\n";
757
758         // wasysym is a simple feature, but it must be after amsmath if both
759         // are used
760         // wasysym redefines some integrals (e.g. iint) from amsmath. That
761         // leads to inconsistent integrals. We only load this package if
762         // the document does not contain integrals (then isRequired("esint")
763         // is false) or if esint is used, since esint redefines all relevant
764         // integral symbols from wasysym and amsmath.
765         // See http://www.lyx.org/trac/ticket/1942
766         if (mustProvide("wasysym") &&
767             params_.use_package("wasysym") != BufferParams::package_off &&
768             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
769                 packages << "\\usepackage{wasysym}\n";
770
771         // accents must be loaded after amsmath
772         if (mustProvide("accents") &&
773             params_.use_package("accents") != BufferParams::package_off)
774                 packages << "\\usepackage{accents}\n";
775
776         // mathdots must be loaded after amsmath
777         if (mustProvide("mathdots") &&
778                 params_.use_package("mathdots") != BufferParams::package_off)
779                 packages << "\\usepackage{mathdots}\n";
780
781         // yhmath must be loaded after amsmath
782         if (mustProvide("yhmath") &&
783             params_.use_package("yhmath") != BufferParams::package_off)
784                 packages << "\\usepackage{yhmath}\n";
785
786         if (mustProvide("undertilde") &&
787                 params_.use_package("undertilde") != BufferParams::package_off)
788                 packages << "\\usepackage{undertilde}\n";
789
790         // [x]color and pdfcolmk are handled in getColorOptions() above
791
792         // makeidx.sty
793         if (isRequired("makeidx") || isRequired("splitidx")) {
794                 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
795                         packages << "\\usepackage{makeidx}\n";
796                 if (!tclass.provides("splitidx") && isRequired("splitidx"))
797                         packages << "\\usepackage{splitidx}\n";
798                 packages << "\\makeindex\n";
799         }
800
801         // graphicx.sty
802         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
803                 if (params_.graphics_driver == "default")
804                         packages << "\\usepackage{graphicx}\n";
805                 else
806                         packages << "\\usepackage["
807                                  << params_.graphics_driver
808                                  << "]{graphicx}\n";
809         }
810
811         // lyxskak.sty --- newer chess support based on skak.sty
812         if (mustProvide("chess"))
813                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
814
815         // setspace.sty
816         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
817                 packages << "\\usepackage{setspace}\n";
818
819         // esint must be after amsmath and wasysym, since it will redeclare
820         // inconsistent integral symbols
821         if (mustProvide("esint") &&
822             params_.use_package("esint") != BufferParams::package_off)
823                 packages << "\\usepackage{esint}\n";
824
825         // natbib.sty
826         // Some classes load natbib themselves, but still allow (or even require)
827         // plain numeric citations (ReVTeX is such a case, see bug 5182).
828         // This special case is indicated by the "natbib-internal" key.
829         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
830                 packages << "\\usepackage[";
831                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
832                         packages << "numbers";
833                 else
834                         packages << "authoryear";
835                 packages << "]{natbib}\n";
836         }
837
838         // jurabib -- we need version 0.6 at least.
839         if (mustProvide("jurabib"))
840                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
841
842         // xargs -- we need version 1.09 at least
843         if (mustProvide("xargs"))
844                 packages << "\\usepackage{xargs}[2008/03/08]\n";
845
846         if (mustProvide("xy"))
847                 packages << "\\usepackage[all]{xy}\n";
848
849         if (mustProvide("feyn"))
850                 packages << "\\usepackage{feyn}\n"; //Diagram
851
852         if (mustProvide("ulem"))
853                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
854                             "\\usepackage{ulem}\n";
855
856         if (mustProvide("mhchem") &&
857             params_.use_package("mhchem") != BufferParams::package_off)
858                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
859                             "\\usepackage{mhchem}\n";
860
861         if (mustProvide("nomencl")) {
862                 // Make it work with the new and old version of the package,
863                 // but don't use the compatibility option since it is
864                 // incompatible to other packages.
865                 packages << "\\usepackage{nomencl}\n"
866                             "% the following is useful when we have the old nomencl.sty package\n"
867                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
868                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
869                             "\\makenomenclature\n";
870         }
871
872         // fixltx2e provides subscript
873         if (mustProvide("subscript") && !isRequired("fixltx2e"))
874                 packages << "\\usepackage{subscript}\n";
875
876         return packages.str();
877 }
878
879
880 string LaTeXFeatures::getPreambleSnippets() const
881 {
882         ostringstream snip;
883         SnippetList::const_iterator pit  = preamble_snippets_.begin();
884         SnippetList::const_iterator pend = preamble_snippets_.end();
885         for (; pit != pend; ++pit)
886                 snip << *pit << '\n';
887         return snip.str();
888 }
889
890
891 std::string LaTeXFeatures::getCSSSnippets() const
892 {
893         ostringstream snip;
894         SnippetList::const_iterator pit  = css_snippets_.begin();
895         SnippetList::const_iterator pend = css_snippets_.end();
896         for (; pit != pend; ++pit)
897                 snip << *pit << '\n';
898         return snip.str();
899 }
900
901
902 docstring const LaTeXFeatures::getMacros() const
903 {
904         odocstringstream macros;
905
906         if (!preamble_snippets_.empty()) {
907                 macros << '\n';
908                 macros << from_utf8(getPreambleSnippets());
909         }
910
911         if (mustProvide("papersize")) {
912                 if (runparams_.flavor == OutputParams::LATEX)
913                         macros << papersizedvi_def << '\n';
914                 else
915                         macros << papersizepdf_def << '\n';
916         }
917
918         if (mustProvide("LyX")) {
919                 if (isRequired("hyperref"))
920                         macros << lyx_hyperref_def << '\n';
921                 else
922                         macros << lyx_def << '\n';
923         }
924
925         if (mustProvide("noun"))
926                 macros << noun_def << '\n';
927
928         if (mustProvide("lyxarrow"))
929                 macros << lyxarrow_def << '\n';
930
931         if (!usePolyglossia() && mustProvide("textgreek")) {
932                 // Avoid a LaTeX error if times fonts are used and the grtimes
933                 // package is installed but actual fonts are not (bug 6469).
934                 if (params_.fonts_roman == "times")
935                         macros << subst(textgreek_def,
936                                         from_ascii("\\greektext #1"),
937                                         from_ascii("%\n  \\IfFileExists"
938                                                    "{grtm10.tfm}{}{\\fontfamily"
939                                                    "{cmr}}\\greektext #1"))
940                                << '\n';
941                 else
942                         macros << textgreek_def << '\n';
943         }
944
945         if (!usePolyglossia() && mustProvide("textcyr"))
946                 macros << textcyr_def << '\n';
947
948         if (mustProvide("lyxmathsym"))
949                 macros << lyxmathsym_def << '\n';
950
951         if (mustProvide("cedilla"))
952                 macros << cedilla_def << '\n';
953
954         if (mustProvide("subring"))
955                 macros << subring_def << '\n';
956
957         if (mustProvide("subdot"))
958                 macros << subdot_def << '\n';
959
960         if (mustProvide("subhat"))
961                 macros << subhat_def << '\n';
962
963         if (mustProvide("subtilde"))
964                 macros << subtilde_def << '\n';
965
966         if (mustProvide("dacute"))
967                 macros << dacute_def << '\n';
968
969         if (mustProvide("tipasymb"))
970                 macros << tipasymb_def << '\n';
971
972         if (mustProvide("dgrave"))
973                 macros << dgrave_def << '\n';
974
975         if (mustProvide("rcap"))
976                 macros << rcap_def << '\n';
977
978         if (mustProvide("ogonek"))
979                 macros << ogonek_def << '\n';
980
981         // quotes.
982         if (mustProvide("quotesinglbase"))
983                 macros << quotesinglbase_def << '\n';
984         if (mustProvide("quotedblbase"))
985                 macros << quotedblbase_def << '\n';
986         if (mustProvide("guilsinglleft"))
987                 macros << guilsinglleft_def << '\n';
988         if (mustProvide("guilsinglright"))
989                 macros << guilsinglright_def << '\n';
990         if (mustProvide("guillemotleft"))
991                 macros << guillemotleft_def << '\n';
992         if (mustProvide("guillemotright"))
993                 macros << guillemotright_def << '\n';
994
995         // Math mode
996         if (mustProvide("binom") && !isRequired("amsmath"))
997                 macros << binom_def << '\n';
998         if (mustProvide("mathcircumflex"))
999                 macros << mathcircumflex_def << '\n';
1000
1001         // other
1002         if (mustProvide("ParagraphLeftIndent"))
1003                 macros << paragraphleftindent_def;
1004         if (mustProvide("NeedLyXFootnoteCode"))
1005                 macros << floatingfootnote_def;
1006
1007         // some problems with tex->html converters
1008         if (mustProvide("NeedTabularnewline"))
1009                 macros << tabularnewline_def;
1010
1011         // greyed-out environment (note inset)
1012         // the color is specified in the routine
1013         // getColorOptions() to avoid LaTeX-package clashes
1014         if (mustProvide("lyxgreyedout"))
1015                 macros << lyxgreyedout_def;
1016
1017         if (mustProvide("lyxdot"))
1018                 macros << lyxdot_def << '\n';
1019
1020         // floats
1021         getFloatDefinitions(macros);
1022
1023         if (mustProvide("refstyle"))
1024                 macros << lyxref_def << '\n';
1025
1026         // change tracking
1027         if (mustProvide("ct-dvipost"))
1028                 macros << changetracking_dvipost_def;
1029
1030         if (mustProvide("ct-xcolor-ulem")) {
1031                 streamsize const prec = macros.precision(2);
1032
1033                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1034                 macros << "\\providecolor{lyxadded}{rgb}{"
1035                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1036
1037                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1038                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1039                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1040
1041                 macros.precision(prec);
1042
1043                 if (isRequired("hyperref"))
1044                         macros << changetracking_xcolor_ulem_hyperref_def;
1045                 else
1046                         macros << changetracking_xcolor_ulem_def;
1047         }
1048
1049         if (mustProvide("ct-none"))
1050                 macros << changetracking_none_def;
1051
1052         return macros.str();
1053 }
1054
1055
1056 string const LaTeXFeatures::getBabelPresettings() const
1057 {
1058         ostringstream tmp;
1059
1060         LanguageList::const_iterator it  = UsedLanguages_.begin();
1061         LanguageList::const_iterator end = UsedLanguages_.end();
1062         for (; it != end; ++it)
1063                 if (!(*it)->babel_presettings().empty())
1064                         tmp << (*it)->babel_presettings() << '\n';
1065         if (!params_.language->babel_presettings().empty())
1066                 tmp << params_.language->babel_presettings() << '\n';
1067
1068         if (!contains(tmp.str(), '@'))
1069                 return tmp.str();
1070
1071         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1072 }
1073
1074
1075 string const LaTeXFeatures::getBabelPostsettings() const
1076 {
1077         ostringstream tmp;
1078
1079         LanguageList::const_iterator it  = UsedLanguages_.begin();
1080         LanguageList::const_iterator end = UsedLanguages_.end();
1081         for (; it != end; ++it)
1082                 if (!(*it)->babel_postsettings().empty())
1083                         tmp << (*it)->babel_postsettings() << '\n';
1084         if (!params_.language->babel_postsettings().empty())
1085                 tmp << params_.language->babel_postsettings() << '\n';
1086
1087         if (!contains(tmp.str(), '@'))
1088                 return tmp.str();
1089
1090         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1091 }
1092
1093
1094 bool LaTeXFeatures::needBabelLangOptions() const
1095 {
1096         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1097                 return true;
1098
1099         LanguageList::const_iterator it  = UsedLanguages_.begin();
1100         LanguageList::const_iterator end = UsedLanguages_.end();
1101         for (; it != end; ++it)
1102                 if ((*it)->asBabelOptions())
1103                         return true;
1104
1105         return false;
1106 }
1107
1108
1109 string const LaTeXFeatures::loadAMSPackages() const
1110 {
1111         ostringstream tmp;
1112         if (mustProvide("amsthm"))
1113                 tmp << "\\usepackage{amsthm}\n";
1114
1115         if (mustProvide("amsmath")
1116             && params_.use_package("amsmath") != BufferParams::package_off) {
1117                 tmp << "\\usepackage{amsmath}\n";
1118         } else {
1119                 // amsbsy and amstext are already provided by amsmath
1120                 if (mustProvide("amsbsy"))
1121                         tmp << "\\usepackage{amsbsy}\n";
1122                 if (mustProvide("amstext"))
1123                         tmp << "\\usepackage{amstext}\n";
1124         }
1125
1126         if (mustProvide("amssymb")
1127             && params_.use_package("amssymb") != BufferParams::package_off)
1128                 tmp << "\\usepackage{amssymb}\n";
1129
1130         return tmp.str();
1131 }
1132
1133
1134 docstring const LaTeXFeatures::getTClassPreamble() const
1135 {
1136         // the text class specific preamble
1137         DocumentClass const & tclass = params_.documentClass();
1138         odocstringstream tcpreamble;
1139
1140         tcpreamble << tclass.preamble();
1141
1142         list<docstring>::const_iterator cit = usedLayouts_.begin();
1143         list<docstring>::const_iterator end = usedLayouts_.end();
1144         for (; cit != end; ++cit)
1145                 tcpreamble << tclass[*cit].preamble();
1146
1147         cit = usedInsetLayouts_.begin();
1148         end = usedInsetLayouts_.end();
1149         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1150         for (; cit != end; ++cit) {
1151                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1152                 if (it == ils.end())
1153                         continue;
1154                 tcpreamble << it->second.preamble();
1155         }
1156
1157         return tcpreamble.str();
1158 }
1159
1160
1161 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1162 {
1163         DocumentClass const & tclass = params_.documentClass();
1164         odocstringstream tcpreamble;
1165
1166         tcpreamble << tclass.htmlpreamble();
1167
1168         list<docstring>::const_iterator cit = usedLayouts_.begin();
1169         list<docstring>::const_iterator end = usedLayouts_.end();
1170         for (; cit != end; ++cit)
1171                 tcpreamble << tclass[*cit].htmlpreamble();
1172
1173         cit = usedInsetLayouts_.begin();
1174         end = usedInsetLayouts_.end();
1175         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1176         for (; cit != end; ++cit) {
1177                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1178                 if (it == ils.end())
1179                         continue;
1180                 tcpreamble << it->second.htmlpreamble();
1181         }
1182
1183         return tcpreamble.str();
1184 }
1185
1186
1187 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1188 {
1189         DocumentClass const & tclass = params_.documentClass();
1190         odocstringstream tcpreamble;
1191
1192         tcpreamble << tclass.htmlstyles();
1193
1194         list<docstring>::const_iterator cit = usedLayouts_.begin();
1195         list<docstring>::const_iterator end = usedLayouts_.end();
1196         for (; cit != end; ++cit)
1197                 tcpreamble << tclass[*cit].htmlstyle();
1198
1199         cit = usedInsetLayouts_.begin();
1200         end = usedInsetLayouts_.end();
1201         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1202         for (; cit != end; ++cit) {
1203                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1204                 if (it == ils.end())
1205                         continue;
1206                 tcpreamble << it->second.htmlstyle();
1207         }
1208
1209         return tcpreamble.str();
1210 }
1211
1212
1213 namespace {
1214 docstring const getFloatI18nPreamble(docstring const & type,
1215                         docstring const & name, Language const * lang,
1216                         Encoding const & enc, bool const polyglossia)
1217 {
1218         // Check whether name can be encoded in the buffer encoding
1219         bool encodable = true;
1220         for (size_t i = 0; i < name.size(); ++i) {
1221                 if (!enc.encodable(name[i])) {
1222                         encodable = false;
1223                         break;
1224                 }
1225         }
1226
1227         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1228                                                : from_ascii(lang->babel());
1229         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1230         docstring const texenc = from_ascii(lang->encoding()->latexName());
1231         docstring const bufenc = from_ascii(enc.iconvName());
1232         docstring const s1 = docstring(1, 0xF0000);
1233         docstring const s2 = docstring(1, 0xF0001);
1234         docstring const translated = encodable ? name
1235                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1236                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1237
1238         odocstringstream os;
1239         os << "\\addto\\captions" << language
1240            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1241         return os.str();
1242 }
1243
1244
1245 docstring const i18npreamble(docstring const & templ, Language const * lang,
1246                 Encoding const & enc, bool const polyglossia)
1247 {
1248         if (templ.empty())
1249                 return templ;
1250
1251         string preamble = polyglossia ?
1252                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1253                 subst(to_utf8(templ), "$$lang", lang->babel());
1254
1255         string const langenc = lang->encoding()->iconvName();
1256         string const texenc = lang->encoding()->latexName();
1257         string const bufenc = enc.iconvName();
1258         // First and second character of plane 15 (Private Use Area)
1259         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1260         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1261         // FIXME UNICODE
1262         // lyx::regex is not unicode-safe.
1263         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1264         static regex const reg("_\\(([^\\)]+)\\)");
1265         smatch sub;
1266         while (regex_search(preamble, sub, reg)) {
1267                 string const key = sub.str(1);
1268                 docstring const name = lang->translateLayout(key);
1269                 // Check whether name can be encoded in the buffer encoding
1270                 bool encodable = true;
1271                 for (size_t i = 0; i < name.size(); ++i) {
1272                         if (!enc.encodable(name[i])) {
1273                                 encodable = false;
1274                                 break;
1275                         }
1276                 }
1277                 string const translated = encodable ? to_utf8(name)
1278                         : "\\inputencoding{" + texenc + "}"
1279                         + s1 + langenc + s2 + to_utf8(name)
1280                         + s1 + bufenc + s2;
1281                 preamble = subst(preamble, sub.str(), translated);
1282         }
1283         return from_utf8(preamble);
1284 }
1285
1286 }
1287
1288
1289 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1290 {
1291         DocumentClass const & tclass = params_.documentClass();
1292         // collect preamble snippets in a set to prevent multiple identical
1293         // commands (would happen if e.g. both theorem and theorem* are used)
1294         set<docstring> snippets;
1295         typedef LanguageList::const_iterator lang_it;
1296         lang_it const lbeg = UsedLanguages_.begin();
1297         lang_it const lend =  UsedLanguages_.end();
1298         list<docstring>::const_iterator cit = usedLayouts_.begin();
1299         list<docstring>::const_iterator end = usedLayouts_.end();
1300         for (; cit != end; ++cit) {
1301                 // language dependent commands (once per document)
1302                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1303                                                 buffer().language(),
1304                                                 buffer().params().encoding(),
1305                                                 use_polyglossia));
1306                 // commands for language changing (for multilanguage documents)
1307                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1308                         snippets.insert(i18npreamble(
1309                                                 tclass[*cit].babelpreamble(),
1310                                                 buffer().language(),
1311                                                 buffer().params().encoding(),
1312                                                 use_polyglossia));
1313                         for (lang_it lit = lbeg; lit != lend; ++lit)
1314                                 snippets.insert(i18npreamble(
1315                                                 tclass[*cit].babelpreamble(),
1316                                                 *lit,
1317                                                 buffer().params().encoding(),
1318                                                 use_polyglossia));
1319                 }
1320         }
1321         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1322                 FloatList const & floats = params_.documentClass().floats();
1323                 UsedFloats::const_iterator fit = usedFloats_.begin();
1324                 UsedFloats::const_iterator fend = usedFloats_.end();
1325                 for (; fit != fend; ++fit) {
1326                         Floating const & fl = floats.getType(fit->first);
1327                         // we assume builtin floats are translated
1328                         if (fl.isPredefined())
1329                                 continue;
1330                         docstring const type = from_ascii(fl.floattype());
1331                         docstring const flname = from_utf8(fl.name());
1332                         docstring name = buffer().language()->translateLayout(fl.name());
1333                         // only request translation if we have a real translation
1334                         // (that differs from the source)
1335                         if (flname != name)
1336                                 snippets.insert(getFloatI18nPreamble(
1337                                                 type, name, buffer().language(),
1338                                                 buffer().params().encoding(),
1339                                                 use_polyglossia));
1340                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1341                                 string const code = (*lit)->code();
1342                                 name = (*lit)->translateLayout(fl.name());
1343                                 // we assume we have a suitable translation if
1344                                 // either the language is English (we need to
1345                                 // translate into English if English is a secondary
1346                                 // language) or if translateIfPossible returns
1347                                 // something different to the English source.
1348                                 bool const have_translation =
1349                                         (flname != name || contains(code, "en"));
1350                                 if (have_translation)
1351                                         snippets.insert(getFloatI18nPreamble(
1352                                                 type, name, *lit,
1353                                                 buffer().params().encoding(),
1354                                                 use_polyglossia));
1355                         }
1356                 }
1357         }
1358
1359         cit = usedInsetLayouts_.begin();
1360         end = usedInsetLayouts_.end();
1361         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1362         for (; cit != end; ++cit) {
1363                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1364                 if (it == ils.end())
1365                         continue;
1366                 // language dependent commands (once per document)
1367                 snippets.insert(i18npreamble(it->second.langpreamble(),
1368                                                 buffer().language(),
1369                                                 buffer().params().encoding(),
1370                                                 use_polyglossia));
1371                 // commands for language changing (for multilanguage documents)
1372                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1373                         snippets.insert(i18npreamble(
1374                                                 it->second.babelpreamble(),
1375                                                 buffer().language(),
1376                                                 buffer().params().encoding(),
1377                                                 use_polyglossia));
1378                         for (lang_it lit = lbeg; lit != lend; ++lit)
1379                                 snippets.insert(i18npreamble(
1380                                                 it->second.babelpreamble(),
1381                                                 *lit,
1382                                                 buffer().params().encoding(),
1383                                                 use_polyglossia));
1384                 }
1385         }
1386
1387         odocstringstream tcpreamble;
1388         set<docstring>::const_iterator const send = snippets.end();
1389         set<docstring>::const_iterator it = snippets.begin();
1390         for (; it != send; ++it)
1391                 tcpreamble << *it;
1392         return tcpreamble.str();
1393 }
1394
1395
1396 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1397 {
1398         // Definition of entities used in the document that are LyX related.
1399         odocstringstream entities;
1400
1401         if (mustProvide("lyxarrow")) {
1402                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1403         }
1404
1405         return entities.str();
1406 }
1407
1408
1409 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1410 {
1411         odocstringstream sgmlpreamble;
1412         // FIXME UNICODE
1413         docstring const basename(from_utf8(onlyPath(fname)));
1414
1415         FileMap::const_iterator end = IncludedFiles_.end();
1416         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1417              fi != end; ++fi)
1418                 // FIXME UNICODE
1419                 sgmlpreamble << "\n<!ENTITY " << fi->first
1420                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1421                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1422
1423         return sgmlpreamble.str();
1424 }
1425
1426
1427 void LaTeXFeatures::showStruct() const
1428 {
1429         lyxerr << "LyX needs the following commands when LaTeXing:"
1430                << "\n***** Packages:" << getPackages()
1431                << "\n***** Macros:" << to_utf8(getMacros())
1432                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1433                << "\n***** done." << endl;
1434 }
1435
1436
1437 Buffer const & LaTeXFeatures::buffer() const
1438 {
1439         return *buffer_;
1440 }
1441
1442
1443 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1444 {
1445         buffer_ = &buffer;
1446 }
1447
1448
1449 BufferParams const & LaTeXFeatures::bufferParams() const
1450 {
1451         return params_;
1452 }
1453
1454
1455 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1456 {
1457         FloatList const & floats = params_.documentClass().floats();
1458
1459         // Here we will output the code to create the needed float styles.
1460         // We will try to do this as minimal as possible.
1461         // \floatstyle{ruled}
1462         // \newfloat{algorithm}{htbp}{loa}
1463         // \providecommand{\algorithmname}{Algorithm}
1464         // \floatname{algorithm}{\protect\algorithmname}
1465         UsedFloats::const_iterator cit = usedFloats_.begin();
1466         UsedFloats::const_iterator end = usedFloats_.end();
1467         for (; cit != end; ++cit) {
1468                 Floating const & fl = floats.getType(cit->first);
1469
1470                 // For builtin floats we do nothing.
1471                 if (fl.isPredefined())
1472                         continue;
1473
1474                 // We have to special case "table" and "figure"
1475                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1476                         // Output code to modify "table" or "figure"
1477                         // but only if builtin == false
1478                         // and that have to be true at this point in the
1479                         // function.
1480                         docstring const type = from_ascii(fl.floattype());
1481                         docstring const placement = from_ascii(fl.placement());
1482                         docstring const style = from_ascii(fl.style());
1483                         if (!style.empty()) {
1484                                 os << "\\floatstyle{" << style << "}\n"
1485                                    << "\\restylefloat{" << type << "}\n";
1486                         }
1487                         if (!placement.empty()) {
1488                                 os << "\\floatplacement{" << type << "}{"
1489                                    << placement << "}\n";
1490                         }
1491                 } else {
1492                         // The other non builtin floats.
1493
1494                         docstring const type = from_ascii(fl.floattype());
1495                         docstring const placement = from_ascii(fl.placement());
1496                         docstring const ext = from_ascii(fl.ext());
1497                         docstring const within = from_ascii(fl.within());
1498                         docstring const style = from_ascii(fl.style());
1499                         docstring const name =
1500                                 buffer().language()->translateLayout(fl.name());
1501                         os << "\\floatstyle{" << style << "}\n"
1502                            << "\\newfloat{" << type << "}{" << placement
1503                            << "}{" << ext << '}';
1504                         if (!within.empty())
1505                                 os << '[' << within << ']';
1506                         os << '\n'
1507                            << "\\providecommand{\\" << type << "name}{"
1508                            << name << "}\n"
1509                            << "\\floatname{" << type << "}{\\protect\\"
1510                            << type << "name}\n";
1511
1512                         // What missing here is to code to minimalize the code
1513                         // output so that the same floatstyle will not be
1514                         // used several times, when the same style is still in
1515                         // effect. (Lgb)
1516                 }
1517                 if (cit->second)
1518                         os << "\n\\newsubfloat{" << from_ascii(fl.floattype()) << "}\n";
1519         }
1520 }
1521
1522
1523 void LaTeXFeatures::resolveAlternatives()
1524 {
1525         for (Features::iterator it = features_.begin(); it != features_.end();) {
1526                 if (contains(*it, '|')) {
1527                         vector<string> const alternatives = getVectorFromString(*it, "|");
1528                         vector<string>::const_iterator const end = alternatives.end();
1529                         vector<string>::const_iterator ita = alternatives.begin();
1530                         for (; ita != end; ++ita) {
1531                                 if (isRequired(*ita))
1532                                         break;
1533                         }
1534                         if (ita == end)
1535                                 require(alternatives.front());
1536                         features_.erase(it);
1537                         it = features_.begin();
1538                 } else
1539                         ++it;
1540         }
1541 }
1542
1543
1544 } // namespace lyx