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