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