]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
Fixes to the language package call
[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 bool LaTeXFeatures::useBabel() const
294 {
295         if (usePolyglossia()
296             || bufferParams().lang_package == "none"
297             || (bufferParams().lang_package == "default"
298                 && lyxrc.language_package_selection == LyXRC::LP_NONE))
299                 return false;
300
301         return (bufferParams().language->lang() != lyxrc.default_language
302                 && !bufferParams().language->babel().empty())
303                 || this->hasLanguages();
304 }
305
306
307 bool LaTeXFeatures::usePolyglossia() const
308 {
309         if (bufferParams().lang_package == "default")
310                 return (lyxrc.language_package_selection == LyXRC::LP_AUTO)
311                         && isRequired("polyglossia")
312                         && isAvailable("polyglossia")
313                         && !params_.documentClass().provides("babel")
314                         && this->hasOnlyPolyglossiaLanguages();
315         return (bufferParams().lang_package == "auto")
316                 && isRequired("polyglossia")
317                 && isAvailable("polyglossia")
318                 && !params_.documentClass().provides("babel")
319                 && this->hasOnlyPolyglossiaLanguages();
320 }
321
322
323 void LaTeXFeatures::require(string const & name)
324 {
325         features_.insert(name);
326 }
327
328
329 void LaTeXFeatures::require(set<string> const & names)
330 {
331         features_.insert(names.begin(), names.end());
332 }
333
334
335 void LaTeXFeatures::useLayout(docstring const & layoutname)
336 {
337         // Some code to avoid loops in dependency definition
338         static int level = 0;
339         const int maxlevel = 30;
340         if (level > maxlevel) {
341                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
342                        << "recursion attained by layout "
343                        << to_utf8(layoutname) << endl;
344                 return;
345         }
346
347         DocumentClass const & tclass = params_.documentClass();
348         if (tclass.hasLayout(layoutname)) {
349                 // Is this layout already in usedLayouts?
350                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
351                     != usedLayouts_.end())
352                         return;
353
354                 Layout const & layout = tclass[layoutname];
355                 require(layout.requires());
356
357                 if (!layout.depends_on().empty()) {
358                         ++level;
359                         useLayout(layout.depends_on());
360                         --level;
361                 }
362                 usedLayouts_.push_back(layoutname);
363         } else {
364                 lyxerr << "LaTeXFeatures::useLayout: layout `"
365                        << to_utf8(layoutname) << "' does not exist in this class"
366                        << endl;
367         }
368
369         --level;
370 }
371
372
373 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
374 {
375         docstring const & lname = lay.name();
376         DocumentClass const & tclass = params_.documentClass();
377
378         // this is a default inset layout, nothing useful here
379         if (!tclass.hasInsetLayout(lname))
380                 return;
381         // Is this layout already in usedInsetLayouts?
382         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
383                         != usedInsetLayouts_.end())
384                 return;
385
386         require(lay.requires());
387         usedInsetLayouts_.push_back(lname);
388 }
389
390
391 bool LaTeXFeatures::isRequired(string const & name) const
392 {
393         return features_.find(name) != features_.end();
394 }
395
396
397 bool LaTeXFeatures::mustProvide(string const & name) const
398 {
399         return isRequired(name) && !params_.documentClass().provides(name);
400 }
401
402
403 bool LaTeXFeatures::isAvailable(string const & name)
404 {
405         string::size_type const i = name.find("->");
406         if (i != string::npos) {
407                 string const from = name.substr(0,i);
408                 string const to = name.substr(i+2);
409                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
410                 return theConverters().isReachable(from, to);
411         }
412         return LaTeXPackages::isAvailable(name);
413 }
414
415
416 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
417 {
418         SnippetList::const_iterator begin = preamble_snippets_.begin();
419         SnippetList::const_iterator end   = preamble_snippets_.end();
420         if (find(begin, end, preamble) == end)
421                 preamble_snippets_.push_back(preamble);
422 }
423
424
425 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
426 {
427         SnippetList::const_iterator begin = css_snippets_.begin();
428         SnippetList::const_iterator end   = css_snippets_.end();
429         if (find(begin, end, snippet) == end)
430                 css_snippets_.push_back(snippet);
431 }
432
433
434 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
435 {
436         if (!usedFloats_[name])
437                 usedFloats_[name] = subfloat;
438         if (subfloat)
439                 require("subfig");
440         // We only need float.sty if we use non builtin floats, or if we
441         // use the "H" modifier. This includes modified table and
442         // figure floats. (Lgb)
443         Floating const & fl = params_.documentClass().floats().getType(name);
444         if (!fl.floattype().empty() && fl.usesFloatPkg()) {
445                 require("float");
446         }
447 }
448
449
450 void LaTeXFeatures::useLanguage(Language const * lang)
451 {
452         if (!lang->babel().empty() || !lang->polyglossia().empty())
453                 UsedLanguages_.insert(lang);
454         if (!lang->requires().empty())
455                 require(lang->requires());
456         // CJK languages do not have a babel name.
457         // They use the CJK package
458         if (lang->encoding()->package() == Encoding::CJK)
459                 require("CJK");
460         // japanese package is special
461         if (lang->encoding()->package() == Encoding::japanese)
462                 require("japanese");
463 }
464
465
466 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
467 {
468         IncludedFiles_[key] = name;
469 }
470
471
472 bool LaTeXFeatures::hasLanguages() const
473 {
474         return !UsedLanguages_.empty();
475 }
476
477
478 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
479 {
480         LanguageList::const_iterator const begin = UsedLanguages_.begin();
481         for (LanguageList::const_iterator cit = begin;
482              cit != UsedLanguages_.end();
483              ++cit) {
484                 if ((*cit)->polyglossia().empty())
485                         return false;
486         }
487         return true;
488 }
489
490
491 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
492 {
493         LanguageList::const_iterator const begin = UsedLanguages_.begin();
494         for (LanguageList::const_iterator cit = begin;
495              cit != UsedLanguages_.end();
496              ++cit) {
497                 if ((*cit)->babel().empty() && !(*cit)->polyglossia().empty() && (*cit)->requires().empty())
498                         return true;
499         }
500         return false;
501 }
502
503
504 string LaTeXFeatures::getBabelLanguages() const
505 {
506         ostringstream languages;
507
508         bool first = true;
509         LanguageList::const_iterator const begin = UsedLanguages_.begin();
510         for (LanguageList::const_iterator cit = begin;
511              cit != UsedLanguages_.end();
512              ++cit) {
513                 if ((*cit)->babel().empty())
514                         continue;
515                 if (!first)
516                         languages << ',';
517                 else
518                         first = false;
519                 languages << (*cit)->babel();
520         }
521         return languages.str();
522 }
523
524
525 std::map<std::string, std::string> LaTeXFeatures::getPolyglossiaLanguages() const
526 {
527         std::map<std::string, std::string> languages;
528
529         LanguageList::const_iterator const begin = UsedLanguages_.begin();
530         for (LanguageList::const_iterator cit = begin;
531              cit != UsedLanguages_.end();
532              ++cit) {
533                 languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts();
534         }
535         return languages;
536 }
537
538
539 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
540 {
541         // This does only find encodings of languages supported by babel, but
542         // that does not matter since we don't have a language with an
543         // encoding supported by inputenc but without babel support.
544         set<string> encodings;
545         LanguageList::const_iterator it  = UsedLanguages_.begin();
546         LanguageList::const_iterator end = UsedLanguages_.end();
547         for (; it != end; ++it)
548                 if ((*it)->encoding()->latexName() != doc_encoding &&
549                     ((*it)->encoding()->package() == Encoding::inputenc
550                      || (*it)->encoding()->package() == Encoding::japanese))
551                         encodings.insert((*it)->encoding()->latexName());
552         return encodings;
553 }
554
555 namespace {
556
557 char const * simplefeatures[] = {
558 // note that the package order here will be the same in the LaTeX-output
559         "array",
560         "verbatim",
561         "longtable",
562         "rotating",
563         "latexsym",
564         "pifont",
565         // subfig is handled in BufferParams.cpp
566         "varioref",
567         "prettyref",
568         "refstyle",
569         /*For a successful cooperation of the `wrapfig' package with the
570           `float' package you should load the `wrapfig' package *after*
571           the `float' package. See the caption package documentation
572           for explanation.*/
573         "float",
574         "rotfloat",
575         "wrapfig",
576         "booktabs",
577         "dvipost",
578         "fancybox",
579         "calc",
580         "units",
581         "tipa",
582         "tipx",
583         "framed",
584         "soul",
585         "textcomp",
586         "pmboxdraw",
587         "bbding",
588         "ifsym",
589         "marvosym",
590         "txfonts",
591         "pxfonts",
592         "mathdesign",
593         "mathrsfs",
594         "mathabx",
595         "mathtools",
596         "cancel",
597         "ascii",
598         "url",
599         "covington",
600         "csquotes",
601         "enumitem",
602         "endnotes",
603         "hhline",
604         "ifthen",
605         // listings is handled in BufferParams.cpp
606         "bm",
607         "pdfpages",
608         "amscd",
609         "slashed",
610         "multirow",
611         "tfrupee"
612 };
613
614 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
615
616 }
617
618
619 string const LaTeXFeatures::getColorOptions() const
620 {
621         ostringstream colors;
622
623         // Handling the color packages separately is needed to be able to load them
624         // before babel when hyperref is loaded with the colorlinks option
625         // for more info see Bufferparams.cpp
626
627         // [x]color.sty
628         if (mustProvide("color") || mustProvide("xcolor")) {
629                 string const package =
630                         (mustProvide("xcolor") ? "xcolor" : "color");
631                 if (params_.graphics_driver == "default"
632                         || params_.graphics_driver == "none")
633                         colors << "\\usepackage{" << package << "}\n";
634                 else
635                         colors << "\\usepackage["
636                                  << params_.graphics_driver
637                                  << "]{" << package << "}\n";
638         }
639
640         // pdfcolmk must be loaded after color
641         if (mustProvide("pdfcolmk"))
642                 colors << "\\usepackage{pdfcolmk}\n";
643
644         // the following 3 color commands must be set after color
645         // is loaded and before pdfpages, therefore add the command
646         // here define the set color
647         if (mustProvide("pagecolor")) {
648                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
649                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
650                 // set the page color
651                 colors << "\\pagecolor{page_backgroundcolor}\n";
652         }
653
654         if (mustProvide("fontcolor")) {
655                 colors << "\\definecolor{document_fontcolor}{rgb}{";
656                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
657                 // set the color
658                 colors << "\\color{document_fontcolor}\n";
659         }
660
661         if (mustProvide("lyxgreyedout")) {
662                 colors << "\\definecolor{note_fontcolor}{rgb}{";
663                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
664                 // the color will be set together with the definition of
665                 // the lyxgreyedout environment (see lyxgreyedout_def)
666         }
667
668         // color for shaded boxes
669         if (isRequired("framed") && mustProvide("color")) {
670                 colors << "\\definecolor{shadecolor}{rgb}{";
671                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
672                 // this color is automatically used by the LaTeX-package "framed"
673         }
674
675         return colors.str();
676 }
677
678
679 string const LaTeXFeatures::getPackages() const
680 {
681         ostringstream packages;
682         DocumentClass const & tclass = params_.documentClass();
683
684         // FIXME: currently, we can only load packages and macros known
685         // to LyX.
686         // However, with the Require tag of layouts/custom insets,
687         // also unknown packages can be requested. They are silently
688         // swallowed now. We should change this eventually.
689
690         //
691         //  These are all the 'simple' includes.  i.e
692         //  packages which we just \usepackage{package}
693         //
694         for (int i = 0; i < nb_simplefeatures; ++i) {
695                 if (mustProvide(simplefeatures[i]))
696                         packages << "\\usepackage{"
697                                  << simplefeatures[i] << "}\n";
698         }
699
700         //
701         // The rest of these packages are somewhat more complicated
702         // than those above.
703         //
704
705         // if fontspec is used, AMS packages have to be loaded before
706         // fontspec (in BufferParams)
707         string const amsPackages = loadAMSPackages();
708         if (!params_.useNonTeXFonts && !amsPackages.empty())
709                 packages << amsPackages;
710
711         // fixltx2e must be loaded after amsthm, since amsthm produces an error with
712         // the redefined \[ command (bug 7233). Load it as early as possible, since
713         // other packages might profit from it.
714         if (mustProvide("fixltx2e"))
715                 packages << "\\usepackage{fixltx2e}\n";
716
717         // wasysym is a simple feature, but it must be after amsmath if both
718         // are used
719         // wasysym redefines some integrals (e.g. iint) from amsmath. That
720         // leads to inconsistent integrals. We only load this package if
721         // the document does not contain integrals (then isRequired("esint")
722         // is false) or if esint is used, since esint redefines all relevant
723         // integral symbols from wasysym and amsmath.
724         // See http://www.lyx.org/trac/ticket/1942
725         if (mustProvide("wasysym") &&
726             params_.use_package("wasysym") != BufferParams::package_off &&
727             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
728                 packages << "\\usepackage{wasysym}\n";
729
730         // accents must be loaded after amsmath
731         if (mustProvide("accents") &&
732             params_.use_package("accents") != BufferParams::package_off)
733                 packages << "\\usepackage{accents}\n";
734
735         // mathdots must be loaded after amsmath
736         if (mustProvide("mathdots") &&
737                 params_.use_package("mathdots") != BufferParams::package_off)
738                 packages << "\\usepackage{mathdots}\n";
739
740         // yhmath must be loaded after amsmath
741         if (mustProvide("yhmath") &&
742             params_.use_package("yhmath") != BufferParams::package_off)
743                 packages << "\\usepackage{yhmath}\n";
744
745         if (mustProvide("undertilde") &&
746                 params_.use_package("undertilde") != BufferParams::package_off)
747                 packages << "\\usepackage{undertilde}\n";
748
749         // [x]color and pdfcolmk are handled in getColorOptions() above
750
751         // makeidx.sty
752         if (isRequired("makeidx") || isRequired("splitidx")) {
753                 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
754                         packages << "\\usepackage{makeidx}\n";
755                 if (!tclass.provides("splitidx") && isRequired("splitidx"))
756                         packages << "\\usepackage{splitidx}\n";
757                 packages << "\\makeindex\n";
758         }
759
760         // graphicx.sty
761         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
762                 if (params_.graphics_driver == "default")
763                         packages << "\\usepackage{graphicx}\n";
764                 else
765                         packages << "\\usepackage["
766                                  << params_.graphics_driver
767                                  << "]{graphicx}\n";
768         }
769
770         // lyxskak.sty --- newer chess support based on skak.sty
771         if (mustProvide("chess"))
772                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
773
774         // setspace.sty
775         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
776                 packages << "\\usepackage{setspace}\n";
777
778         // esint must be after amsmath and wasysym, since it will redeclare
779         // inconsistent integral symbols
780         if (mustProvide("esint") &&
781             params_.use_package("esint") != BufferParams::package_off)
782                 packages << "\\usepackage{esint}\n";
783
784         // natbib.sty
785         // Some classes load natbib themselves, but still allow (or even require)
786         // plain numeric citations (ReVTeX is such a case, see bug 5182).
787         // This special case is indicated by the "natbib-internal" key.
788         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
789                 packages << "\\usepackage[";
790                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
791                         packages << "numbers";
792                 else
793                         packages << "authoryear";
794                 packages << "]{natbib}\n";
795         }
796
797         // jurabib -- we need version 0.6 at least.
798         if (mustProvide("jurabib"))
799                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
800
801         // xargs -- we need version 1.09 at least
802         if (mustProvide("xargs"))
803                 packages << "\\usepackage{xargs}[2008/03/08]\n";
804
805         if (mustProvide("xy"))
806                 packages << "\\usepackage[all]{xy}\n";
807
808         if (mustProvide("feyn"))
809                 packages << "\\usepackage{feyn}\n"; //Diagram
810
811         if (mustProvide("ulem"))
812                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
813                             "\\usepackage{ulem}\n";
814
815         if (mustProvide("mhchem") &&
816             params_.use_package("mhchem") != BufferParams::package_off)
817                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
818                             "\\usepackage{mhchem}\n";
819
820         if (mustProvide("nomencl")) {
821                 // Make it work with the new and old version of the package,
822                 // but don't use the compatibility option since it is
823                 // incompatible to other packages.
824                 packages << "\\usepackage{nomencl}\n"
825                             "% the following is useful when we have the old nomencl.sty package\n"
826                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
827                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
828                             "\\makenomenclature\n";
829         }
830
831         // fixltx2e provides subscript
832         if (mustProvide("subscript") && !isRequired("fixltx2e"))
833                 packages << "\\usepackage{subscript}\n";
834
835         return packages.str();
836 }
837
838
839 string LaTeXFeatures::getPreambleSnippets() const
840 {
841         ostringstream snip;
842         SnippetList::const_iterator pit  = preamble_snippets_.begin();
843         SnippetList::const_iterator pend = preamble_snippets_.end();
844         for (; pit != pend; ++pit)
845                 snip << *pit << '\n';
846         return snip.str();
847 }
848
849
850 std::string LaTeXFeatures::getCSSSnippets() const
851 {
852         ostringstream snip;
853         SnippetList::const_iterator pit  = css_snippets_.begin();
854         SnippetList::const_iterator pend = css_snippets_.end();
855         for (; pit != pend; ++pit)
856                 snip << *pit << '\n';
857         return snip.str();
858 }
859
860
861 docstring const LaTeXFeatures::getMacros() const
862 {
863         odocstringstream macros;
864
865         if (!preamble_snippets_.empty()) {
866                 macros << '\n';
867                 macros << from_utf8(getPreambleSnippets());
868         }
869
870         if (mustProvide("papersize")) {
871                 if (runparams_.flavor == OutputParams::LATEX)
872                         macros << papersizedvi_def << '\n';
873                 else
874                         macros << papersizepdf_def << '\n';
875         }
876
877         if (mustProvide("LyX")) {
878                 if (isRequired("hyperref"))
879                         macros << lyx_hyperref_def << '\n';
880                 else
881                         macros << lyx_def << '\n';
882         }
883
884         if (mustProvide("noun"))
885                 macros << noun_def << '\n';
886
887         if (mustProvide("lyxarrow"))
888                 macros << lyxarrow_def << '\n';
889
890         if (!usePolyglossia() && mustProvide("textgreek")) {
891                 // Avoid a LaTeX error if times fonts are used and the grtimes
892                 // package is installed but actual fonts are not (bug 6469).
893                 if (params_.fonts_roman == "times")
894                         macros << subst(textgreek_def,
895                                         from_ascii("\\greektext #1"),
896                                         from_ascii("%\n  \\IfFileExists"
897                                                    "{grtm10.tfm}{}{\\fontfamily"
898                                                    "{cmr}}\\greektext #1"))
899                                << '\n';
900                 else
901                         macros << textgreek_def << '\n';
902         }
903
904         if (!usePolyglossia() && mustProvide("textcyr"))
905                 macros << textcyr_def << '\n';
906
907         if (mustProvide("lyxmathsym"))
908                 macros << lyxmathsym_def << '\n';
909
910         if (mustProvide("cedilla"))
911                 macros << cedilla_def << '\n';
912
913         if (mustProvide("subring"))
914                 macros << subring_def << '\n';
915
916         if (mustProvide("subdot"))
917                 macros << subdot_def << '\n';
918
919         if (mustProvide("subhat"))
920                 macros << subhat_def << '\n';
921
922         if (mustProvide("subtilde"))
923                 macros << subtilde_def << '\n';
924
925         if (mustProvide("dacute"))
926                 macros << dacute_def << '\n';
927
928         if (mustProvide("tipasymb"))
929                 macros << tipasymb_def << '\n';
930
931         if (mustProvide("dgrave"))
932                 macros << dgrave_def << '\n';
933
934         if (mustProvide("rcap"))
935                 macros << rcap_def << '\n';
936
937         if (mustProvide("ogonek"))
938                 macros << ogonek_def << '\n';
939
940         // quotes.
941         if (mustProvide("quotesinglbase"))
942                 macros << quotesinglbase_def << '\n';
943         if (mustProvide("quotedblbase"))
944                 macros << quotedblbase_def << '\n';
945         if (mustProvide("guilsinglleft"))
946                 macros << guilsinglleft_def << '\n';
947         if (mustProvide("guilsinglright"))
948                 macros << guilsinglright_def << '\n';
949         if (mustProvide("guillemotleft"))
950                 macros << guillemotleft_def << '\n';
951         if (mustProvide("guillemotright"))
952                 macros << guillemotright_def << '\n';
953
954         // Math mode
955         if (mustProvide("binom") && !isRequired("amsmath"))
956                 macros << binom_def << '\n';
957         if (mustProvide("mathcircumflex"))
958                 macros << mathcircumflex_def << '\n';
959
960         // other
961         if (mustProvide("ParagraphLeftIndent"))
962                 macros << paragraphleftindent_def;
963         if (mustProvide("NeedLyXFootnoteCode"))
964                 macros << floatingfootnote_def;
965
966         // some problems with tex->html converters
967         if (mustProvide("NeedTabularnewline"))
968                 macros << tabularnewline_def;
969
970         // greyed-out environment (note inset)
971         // the color is specified in the routine
972         // getColorOptions() to avoid LaTeX-package clashes
973         if (mustProvide("lyxgreyedout"))
974                 macros << lyxgreyedout_def;
975
976         if (mustProvide("lyxdot"))
977                 macros << lyxdot_def << '\n';
978
979         // floats
980         getFloatDefinitions(macros);
981
982         if (mustProvide("refstyle"))
983                 macros << lyxref_def << '\n';
984
985         // change tracking
986         if (mustProvide("ct-dvipost"))
987                 macros << changetracking_dvipost_def;
988
989         if (mustProvide("ct-xcolor-ulem")) {
990                 streamsize const prec = macros.precision(2);
991
992                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
993                 macros << "\\providecolor{lyxadded}{rgb}{"
994                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
995
996                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
997                 macros << "\\providecolor{lyxdeleted}{rgb}{"
998                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
999
1000                 macros.precision(prec);
1001
1002                 if (isRequired("hyperref"))
1003                         macros << changetracking_xcolor_ulem_hyperref_def;
1004                 else
1005                         macros << changetracking_xcolor_ulem_def;
1006         }
1007
1008         if (mustProvide("ct-none"))
1009                 macros << changetracking_none_def;
1010
1011         return macros.str();
1012 }
1013
1014
1015 string const LaTeXFeatures::getBabelPresettings() const
1016 {
1017         ostringstream tmp;
1018
1019         LanguageList::const_iterator it  = UsedLanguages_.begin();
1020         LanguageList::const_iterator end = UsedLanguages_.end();
1021         for (; it != end; ++it)
1022                 if (!(*it)->babel_presettings().empty())
1023                         tmp << (*it)->babel_presettings() << '\n';
1024         if (!params_.language->babel_presettings().empty())
1025                 tmp << params_.language->babel_presettings() << '\n';
1026
1027         if (!contains(tmp.str(), '@'))
1028                 return tmp.str();
1029
1030         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1031 }
1032
1033
1034 string const LaTeXFeatures::getBabelPostsettings() const
1035 {
1036         ostringstream tmp;
1037
1038         LanguageList::const_iterator it  = UsedLanguages_.begin();
1039         LanguageList::const_iterator end = UsedLanguages_.end();
1040         for (; it != end; ++it)
1041                 if (!(*it)->babel_postsettings().empty())
1042                         tmp << (*it)->babel_postsettings() << '\n';
1043         if (!params_.language->babel_postsettings().empty())
1044                 tmp << params_.language->babel_postsettings() << '\n';
1045
1046         if (!contains(tmp.str(), '@'))
1047                 return tmp.str();
1048
1049         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1050 }
1051
1052
1053 bool LaTeXFeatures::needBabelLangOptions() const
1054 {
1055         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1056                 return true;
1057
1058         LanguageList::const_iterator it  = UsedLanguages_.begin();
1059         LanguageList::const_iterator end = UsedLanguages_.end();
1060         for (; it != end; ++it)
1061                 if ((*it)->asBabelOptions())
1062                         return true;
1063
1064         return false;
1065 }
1066
1067
1068 string const LaTeXFeatures::loadAMSPackages() const
1069 {
1070         ostringstream tmp;
1071         if (mustProvide("amsthm"))
1072                 tmp << "\\usepackage{amsthm}\n";
1073
1074         if (mustProvide("amsmath")
1075             && params_.use_package("amsmath") != BufferParams::package_off) {
1076                 tmp << "\\usepackage{amsmath}\n";
1077         } else {
1078                 // amsbsy and amstext are already provided by amsmath
1079                 if (mustProvide("amsbsy"))
1080                         tmp << "\\usepackage{amsbsy}\n";
1081                 if (mustProvide("amstext"))
1082                         tmp << "\\usepackage{amstext}\n";
1083         }
1084
1085         if (mustProvide("amssymb")
1086             && params_.use_package("amssymb") != BufferParams::package_off)
1087                 tmp << "\\usepackage{amssymb}\n";
1088
1089         return tmp.str();
1090 }
1091
1092
1093 docstring const LaTeXFeatures::getTClassPreamble() const
1094 {
1095         // the text class specific preamble
1096         DocumentClass const & tclass = params_.documentClass();
1097         odocstringstream tcpreamble;
1098
1099         tcpreamble << tclass.preamble();
1100
1101         list<docstring>::const_iterator cit = usedLayouts_.begin();
1102         list<docstring>::const_iterator end = usedLayouts_.end();
1103         for (; cit != end; ++cit)
1104                 tcpreamble << tclass[*cit].preamble();
1105
1106         cit = usedInsetLayouts_.begin();
1107         end = usedInsetLayouts_.end();
1108         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1109         for (; cit != end; ++cit) {
1110                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1111                 if (it == ils.end())
1112                         continue;
1113                 tcpreamble << it->second.preamble();
1114         }
1115
1116         return tcpreamble.str();
1117 }
1118
1119
1120 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1121 {
1122         DocumentClass const & tclass = params_.documentClass();
1123         odocstringstream tcpreamble;
1124
1125         tcpreamble << tclass.htmlpreamble();
1126
1127         list<docstring>::const_iterator cit = usedLayouts_.begin();
1128         list<docstring>::const_iterator end = usedLayouts_.end();
1129         for (; cit != end; ++cit)
1130                 tcpreamble << tclass[*cit].htmlpreamble();
1131
1132         cit = usedInsetLayouts_.begin();
1133         end = usedInsetLayouts_.end();
1134         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1135         for (; cit != end; ++cit) {
1136                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1137                 if (it == ils.end())
1138                         continue;
1139                 tcpreamble << it->second.htmlpreamble();
1140         }
1141
1142         return tcpreamble.str();
1143 }
1144
1145
1146 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1147 {
1148         DocumentClass const & tclass = params_.documentClass();
1149         odocstringstream tcpreamble;
1150
1151         tcpreamble << tclass.htmlstyles();
1152
1153         list<docstring>::const_iterator cit = usedLayouts_.begin();
1154         list<docstring>::const_iterator end = usedLayouts_.end();
1155         for (; cit != end; ++cit)
1156                 tcpreamble << tclass[*cit].htmlstyle();
1157
1158         cit = usedInsetLayouts_.begin();
1159         end = usedInsetLayouts_.end();
1160         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1161         for (; cit != end; ++cit) {
1162                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1163                 if (it == ils.end())
1164                         continue;
1165                 tcpreamble << it->second.htmlstyle();
1166         }
1167
1168         return tcpreamble.str();
1169 }
1170
1171
1172 namespace {
1173 docstring const getFloatI18nPreamble(docstring const & type,
1174                         docstring const & name, Language const * lang,
1175                         Encoding const & enc, bool const polyglossia)
1176 {
1177         // Check whether name can be encoded in the buffer encoding
1178         bool encodable = true;
1179         for (size_t i = 0; i < name.size(); ++i) {
1180                 if (!enc.encodable(name[i])) {
1181                         encodable = false;
1182                         break;
1183                 }
1184         }
1185
1186         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1187                                                : from_ascii(lang->babel());
1188         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1189         docstring const texenc = from_ascii(lang->encoding()->latexName());
1190         docstring const bufenc = from_ascii(enc.iconvName());
1191         docstring const s1 = docstring(1, 0xF0000);
1192         docstring const s2 = docstring(1, 0xF0001);
1193         docstring const translated = encodable ? name
1194                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1195                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1196
1197         odocstringstream os;
1198         os << "\\addto\\captions" << language
1199            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1200         return os.str();
1201 }
1202
1203
1204 docstring const i18npreamble(docstring const & templ, Language const * lang,
1205                 Encoding const & enc, bool const polyglossia)
1206 {
1207         if (templ.empty())
1208                 return templ;
1209
1210         string preamble = polyglossia ?
1211                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1212                 subst(to_utf8(templ), "$$lang", lang->babel());
1213
1214         string const langenc = lang->encoding()->iconvName();
1215         string const texenc = lang->encoding()->latexName();
1216         string const bufenc = enc.iconvName();
1217         // First and second character of plane 15 (Private Use Area)
1218         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1219         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1220         // FIXME UNICODE
1221         // lyx::regex is not unicode-safe.
1222         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1223         static regex const reg("_\\(([^\\)]+)\\)");
1224         smatch sub;
1225         while (regex_search(preamble, sub, reg)) {
1226                 string const key = sub.str(1);
1227                 docstring const name = lang->translateLayout(key);
1228                 // Check whether name can be encoded in the buffer encoding
1229                 bool encodable = true;
1230                 for (size_t i = 0; i < name.size(); ++i) {
1231                         if (!enc.encodable(name[i])) {
1232                                 encodable = false;
1233                                 break;
1234                         }
1235                 }
1236                 string const translated = encodable ? to_utf8(name)
1237                         : "\\inputencoding{" + texenc + "}"
1238                         + s1 + langenc + s2 + to_utf8(name)
1239                         + s1 + bufenc + s2;
1240                 preamble = subst(preamble, sub.str(), translated);
1241         }
1242         return from_utf8(preamble);
1243 }
1244
1245 }
1246
1247
1248 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1249 {
1250         DocumentClass const & tclass = params_.documentClass();
1251         // collect preamble snippets in a set to prevent multiple identical
1252         // commands (would happen if e.g. both theorem and theorem* are used)
1253         set<docstring> snippets;
1254         typedef LanguageList::const_iterator lang_it;
1255         lang_it const lbeg = UsedLanguages_.begin();
1256         lang_it const lend =  UsedLanguages_.end();
1257         list<docstring>::const_iterator cit = usedLayouts_.begin();
1258         list<docstring>::const_iterator end = usedLayouts_.end();
1259         for (; cit != end; ++cit) {
1260                 // language dependent commands (once per document)
1261                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1262                                                 buffer().language(),
1263                                                 buffer().params().encoding(),
1264                                                 use_polyglossia));
1265                 // commands for language changing (for multilanguage documents)
1266                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1267                         snippets.insert(i18npreamble(
1268                                                 tclass[*cit].babelpreamble(),
1269                                                 buffer().language(),
1270                                                 buffer().params().encoding(),
1271                                                 use_polyglossia));
1272                         for (lang_it lit = lbeg; lit != lend; ++lit)
1273                                 snippets.insert(i18npreamble(
1274                                                 tclass[*cit].babelpreamble(),
1275                                                 *lit,
1276                                                 buffer().params().encoding(),
1277                                                 use_polyglossia));
1278                 }
1279         }
1280         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1281                 FloatList const & floats = params_.documentClass().floats();
1282                 UsedFloats::const_iterator fit = usedFloats_.begin();
1283                 UsedFloats::const_iterator fend = usedFloats_.end();
1284                 for (; fit != fend; ++fit) {
1285                         Floating const & fl = floats.getType(fit->first);
1286                         // we assume builtin floats are translated
1287                         if (fl.isPredefined())
1288                                 continue;
1289                         docstring const type = from_ascii(fl.floattype());
1290                         docstring const flname = from_utf8(fl.name());
1291                         docstring name = buffer().language()->translateLayout(fl.name());
1292                         // only request translation if we have a real translation
1293                         // (that differs from the source)
1294                         if (flname != name)
1295                                 snippets.insert(getFloatI18nPreamble(
1296                                                 type, name, buffer().language(),
1297                                                 buffer().params().encoding(),
1298                                                 use_polyglossia));
1299                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1300                                 string const code = (*lit)->code();
1301                                 name = (*lit)->translateLayout(fl.name());
1302                                 // we assume we have a suitable translation if
1303                                 // either the language is English (we need to
1304                                 // translate into English if English is a secondary
1305                                 // language) or if translateIfPossible returns
1306                                 // something different to the English source.
1307                                 bool const have_translation =
1308                                         (flname != name || contains(code, "en"));
1309                                 if (have_translation)
1310                                         snippets.insert(getFloatI18nPreamble(
1311                                                 type, name, *lit,
1312                                                 buffer().params().encoding(),
1313                                                 use_polyglossia));
1314                         }
1315                 }
1316         }
1317
1318         cit = usedInsetLayouts_.begin();
1319         end = usedInsetLayouts_.end();
1320         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1321         for (; cit != end; ++cit) {
1322                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1323                 if (it == ils.end())
1324                         continue;
1325                 // language dependent commands (once per document)
1326                 snippets.insert(i18npreamble(it->second.langpreamble(),
1327                                                 buffer().language(),
1328                                                 buffer().params().encoding(),
1329                                                 use_polyglossia));
1330                 // commands for language changing (for multilanguage documents)
1331                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1332                         snippets.insert(i18npreamble(
1333                                                 it->second.babelpreamble(),
1334                                                 buffer().language(),
1335                                                 buffer().params().encoding(),
1336                                                 use_polyglossia));
1337                         for (lang_it lit = lbeg; lit != lend; ++lit)
1338                                 snippets.insert(i18npreamble(
1339                                                 it->second.babelpreamble(),
1340                                                 *lit,
1341                                                 buffer().params().encoding(),
1342                                                 use_polyglossia));
1343                 }
1344         }
1345
1346         odocstringstream tcpreamble;
1347         set<docstring>::const_iterator const send = snippets.end();
1348         set<docstring>::const_iterator it = snippets.begin();
1349         for (; it != send; ++it)
1350                 tcpreamble << *it;
1351         return tcpreamble.str();
1352 }
1353
1354
1355 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1356 {
1357         // Definition of entities used in the document that are LyX related.
1358         odocstringstream entities;
1359
1360         if (mustProvide("lyxarrow")) {
1361                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1362         }
1363
1364         return entities.str();
1365 }
1366
1367
1368 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1369 {
1370         odocstringstream sgmlpreamble;
1371         // FIXME UNICODE
1372         docstring const basename(from_utf8(onlyPath(fname)));
1373
1374         FileMap::const_iterator end = IncludedFiles_.end();
1375         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1376              fi != end; ++fi)
1377                 // FIXME UNICODE
1378                 sgmlpreamble << "\n<!ENTITY " << fi->first
1379                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1380                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1381
1382         return sgmlpreamble.str();
1383 }
1384
1385
1386 void LaTeXFeatures::showStruct() const
1387 {
1388         lyxerr << "LyX needs the following commands when LaTeXing:"
1389                << "\n***** Packages:" << getPackages()
1390                << "\n***** Macros:" << to_utf8(getMacros())
1391                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1392                << "\n***** done." << endl;
1393 }
1394
1395
1396 Buffer const & LaTeXFeatures::buffer() const
1397 {
1398         return *buffer_;
1399 }
1400
1401
1402 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1403 {
1404         buffer_ = &buffer;
1405 }
1406
1407
1408 BufferParams const & LaTeXFeatures::bufferParams() const
1409 {
1410         return params_;
1411 }
1412
1413
1414 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1415 {
1416         FloatList const & floats = params_.documentClass().floats();
1417
1418         // Here we will output the code to create the needed float styles.
1419         // We will try to do this as minimal as possible.
1420         // \floatstyle{ruled}
1421         // \newfloat{algorithm}{htbp}{loa}
1422         // \providecommand{\algorithmname}{Algorithm}
1423         // \floatname{algorithm}{\protect\algorithmname}
1424         UsedFloats::const_iterator cit = usedFloats_.begin();
1425         UsedFloats::const_iterator end = usedFloats_.end();
1426         for (; cit != end; ++cit) {
1427                 Floating const & fl = floats.getType(cit->first);
1428
1429                 // For builtin floats we do nothing.
1430                 if (fl.isPredefined())
1431                         continue;
1432
1433                 // We have to special case "table" and "figure"
1434                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1435                         // Output code to modify "table" or "figure"
1436                         // but only if builtin == false
1437                         // and that have to be true at this point in the
1438                         // function.
1439                         docstring const type = from_ascii(fl.floattype());
1440                         docstring const placement = from_ascii(fl.placement());
1441                         docstring const style = from_ascii(fl.style());
1442                         if (!style.empty()) {
1443                                 os << "\\floatstyle{" << style << "}\n"
1444                                    << "\\restylefloat{" << type << "}\n";
1445                         }
1446                         if (!placement.empty()) {
1447                                 os << "\\floatplacement{" << type << "}{"
1448                                    << placement << "}\n";
1449                         }
1450                 } else {
1451                         // The other non builtin floats.
1452
1453                         docstring const type = from_ascii(fl.floattype());
1454                         docstring const placement = from_ascii(fl.placement());
1455                         docstring const ext = from_ascii(fl.ext());
1456                         docstring const within = from_ascii(fl.within());
1457                         docstring const style = from_ascii(fl.style());
1458                         docstring const name =
1459                                 buffer().language()->translateLayout(fl.name());
1460                         os << "\\floatstyle{" << style << "}\n"
1461                            << "\\newfloat{" << type << "}{" << placement
1462                            << "}{" << ext << '}';
1463                         if (!within.empty())
1464                                 os << '[' << within << ']';
1465                         os << '\n'
1466                            << "\\providecommand{\\" << type << "name}{"
1467                            << name << "}\n"
1468                            << "\\floatname{" << type << "}{\\protect\\"
1469                            << type << "name}\n";
1470
1471                         // What missing here is to code to minimalize the code
1472                         // output so that the same floatstyle will not be
1473                         // used several times, when the same style is still in
1474                         // effect. (Lgb)
1475                 }
1476                 if (cit->second)
1477                         os << "\n\\newsubfloat{" << from_ascii(fl.floattype()) << "}\n";
1478         }
1479 }
1480
1481
1482 void LaTeXFeatures::resolveAlternatives()
1483 {
1484         for (Features::iterator it = features_.begin(); it != features_.end();) {
1485                 if (contains(*it, '|')) {
1486                         vector<string> const alternatives = getVectorFromString(*it, "|");
1487                         vector<string>::const_iterator const end = alternatives.end();
1488                         vector<string>::const_iterator ita = alternatives.begin();
1489                         for (; ita != end; ++ita) {
1490                                 if (isRequired(*ita))
1491                                         break;
1492                         }
1493                         if (ita == end)
1494                                 require(alternatives.front());
1495                         features_.erase(it);
1496                         it = features_.begin();
1497                 } else
1498                         ++it;
1499         }
1500 }
1501
1502
1503 } // namespace lyx