]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
37209e23b02f92529cea6924313e15e5bac33573
[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 "LaTeXFonts.h"
28 #include "LaTeXPackages.h"
29 #include "Layout.h"
30 #include "Lexer.h"
31 #include "LyXRC.h"
32 #include "TextClass.h"
33 #include "TexRow.h"
34 #include "texstream.h"
35
36 #include "insets/InsetLayout.h"
37
38 #include "support/debug.h"
39 #include "support/docstream.h"
40 #include "support/FileName.h"
41 #include "support/filetools.h"
42 #include "support/gettext.h"
43 #include "support/lstrings.h"
44 #include "support/regex.h"
45
46 #include <algorithm>
47
48
49 using namespace std;
50 using namespace lyx::support;
51
52
53 namespace lyx {
54
55 /////////////////////////////////////////////////////////////////////
56 //
57 // Strings
58 //
59 /////////////////////////////////////////////////////////////////////
60
61 //\NeedsTeXFormat{LaTeX2e}
62 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
63 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
64
65 static docstring const lyx_def = from_ascii(
66         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
67
68 static docstring const lyx_hyperref_def = from_ascii(
69         "\\providecommand{\\LyX}{\\texorpdfstring%\n"
70         "  {L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}\n"
71         "  {LyX}}");
72
73 static docstring const noun_def = from_ascii(
74         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
75
76 static docstring const lyxarrow_def = from_ascii(
77         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
78         "\\@ifstar\n"
79         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
80         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
81
82 // for quotes without babel. This does not give perfect results, but
83 // anybody serious about non-english quotes should use babel (JMarc).
84
85 static docstring const quotedblbase_def = from_ascii(
86         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
87         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
88         "  \\penalty10000\\hskip0em\\relax%\n"
89         "}");
90
91 static docstring const quotesinglbase_def = from_ascii(
92         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
93         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
94         "  \\penalty10000\\hskip0em\\relax%\n"
95         "}");
96
97 static docstring const guillemotleft_def = from_ascii(
98         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
99         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
100         "\\penalty10000\\hskip0pt\\relax%\n"
101         "}");
102
103 static docstring const guillemotright_def = from_ascii(
104         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
105         "  \\penalty10000\\hskip0pt%\n"
106         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
107         "}");
108
109 static docstring const guilsinglleft_def = from_ascii(
110         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
111         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
112         "  \\penalty10000\\hskip0pt\\relax%\n"
113         "}");
114
115 static docstring const guilsinglright_def = from_ascii(
116         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
117         "  \\penalty10000\\hskip0pt%\n"
118         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
119         "}");
120
121 static docstring const paragraphleftindent_def = from_ascii(
122         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
123         "{\n"
124         "  \\begin{list}{}{%\n"
125         "    \\setlength{\\topsep}{0pt}%\n"
126         "    \\addtolength{\\leftmargin}{#1}\n"
127 // ho hum, yet more things commented out with no hint as to why they
128 // weren't just removed
129 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
130 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
131 //      "%%    \\setlength\\listparindent\\parindent%\n"
132 //      "%%    \\setlength\\itemindent\\parindent%\n"
133         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
134         "  }\n"
135         "  \\item[]\n"
136         "}\n"
137         "{\\end{list}}\n");
138
139 static docstring const floatingfootnote_def = from_ascii(
140         "%% Special footnote code from the package 'stblftnt.sty'\n"
141         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
142         "\\let\\SF@@footnote\\footnote\n"
143         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
144         "    \\expandafter\\SF@@footnote\n"
145         "  \\else\n"
146         "    \\expandafter\\SF@gobble@opt\n"
147         "  \\fi\n"
148         "}\n"
149         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
150         "  \\SF@gobble@twobracket\n"
151         "  \\@gobble\n"
152         "}\n"
153         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
154         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
155         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
156
157 static docstring const binom_def = from_ascii(
158         "%% Binom macro for standard LaTeX users\n"
159         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
160
161 static docstring const mathcircumflex_def = from_ascii(
162         "%% For printing a cirumflex inside a formula\n"
163         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
164
165 static docstring const tabularnewline_def = from_ascii(
166         "%% Because html converters don't know tabularnewline\n"
167         "\\providecommand{\\tabularnewline}{\\\\}\n");
168
169 static docstring const lyxgreyedout_def = from_ascii(
170         "%% The greyedout annotation environment\n"
171         "\\newenvironment{lyxgreyedout}\n"
172         "  {\\textcolor{note_fontcolor}\\bgroup\\ignorespaces}\n"
173         "  {\\ignorespacesafterend\\egroup}\n");
174
175 // We want to omit the file extension for includegraphics, but this does not
176 // work when the filename contains other dots.
177 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
178 static docstring const lyxdot_def = from_ascii(
179         "%% A simple dot to overcome graphicx limitations\n"
180         "\\newcommand{\\lyxdot}{.}\n");
181
182 static docstring const changetracking_dvipost_def = from_ascii(
183         "%% Change tracking with dvipost\n"
184         "\\dvipostlayout\n"
185         "\\dvipost{osstart color push Red}\n"
186         "\\dvipost{osend color pop}\n"
187         "\\dvipost{cbstart color push Blue}\n"
188         "\\dvipost{cbend color pop}\n"
189         "\\DeclareRobustCommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
190         "\\DeclareRobustCommand{\\lyxdeleted}[3]{%\n"
191         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
192
193 static docstring const changetracking_xcolor_ulem_def = from_ascii(
194         "%% Change tracking with ulem\n"
195         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
196         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\lyxsout{#3}}}\n"
197         "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n");
198
199 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
200         "%% Change tracking with ulem\n"
201         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
202         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\lyxsout{#3}}{}}}\n"
203         "\\DeclareRobustCommand{\\lyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n");
204
205 static docstring const changetracking_tikz_math_sout_def = from_ascii(
206         "%% Strike out display math with tikz\n"
207         "\\usepackage{tikz}\n"
208         "\\usetikzlibrary{calc}\n"
209         "\\newcommand{\\lyxmathsout}[1]{%\n"
210         "  \\tikz[baseline=(math.base)]{\n"
211         "    \\node[inner sep=0pt,outer sep=0pt](math){#1};\n"
212         "    \\draw($(math.south west)+(2em,.5em)$)--($(math.north east)-(2em,.5em)$);\n"
213         "  }\n"
214         "}\n");
215
216 static docstring const changetracking_none_def = from_ascii(
217         "\\newcommand{\\lyxadded}[3]{#3}\n"
218         "\\newcommand{\\lyxdeleted}[3]{}\n");
219
220 static docstring const textgreek_LGR_def = from_ascii(
221         "\\DeclareFontEncoding{LGR}{}{}\n");
222 static docstring const textgreek_def = from_ascii(
223         "\\DeclareRobustCommand{\\greektext}{%\n"
224         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
225         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
226         "\\ProvideTextCommand{\\~}{LGR}[1]{\\char126#1}\n");
227
228 static docstring const textcyr_T2A_def = from_ascii(
229         "\\InputIfFileExists{t2aenc.def}{}{%\n"
230         "  \\errmessage{File `t2aenc.def' not found: Cyrillic script not supported}}\n");
231 static docstring const textcyr_def = from_ascii(
232         "\\DeclareRobustCommand{\\cyrtext}{%\n"
233         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
234         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n");
235
236 static docstring const lyxmathsym_def = from_ascii(
237         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
238         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
239
240 static docstring const papersizedvi_def = from_ascii(
241         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
242
243 static docstring const papersizepdf_def = from_ascii(
244         "\\pdfpageheight\\paperheight\n"
245         "\\pdfpagewidth\\paperwidth\n");
246
247 static docstring const papersizepdflua_def = from_ascii(
248         "% Backwards compatibility for LuaTeX < 0.90\n"
249         "\\@ifundefined{pageheight}{\\let\\pageheight\\pdfpageheight}{}\n"
250         "\\@ifundefined{pagewidth}{\\let\\pagewidth\\pdfpagewidth}{}\n"
251         "\\pageheight\\paperheight\n"
252         "\\pagewidth\\paperwidth\n");
253
254 static docstring const cedilla_def = from_ascii(
255         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
256         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
257
258 static docstring const subring_def = from_ascii(
259         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
260         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
261
262 static docstring const subdot_def = from_ascii(
263         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
264         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
265
266 static docstring const subhat_def = from_ascii(
267         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
268         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
269
270 static docstring const subtilde_def = from_ascii(
271         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
272         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
273
274 static docstring const dacute_def = from_ascii(
275         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
276
277 static docstring const tipasymb_def = from_ascii(
278         "\\DeclareFontEncoding{T3}{}{}\n"
279         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
280
281 static docstring const dgrave_def = from_ascii(
282         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
283
284 static docstring const rcap_def = from_ascii(
285         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
286
287 static docstring const ogonek_def = from_ascii(
288         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
289         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
290         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
291         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
292         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
293
294 static docstring const lyxaccent_def = from_ascii(
295         "%% custom text accent \\LyxTextAccent[<rise value (length)>]{<accent>}{<base>}\n"
296         "\\newcommand*{\\LyxTextAccent}[3][0ex]{%\n"
297         "  \\hmode@bgroup\\ooalign{\\null#3\\crcr\\hidewidth\n"
298         "  \\raise#1\\hbox{#2}\\hidewidth}\\egroup}\n"
299         "%% select a font size smaller than the current font size:\n"
300         "\\newcommand{\\LyxAccentSize}[1][\\sf@size]{%\n"
301         "  \\check@mathfonts\\fontsize#1\\z@\\math@fontsfalse\\selectfont\n"
302         "}\n");
303
304 static docstring const textcommabelow_def = from_ascii(
305         "\\ProvideTextCommandDefault{\\textcommabelow}[1]{%%\n"
306         "  \\LyxTextAccent[-.31ex]{\\LyxAccentSize,}{#1}}\n");
307
308 static docstring const textcommaabove_def = from_ascii(
309         "\\ProvideTextCommandDefault{\\textcommaabove}[1]{%%\n"
310         "  \\LyxTextAccent[.5ex]{\\LyxAccentSize`}{#1}}\n");
311
312 static docstring const textcommaaboveright_def = from_ascii(
313         "\\ProvideTextCommandDefault{\\textcommaaboveright}[1]{%%\n"
314         "  \\LyxTextAccent[.5ex]{\\LyxAccentSize\\ '}{#1}}\n");
315
316 // Baltic languages use a comma-accent instead of a cedilla
317 static docstring const textbaltic_def = from_ascii(
318         "%% use comma accent instead of cedilla for these characters:\n"
319         "\\DeclareTextCompositeCommand{\\c}{T1}{g}{\\textcommaabove{g}}\n"
320         "\\DeclareTextCompositeCommand{\\c}{T1}{G}{\\textcommabelow{G}}\n"
321         "\\DeclareTextCompositeCommand{\\c}{T1}{k}{\\textcommabelow{k}}\n"
322         "\\DeclareTextCompositeCommand{\\c}{T1}{K}{\\textcommabelow{K}}\n"
323         "\\DeclareTextCompositeCommand{\\c}{T1}{l}{\\textcommabelow{l}}\n"
324         "\\DeclareTextCompositeCommand{\\c}{T1}{L}{\\textcommabelow{L}}\n"
325         "\\DeclareTextCompositeCommand{\\c}{T1}{n}{\\textcommabelow{n}}\n"
326         "\\DeclareTextCompositeCommand{\\c}{T1}{N}{\\textcommabelow{N}}\n"
327         "\\DeclareTextCompositeCommand{\\c}{T1}{r}{\\textcommabelow{r}}\n"
328         "\\DeclareTextCompositeCommand{\\c}{T1}{R}{\\textcommabelow{R}}\n");
329
330 static docstring const lyxref_def = from_ascii(
331                 "\\RS@ifundefined{subsecref}\n"
332                 "  {\\newref{subsec}{name = \\RSsectxt}}\n"
333                 "  {}\n"
334                 "\\RS@ifundefined{thmref}\n"
335                 "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
336                 "  {}\n"
337                 "\\RS@ifundefined{lemref}\n"
338                 "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n"
339                 "  {}\n");
340
341 // Make sure the columns are also outputed as rtl
342 static docstring const rtloutputdblcol_def = from_ascii(
343         "\\def\\@outputdblcol{%\n"
344         "  \\if@firstcolumn\n"
345         "    \\global \\@firstcolumnfalse\n"
346         "    \\global \\setbox\\@leftcolumn \\box\\@outputbox\n"
347         "  \\else\n"
348         "    \\global \\@firstcolumntrue\n"
349         "    \\setbox\\@outputbox \\vbox {%\n"
350         "      \\hb@xt@\\textwidth {%\n"
351         "      \\kern\\textwidth \\kern-\\columnwidth %**\n"
352         "      \\hb@xt@\\columnwidth {%\n"
353         "         \\box\\@leftcolumn \\hss}%\n"
354         "      \\kern-\\textwidth %**\n"
355         "      \\hfil\n"
356         "      {\\normalcolor\\vrule \\@width\\columnseprule}%\n"
357         "      \\hfil\n"
358         "      \\kern-\\textwidth  %**\n"
359         "      \\hb@xt@\\columnwidth {%\n"
360         "         \\box\\@outputbox \\hss}%\n"
361         "      \\kern-\\columnwidth \\kern\\textwidth %**\n"
362         "    }%\n"
363         "  }%\n"
364         "  \\@combinedblfloats\n"
365         "  \\@outputpage\n"
366         "  \\begingroup\n"
367         "  \\@dblfloatplacement\n"
368         "  \\@startdblcolumn\n"
369         "  \\@whilesw\\if@fcolmade \\fi\n"
370         "  {\\@outputpage\n"
371         "    \\@startdblcolumn}%\n"
372         "  \\endgroup\n"
373         "  \\fi\n"
374         "}\n"
375         "\\@mparswitchtrue\n");
376
377
378 /////////////////////////////////////////////////////////////////////
379 //
380 // LyXHTML strings
381 //
382 /////////////////////////////////////////////////////////////////////
383
384 static docstring const lyxnoun_style = from_ascii(
385         "dfn.lyxnoun {\n"
386         "  font-variant: small-caps;\n"
387         "}\n");
388
389
390 // this is how it normally renders, but it might not always do so.
391 static docstring const lyxstrikeout_style = from_ascii(
392         "del.strikeout {\n"
393         "  text-decoration: line-through;\n"
394         "}\n");
395
396
397 /////////////////////////////////////////////////////////////////////
398 //
399 // LaTeXFeatures
400 //
401 /////////////////////////////////////////////////////////////////////
402
403
404 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
405                              OutputParams const & r)
406         : buffer_(&b), params_(p), runparams_(r), in_float_(false),
407           in_deleted_inset_(false)
408 {}
409
410
411 LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const
412 {
413         string const local_lp = bufferParams().lang_package;
414
415         // Locally, custom is just stored as a string
416         // in bufferParams().lang_package.
417         if (local_lp != "auto"
418             && local_lp != "babel"
419             && local_lp != "default"
420             && local_lp != "none")
421                  return LANG_PACK_CUSTOM;
422
423         if (local_lp == "none")
424                 return LANG_PACK_NONE;
425
426         /* If "auto" is selected, we load polyglossia with non-TeX fonts,
427          * else we select babel.
428          * If babel is selected (either directly or via the "auto"
429          * mechanism), we really do only require it if we have
430          * a language that needs it.
431          */
432         bool const polyglossia_required =
433                 params_.useNonTeXFonts
434                 && isAvailable("polyglossia")
435                 && !isProvided("babel")
436                 && this->hasOnlyPolyglossiaLanguages();
437         bool const babel_required =
438                 !bufferParams().language->babel().empty()
439                 || !this->getBabelLanguages().empty();
440
441         if (local_lp == "auto") {
442                 // polyglossia requirement has priority over babel
443                 if (polyglossia_required)
444                         return LANG_PACK_POLYGLOSSIA;
445                 else if (babel_required)
446                         return LANG_PACK_BABEL;
447         }
448
449         if (local_lp == "babel") {
450                 if (babel_required)
451                         return LANG_PACK_BABEL;
452         }
453
454         if (local_lp == "default") {
455                 switch (lyxrc.language_package_selection) {
456                 case LyXRC::LP_AUTO:
457                         // polyglossia requirement has priority over babel
458                         if (polyglossia_required)
459                                 return LANG_PACK_POLYGLOSSIA;
460                         else if (babel_required)
461                                 return LANG_PACK_BABEL;
462                         break;
463                 case LyXRC::LP_BABEL:
464                         if (babel_required)
465                                 return LANG_PACK_BABEL;
466                         break;
467                 case LyXRC::LP_CUSTOM:
468                         return LANG_PACK_CUSTOM;
469                 case LyXRC::LP_NONE:
470                         return LANG_PACK_NONE;
471                 }
472         }
473
474         return LANG_PACK_NONE;
475 }
476
477
478 void LaTeXFeatures::require(string const & name)
479 {
480         features_.insert(name);
481 }
482
483
484 void LaTeXFeatures::require(set<string> const & names)
485 {
486         features_.insert(names.begin(), names.end());
487 }
488
489
490 void LaTeXFeatures::useLayout(docstring const & layoutname)
491 {
492         useLayout(layoutname, 0);
493 }
494
495
496 void LaTeXFeatures::useLayout(docstring const & layoutname, int level)
497 {
498         // Some code to avoid loops in dependency definition
499         const int maxlevel = 30;
500         if (level > maxlevel) {
501                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
502                        << "recursion attained by layout "
503                        << to_utf8(layoutname) << endl;
504                 return;
505         }
506
507         DocumentClass const & tclass = params_.documentClass();
508         if (tclass.hasLayout(layoutname)) {
509                 // Is this layout already in usedLayouts?
510                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
511                     != usedLayouts_.end())
512                         return;
513
514                 Layout const & layout = tclass[layoutname];
515                 require(layout.requires());
516
517                 if (!layout.depends_on().empty()) {
518                         useLayout(layout.depends_on(), level + 1);
519                 }
520                 usedLayouts_.push_back(layoutname);
521         } else {
522                 lyxerr << "LaTeXFeatures::useLayout: layout `"
523                        << to_utf8(layoutname) << "' does not exist in this class"
524                        << endl;
525         }
526 }
527
528
529 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
530 {
531         docstring const & lname = lay.name();
532         DocumentClass const & tclass = params_.documentClass();
533
534         // this is a default inset layout, nothing useful here
535         if (!tclass.hasInsetLayout(lname))
536                 return;
537         // Is this layout already in usedInsetLayouts?
538         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
539                         != usedInsetLayouts_.end())
540                 return;
541
542         require(lay.requires());
543         usedInsetLayouts_.push_back(lname);
544 }
545
546
547 bool LaTeXFeatures::isRequired(string const & name) const
548 {
549         return features_.find(name) != features_.end();
550 }
551
552
553 bool LaTeXFeatures::isProvided(string const & name) const
554 {
555         if (params_.useNonTeXFonts)
556                 return params_.documentClass().provides(name);
557
558         bool const ot1 = (params_.font_encoding() == "default"
559                 || params_.font_encoding() == "OT1");
560         bool const complete = (params_.fontsSans() == "default"
561                 && params_.fontsTypewriter() == "default");
562         bool const nomath = (params_.fontsMath() == "default");
563         return params_.documentClass().provides(name)
564                 || theLaTeXFonts().getLaTeXFont(
565                         from_ascii(params_.fontsRoman())).provides(name, ot1,
566                                                                   complete,
567                                                                   nomath)
568                 || theLaTeXFonts().getLaTeXFont(
569                         from_ascii(params_.fontsSans())).provides(name, ot1,
570                                                                  complete,
571                                                                  nomath)
572                 || theLaTeXFonts().getLaTeXFont(
573                         from_ascii(params_.fontsTypewriter())).provides(name, ot1,
574                                                                        complete,
575                                                                        nomath)
576                 || theLaTeXFonts().getLaTeXFont(
577                         from_ascii(params_.fontsMath())).provides(name, ot1,
578                                                                        complete,
579                                                                        nomath);
580         // TODO: "textbaltic" provided, if the font-encoding is "L7x"
581         //       "textgreek" provided, if a language with font-encoding LGR is used in the document
582         //       "textcyr" provided, if a language with font-encoding T2A is used in the document
583 }
584
585
586 bool LaTeXFeatures::mustProvide(string const & name) const
587 {
588         return isRequired(name) && !isProvided(name);
589 }
590
591
592 bool LaTeXFeatures::isAvailable(string const & name)
593 {
594         string::size_type const i = name.find("->");
595         if (i != string::npos) {
596                 string const from = name.substr(0,i);
597                 string const to = name.substr(i+2);
598                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
599                 return theConverters().isReachable(from, to);
600         }
601         return LaTeXPackages::isAvailable(name);
602 }
603
604
605 namespace {
606
607 void addSnippet(std::list<TexString> & list, TexString ts, bool allow_dupes)
608 {
609         if (allow_dupes ||
610             // test the absense of duplicates, i.e. elements with same str
611             none_of(list.begin(), list.end(), [&](TexString const & ts2){
612                             return ts.str == ts2.str;
613                     })
614             )
615                 list.push_back(move(ts));
616 }
617
618
619 TexString getSnippets(std::list<TexString> const & list)
620 {
621         otexstringstream snip;
622         for (TexString const & ts : list)
623                 snip << TexString(ts) << '\n';
624         return snip.release();
625 }
626
627 } //anon namespace
628
629
630 void LaTeXFeatures::addPreambleSnippet(TexString ts, bool allow_dupes)
631 {
632         addSnippet(preamble_snippets_, move(ts), allow_dupes);
633 }
634
635
636 void LaTeXFeatures::addPreambleSnippet(docstring const & str, bool allow_dupes)
637 {
638         addSnippet(preamble_snippets_, TexString(str), allow_dupes);
639 }
640
641
642 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
643 {
644         addSnippet(css_snippets_, TexString(from_ascii(snippet)), false);
645 }
646
647
648 TexString LaTeXFeatures::getPreambleSnippets() const
649 {
650         return getSnippets(preamble_snippets_);
651 }
652
653
654 docstring LaTeXFeatures::getCSSSnippets() const
655 {
656         return getSnippets(css_snippets_).str;
657 }
658
659
660
661 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
662 {
663         if (!usedFloats_[name])
664                 usedFloats_[name] = subfloat;
665         if (subfloat)
666                 require("subfig");
667         // We only need float.sty if we use non builtin floats, or if we
668         // use the "H" modifier. This includes modified table and
669         // figure floats. (Lgb)
670         Floating const & fl = params_.documentClass().floats().getType(name);
671         if (!fl.floattype().empty() && fl.usesFloatPkg()) {
672                 require("float");
673         }
674 }
675
676
677 void LaTeXFeatures::useLanguage(Language const * lang)
678 {
679         if (!lang->babel().empty() || !lang->polyglossia().empty())
680                 UsedLanguages_.insert(lang);
681         if (!lang->requires().empty())
682                 require(lang->requires());
683         // CJK languages do not have a babel name.
684         // They use the CJK package
685         if (lang->encoding()->package() == Encoding::CJK)
686                 require("CJK");
687         // japanese package is special
688         if (lang->encoding()->package() == Encoding::japanese)
689                 require("japanese");
690 }
691
692
693 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
694 {
695         IncludedFiles_[key] = name;
696 }
697
698
699 bool LaTeXFeatures::hasLanguages() const
700 {
701         return !UsedLanguages_.empty();
702 }
703
704
705 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
706 {
707         // first the main language
708         if (params_.language->polyglossia().empty())
709                 return false;
710         // now the secondary languages
711         LanguageList::const_iterator const begin = UsedLanguages_.begin();
712         for (LanguageList::const_iterator cit = begin;
713              cit != UsedLanguages_.end();
714              ++cit) {
715                 if ((*cit)->polyglossia().empty())
716                         return false;
717         }
718         return true;
719 }
720
721
722 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
723 {
724         // first the main language
725         if (params_.language->isPolyglossiaExclusive())
726                 return true;
727         // now the secondary languages
728         LanguageList::const_iterator const begin = UsedLanguages_.begin();
729         for (LanguageList::const_iterator cit = begin;
730              cit != UsedLanguages_.end();
731              ++cit) {
732                 if ((*cit)->isPolyglossiaExclusive())
733                         return true;
734         }
735         return false;
736 }
737
738
739 vector<string> LaTeXFeatures::getPolyglossiaExclusiveLanguages() const
740 {
741         vector<string> result;
742         // first the main language
743         if (params_.language->isPolyglossiaExclusive())
744                 result.push_back(params_.language->display());
745         // now the secondary languages
746         LanguageList::const_iterator const begin = UsedLanguages_.begin();
747         for (LanguageList::const_iterator cit = begin;
748              cit != UsedLanguages_.end();
749              ++cit) {
750                 if ((*cit)->isPolyglossiaExclusive())
751                         result.push_back((*cit)->display());
752         }
753         return result;
754 }
755
756
757 vector<string> LaTeXFeatures::getBabelExclusiveLanguages() const
758 {
759         vector<string> result;
760         // first the main language
761         if (params_.language->isBabelExclusive())
762                 result.push_back(params_.language->display());
763         // now the secondary languages
764         LanguageList::const_iterator const begin = UsedLanguages_.begin();
765         for (LanguageList::const_iterator cit = begin;
766              cit != UsedLanguages_.end();
767              ++cit) {
768                 if ((*cit)->isBabelExclusive())
769                         result.push_back((*cit)->display());
770         }
771         return result;
772 }
773
774
775 string LaTeXFeatures::getBabelLanguages() const
776 {
777         ostringstream languages;
778
779         bool first = true;
780         LanguageList::const_iterator const begin = UsedLanguages_.begin();
781         for (LanguageList::const_iterator cit = begin;
782              cit != UsedLanguages_.end();
783              ++cit) {
784                 if ((*cit)->babel().empty())
785                         continue;
786                 if (!first)
787                         languages << ',';
788                 else
789                         first = false;
790                 languages << (*cit)->babel();
791         }
792         return languages.str();
793 }
794
795
796 set<string> LaTeXFeatures::getPolyglossiaLanguages() const
797 {
798         set<string> languages;
799
800         LanguageList::const_iterator const begin = UsedLanguages_.begin();
801         for (LanguageList::const_iterator cit = begin;
802              cit != UsedLanguages_.end();
803              ++cit) {
804                 // We do not need the variants here
805                 languages.insert((*cit)->polyglossia());
806         }
807         return languages;
808 }
809
810
811 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
812 {
813         // This does only find encodings of languages supported by babel, but
814         // that does not matter since we don't have a language with an
815         // encoding supported by inputenc but without babel support.
816         set<string> encodings;
817         LanguageList::const_iterator it  = UsedLanguages_.begin();
818         LanguageList::const_iterator end = UsedLanguages_.end();
819         for (; it != end; ++it)
820                 if ((*it)->encoding()->latexName() != doc_encoding &&
821                     ((*it)->encoding()->package() == Encoding::inputenc
822                      || (*it)->encoding()->package() == Encoding::japanese))
823                         encodings.insert((*it)->encoding()->latexName());
824         return encodings;
825 }
826
827
828 void LaTeXFeatures::getFontEncodings(vector<string> & encodings) const
829 {
830         // these must be loaded if glyphs of this script are used
831         // unless a language providing them is used in the document
832         // FIXME: currently the option is written twice in this case
833         if (mustProvide("textgreek"))
834                 encodings.insert(encodings.begin(), "LGR");
835         if (mustProvide("textcyr"))
836                 encodings.insert(encodings.begin(), "T2A");
837
838         LanguageList::const_iterator it  = UsedLanguages_.begin();
839         LanguageList::const_iterator end = UsedLanguages_.end();
840         for (; it != end; ++it)
841                 if (!(*it)->fontenc().empty()
842                     && ascii_lowercase((*it)->fontenc()) != "none") {
843                         vector<string> extraencs = getVectorFromString((*it)->fontenc());
844                         vector<string>::const_iterator fit = extraencs.begin();
845                         for (; fit != extraencs.end(); ++fit) {
846                                 if (find(encodings.begin(), encodings.end(), *fit) == encodings.end())
847                                         encodings.insert(encodings.begin(), *fit);
848                         }
849                 }
850 }
851
852 namespace {
853
854 char const * simplefeatures[] = {
855 // note that the package order here will be the same in the LaTeX-output
856         "array",
857         "verbatim",
858         "longtable",
859         "rotating",
860         "latexsym",
861         "pifont",
862         // subfig is handled in BufferParams.cpp
863         "varioref",
864         "prettyref",
865         "refstyle",
866         /*For a successful cooperation of the `wrapfig' package with the
867           `float' package you should load the `wrapfig' package *after*
868           the `float' package. See the caption package documentation
869           for explanation.*/
870         "float",
871         "rotfloat",
872         "wrapfig",
873         "booktabs",
874         "dvipost",
875         "fancybox",
876         "calc",
877         "units",
878         "framed",
879         "soul",
880         "textcomp",
881         "pmboxdraw",
882         "bbding",
883         "ifsym",
884         "txfonts",
885         "pxfonts",
886         "mathdesign",
887         "mathrsfs",
888         "mathabx",
889         "mathtools",
890         // "cancel",
891         "ascii",
892         "url",
893         "covington",
894         "csquotes",
895         "enumitem",
896         "endnotes",
897         "hhline",
898         "ifthen",
899         // listings is handled in BufferParams.cpp
900         "bm",
901         "pdfpages",
902         "amscd",
903         "slashed",
904         "multicol",
905         "multirow",
906         "tfrupee",
907         "shapepar",
908         "rsphrase",
909         "hpstatement",
910         "algorithm2e",
911         "sectionbox",
912         "tcolorbox",
913         "pdfcomment",
914         "fixme",
915         "todonotes",
916         "forest",
917         "varwidth"
918 };
919
920 char const * bibliofeatures[] = {
921         // Known bibliography packages (will be loaded before natbib)
922         "achicago",
923         "apacite",
924         "apalike",
925         "astron",
926         "authordate1-4",
927         "babelbib",
928         "bibgerm",
929         "chicago",
930         "chscite",
931         "harvard",
932         "mslapa",
933         "named"
934 };
935
936 int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *);
937
938 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
939
940 }
941
942
943 string const LaTeXFeatures::getColorOptions() const
944 {
945         ostringstream colors;
946
947         // Handling the color packages separately is needed to be able to load them
948         // before babel when hyperref is loaded with the colorlinks option
949         // for more info see Bufferparams.cpp
950
951         // [x]color.sty
952         if (mustProvide("color") || mustProvide("xcolor")) {
953                 string const package =
954                         (mustProvide("xcolor") ? "xcolor" : "color");
955                 if (params_.graphics_driver == "default"
956                         || params_.graphics_driver == "none")
957                         colors << "\\usepackage{" << package << "}\n";
958                 else
959                         colors << "\\usepackage["
960                                  << params_.graphics_driver
961                                  << "]{" << package << "}\n";
962         }
963
964         // pdfcolmk must be loaded after color
965         if (mustProvide("pdfcolmk"))
966                 colors << "\\usepackage{pdfcolmk}\n";
967
968         // the following 3 color commands must be set after color
969         // is loaded and before pdfpages, therefore add the command
970         // here define the set color
971         if (mustProvide("pagecolor")) {
972                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
973                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
974                 // set the page color
975                 colors << "\\pagecolor{page_backgroundcolor}\n";
976         }
977
978         if (mustProvide("fontcolor")) {
979                 colors << "\\definecolor{document_fontcolor}{rgb}{";
980                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
981                 // set the color
982                 colors << "\\color{document_fontcolor}\n";
983         }
984
985         if (mustProvide("lyxgreyedout")) {
986                 colors << "\\definecolor{note_fontcolor}{rgb}{";
987                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
988                 // the color will be set together with the definition of
989                 // the lyxgreyedout environment (see lyxgreyedout_def)
990         }
991
992         // color for shaded boxes
993         if (isRequired("framed") && mustProvide("color")) {
994                 colors << "\\definecolor{shadecolor}{rgb}{";
995                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
996                 // this color is automatically used by the LaTeX-package "framed"
997         }
998
999         return colors.str();
1000 }
1001
1002
1003 string const LaTeXFeatures::getPackageOptions() const
1004 {
1005         ostringstream packageopts;
1006         // Output all the package option stuff we have been asked to do.
1007         map<string, string>::const_iterator it =
1008                 params_.documentClass().packageOptions().begin();
1009         map<string, string>::const_iterator en =
1010                 params_.documentClass().packageOptions().end();
1011         for (; it != en; ++it)
1012                 if (mustProvide(it->first))
1013                         packageopts << "\\PassOptionsToPackage{" << it->second << "}"
1014                                  << "{" << it->first << "}\n";
1015         return packageopts.str();
1016 }
1017
1018
1019 string const LaTeXFeatures::getPackages() const
1020 {
1021         ostringstream packages;
1022
1023         // FIXME: currently, we can only load packages and macros known
1024         // to LyX.
1025         // However, with the Require tag of layouts/custom insets,
1026         // also unknown packages can be requested. They are silently
1027         // swallowed now. We should change this eventually.
1028
1029         //  These are all the 'simple' includes.  i.e
1030         //  packages which we just \usepackage{package}
1031         for (int i = 0; i < nb_simplefeatures; ++i) {
1032                 if (mustProvide(simplefeatures[i]))
1033                         packages << "\\usepackage{" << simplefeatures[i] << "}\n";
1034         }
1035
1036         // The rest of these packages are somewhat more complicated
1037         // than those above.
1038
1039         // The tipa package and its extensions (tipx, tone) must not
1040         // be loaded with non-TeX fonts, since fontspec includes the
1041         // respective macros
1042         if (mustProvide("tipa") && !params_.useNonTeXFonts)
1043                 packages << "\\usepackage{tipa}\n";
1044         if (mustProvide("tipx") && !params_.useNonTeXFonts)
1045                 packages << "\\usepackage{tipx}\n";
1046         if (mustProvide("extraipa") && !params_.useNonTeXFonts)
1047                 packages << "\\usepackage{extraipa}\n";
1048         if (mustProvide("tone") && !params_.useNonTeXFonts)
1049                 packages << "\\usepackage{tone}\n";
1050
1051         // if fontspec or newtxmath is used, AMS packages have to be loaded
1052         // before fontspec (in BufferParams)
1053         string const amsPackages = loadAMSPackages();
1054         bool const ot1 = (params_.font_encoding() == "default" || params_.font_encoding() == "OT1");
1055         bool const use_newtxmath =
1056                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fontsMath())).getUsedPackage(
1057                         ot1, false, false) == "newtxmath";
1058
1059         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
1060                 packages << amsPackages;
1061
1062         if (mustProvide("cancel") &&
1063             params_.use_package("cancel") != BufferParams::package_off)
1064                 packages << "\\usepackage{cancel}\n";
1065
1066         // marvosym and bbding both define the \Cross macro
1067         if (mustProvide("marvosym")) {
1068             if (mustProvide("bbding"))
1069                 packages << "\\let\\Cross\\relax\n";
1070             packages << "\\usepackage{marvosym}\n";
1071         }
1072
1073         // accents must be loaded after amsmath
1074         if (mustProvide("accents") &&
1075             params_.use_package("accents") != BufferParams::package_off)
1076                 packages << "\\usepackage{accents}\n";
1077
1078         // mathdots must be loaded after amsmath
1079         if (mustProvide("mathdots") &&
1080                 params_.use_package("mathdots") != BufferParams::package_off)
1081                 packages << "\\usepackage{mathdots}\n";
1082
1083         // yhmath must be loaded after amsmath
1084         if (mustProvide("yhmath") &&
1085             params_.use_package("yhmath") != BufferParams::package_off)
1086                 packages << "\\usepackage{yhmath}\n";
1087
1088         // stmaryrd must be loaded after amsmath
1089         if (mustProvide("stmaryrd") &&
1090             params_.use_package("stmaryrd") != BufferParams::package_off)
1091                 packages << "\\usepackage{stmaryrd}\n";
1092
1093         if (mustProvide("stackrel") &&
1094             params_.use_package("stackrel") != BufferParams::package_off)
1095                 packages << "\\usepackage{stackrel}\n";
1096
1097         if (mustProvide("undertilde") &&
1098                 params_.use_package("undertilde") != BufferParams::package_off)
1099                 packages << "\\usepackage{undertilde}\n";
1100
1101         // [x]color and pdfcolmk are handled in getColorOptions() above
1102
1103         // makeidx.sty
1104         if (isRequired("makeidx") || isRequired("splitidx")) {
1105                 if (!isProvided("makeidx") && !isRequired("splitidx"))
1106                         packages << "\\usepackage{makeidx}\n";
1107                 if (mustProvide("splitidx"))
1108                         packages << "\\usepackage{splitidx}\n";
1109                 packages << "\\makeindex\n";
1110         }
1111
1112         // graphicx.sty
1113         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
1114                 if (params_.graphics_driver == "default")
1115                         packages << "\\usepackage{graphicx}\n";
1116                 else
1117                         packages << "\\usepackage["
1118                                  << params_.graphics_driver
1119                                  << "]{graphicx}\n";
1120         }
1121
1122         // lyxskak.sty --- newer chess support based on skak.sty
1123         if (mustProvide("chess"))
1124                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
1125
1126         // setspace.sty
1127         if (mustProvide("setspace") && !isProvided("SetSpace"))
1128                 packages << "\\usepackage{setspace}\n";
1129
1130         // we need to assure that mhchem is loaded before esint and every other
1131         // package that redefines command of amsmath because mhchem loads amlatex
1132         // (this info is from the author of mhchem from June 2013)
1133         if (mustProvide("mhchem") &&
1134             params_.use_package("mhchem") != BufferParams::package_off)
1135                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
1136                             "\\usepackage{mhchem}\n";
1137
1138         // wasysym is a simple feature, but it must be after amsmath if both
1139         // are used
1140         // wasysym redefines some integrals (e.g. iint) from amsmath. That
1141         // leads to inconsistent integrals. We only load this package if
1142         // the document does not contain integrals (then isRequired("esint")
1143         // is false) or if esint is used, since esint redefines all relevant
1144         // integral symbols from wasysym and amsmath.
1145         // See http://www.lyx.org/trac/ticket/1942
1146         if (mustProvide("wasysym") &&
1147             params_.use_package("wasysym") != BufferParams::package_off &&
1148             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
1149                 packages << "\\usepackage{wasysym}\n";
1150
1151         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
1152         // and wasysym, since it will redeclare inconsistent integral symbols
1153         if (mustProvide("esint") &&
1154             params_.use_package("esint") != BufferParams::package_off)
1155                 packages << "\\usepackage{esint}\n";
1156
1157         // Known bibliography packages (simple \usepackage{package})
1158         for (int i = 0; i < nb_bibliofeatures; ++i) {
1159                 if (mustProvide(bibliofeatures[i]))
1160                         packages << "\\usepackage{"
1161                                  << bibliofeatures[i] << "}\n";
1162         }
1163
1164         // Compatibility between achicago and natbib
1165         if (mustProvide("achicago") && mustProvide("natbib"))
1166                 packages << "\\let\\achicagobib\\thebibliography\n";
1167
1168         // natbib.sty
1169         // Some classes load natbib themselves, but still allow (or even require)
1170         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1171         // This special case is indicated by the "natbib-internal" key.
1172         if (mustProvide("natbib") && !isProvided("natbib-internal")) {
1173                 packages << "\\usepackage[";
1174                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1175                         packages << "numbers";
1176                 else
1177                         packages << "authoryear";
1178                 packages << "]{natbib}\n";
1179         }
1180
1181         // Compatibility between achicago and natbib
1182         if (mustProvide("achicago") && mustProvide("natbib")) {
1183                 packages << "\\let\\thebibliography\\achicagobib\n";
1184                 packages << "\\let\\SCcite\\astroncite\n";
1185                 packages << "\\let\\UnexpandableProtect\\protect\n";
1186         }
1187
1188         // jurabib -- we need version 0.6 at least.
1189         if (mustProvide("jurabib"))
1190                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
1191
1192         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1193         if (mustProvide("opcit")) {
1194                 if (isRequired("hyperref"))
1195                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1196                 else
1197                         packages << "\\usepackage[custombst]{opcit}\n";
1198         }
1199
1200         // xargs -- we need version 1.09 at least
1201         if (mustProvide("xargs"))
1202                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1203
1204         if (mustProvide("xy"))
1205                 packages << "\\usepackage[all]{xy}\n";
1206
1207         if (mustProvide("feyn"))
1208                 packages << "\\usepackage{feyn}\n"; //Diagram
1209
1210         if (mustProvide("ulem"))
1211                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1212                             "\\usepackage{ulem}\n";
1213
1214         if (mustProvide("nomencl")) {
1215                 // Make it work with the new and old version of the package,
1216                 // but don't use the compatibility option since it is
1217                 // incompatible to other packages.
1218                 packages << "\\usepackage{nomencl}\n"
1219                             "% the following is useful when we have the old nomencl.sty package\n"
1220                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1221                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1222                             "\\makenomenclature\n";
1223         }
1224
1225         // fixltx2e provides subscript
1226         if (mustProvide("subscript") && !isRequired("fixltx2e"))
1227                 packages << "\\usepackage{subscript}\n";
1228
1229         // footmisc must be loaded after setspace
1230         // Set options here, load the package after the user preamble to
1231         // avoid problems with manual loaded footmisc.
1232         if (mustProvide("footmisc"))
1233                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1234
1235         if (mustProvide("microtype")){
1236                 packages << "\\usepackage{microtype}\n";
1237         }
1238
1239         return packages.str();
1240 }
1241
1242
1243 TexString LaTeXFeatures::getMacros() const
1244 {
1245         otexstringstream macros;
1246
1247         if (!preamble_snippets_.empty()) {
1248                 macros << '\n';
1249                 macros << getPreambleSnippets();
1250         }
1251
1252         if (mustProvide("papersize")) {
1253                 if (runparams_.flavor == OutputParams::LATEX
1254                     || runparams_.flavor == OutputParams::DVILUATEX)
1255                         macros << papersizedvi_def << '\n';
1256                 else if  (runparams_.flavor == OutputParams::LUATEX)
1257                         macros << papersizepdflua_def << '\n';
1258                 else
1259                         macros << papersizepdf_def << '\n';
1260         }
1261
1262         if (mustProvide("LyX")) {
1263                 if (isRequired("hyperref"))
1264                         macros << lyx_hyperref_def << '\n';
1265                 else
1266                         macros << lyx_def << '\n';
1267         }
1268
1269         if (mustProvide("noun"))
1270                 macros << noun_def << '\n';
1271
1272         if (mustProvide("lyxarrow"))
1273                 macros << lyxarrow_def << '\n';
1274
1275         if (!usePolyglossia() && mustProvide("textgreek")) {
1276                 // ensure LGR font encoding is defined also if fontenc is not loaded by LyX
1277                 if (params_.font_encoding() == "default")
1278                         macros << textgreek_LGR_def;
1279                 macros << textgreek_def << '\n';
1280         }
1281
1282         if (!usePolyglossia() && mustProvide("textcyr")) {
1283                 // ensure T2A font encoding is set up also if fontenc is not loaded by LyX
1284                 if (params_.font_encoding() == "default")
1285                         macros << textcyr_T2A_def;
1286                 macros << textcyr_def << '\n';
1287         }
1288
1289         // non-standard text accents:
1290         if (mustProvide("textcommaabove") || mustProvide("textcommaaboveright") ||
1291             mustProvide("textcommabelow") || mustProvide("textbaltic"))
1292                 macros << lyxaccent_def;
1293
1294         if (mustProvide("textcommabelow") || mustProvide("textbaltic"))
1295                 macros << textcommabelow_def << '\n';
1296
1297         if (mustProvide("textcommaabove") || mustProvide("textbaltic"))
1298                 macros << textcommaabove_def << '\n';
1299
1300         if (mustProvide("textcommaaboveright"))
1301                 macros << textcommaaboveright_def << '\n';
1302
1303         if (mustProvide("textbaltic"))
1304                 macros << textbaltic_def << '\n';
1305
1306         if (mustProvide("lyxmathsym"))
1307                 macros << lyxmathsym_def << '\n';
1308
1309         if (mustProvide("cedilla"))
1310                 macros << cedilla_def << '\n';
1311
1312         if (mustProvide("subring"))
1313                 macros << subring_def << '\n';
1314
1315         if (mustProvide("subdot"))
1316                 macros << subdot_def << '\n';
1317
1318         if (mustProvide("subhat"))
1319                 macros << subhat_def << '\n';
1320
1321         if (mustProvide("subtilde"))
1322                 macros << subtilde_def << '\n';
1323
1324         if (mustProvide("dacute"))
1325                 macros << dacute_def << '\n';
1326
1327         if (mustProvide("tipasymb"))
1328                 macros << tipasymb_def << '\n';
1329
1330         if (mustProvide("dgrave"))
1331                 macros << dgrave_def << '\n';
1332
1333         if (mustProvide("rcap"))
1334                 macros << rcap_def << '\n';
1335
1336         if (mustProvide("ogonek"))
1337                 macros << ogonek_def << '\n';
1338
1339         // quotes.
1340         if (mustProvide("quotesinglbase"))
1341                 macros << quotesinglbase_def << '\n';
1342         if (mustProvide("quotedblbase"))
1343                 macros << quotedblbase_def << '\n';
1344         if (mustProvide("guilsinglleft"))
1345                 macros << guilsinglleft_def << '\n';
1346         if (mustProvide("guilsinglright"))
1347                 macros << guilsinglright_def << '\n';
1348         if (mustProvide("guillemotleft"))
1349                 macros << guillemotleft_def << '\n';
1350         if (mustProvide("guillemotright"))
1351                 macros << guillemotright_def << '\n';
1352
1353         // Math mode
1354         if (mustProvide("binom") && !isRequired("amsmath"))
1355                 macros << binom_def << '\n';
1356         if (mustProvide("mathcircumflex"))
1357                 macros << mathcircumflex_def << '\n';
1358
1359         // other
1360         if (mustProvide("ParagraphLeftIndent"))
1361                 macros << paragraphleftindent_def;
1362         if (mustProvide("NeedLyXFootnoteCode"))
1363                 macros << floatingfootnote_def;
1364
1365         // some problems with tex->html converters
1366         if (mustProvide("NeedTabularnewline"))
1367                 macros << tabularnewline_def;
1368
1369         // greyed-out environment (note inset)
1370         // the color is specified in the routine
1371         // getColorOptions() to avoid LaTeX-package clashes
1372         if (mustProvide("lyxgreyedout"))
1373                 macros << lyxgreyedout_def;
1374
1375         if (mustProvide("lyxdot"))
1376                 macros << lyxdot_def << '\n';
1377
1378         // floats
1379         getFloatDefinitions(macros);
1380
1381         if (mustProvide("refstyle"))
1382                 macros << lyxref_def << '\n';
1383
1384         // change tracking
1385         if (mustProvide("ct-dvipost"))
1386                 macros << changetracking_dvipost_def;
1387
1388         if (mustProvide("ct-xcolor-ulem")) {
1389                 streamsize const prec = macros.os().precision(2);
1390
1391                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1392                 macros << "\\providecolor{lyxadded}{rgb}{"
1393                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1394
1395                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1396                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1397                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1398
1399                 macros.os().precision(prec);
1400
1401                 if (isRequired("hyperref"))
1402                         macros << changetracking_xcolor_ulem_hyperref_def;
1403                 else
1404                         macros << changetracking_xcolor_ulem_def;
1405         }
1406
1407         if (mustProvide("ct-tikz-math-sout"))
1408                         macros << changetracking_tikz_math_sout_def;
1409
1410         if (mustProvide("ct-none"))
1411                 macros << changetracking_none_def;
1412
1413         if (mustProvide("rtloutputdblcol"))
1414                 macros << rtloutputdblcol_def;
1415
1416         return macros.release();
1417 }
1418
1419
1420 docstring const LaTeXFeatures::getBabelPresettings() const
1421 {
1422         odocstringstream tmp;
1423
1424         for (Language const * lang : UsedLanguages_)
1425                 if (!lang->babel_presettings().empty())
1426                         tmp << lang->babel_presettings() << '\n';
1427         if (!params_.language->babel_presettings().empty())
1428                 tmp << params_.language->babel_presettings() << '\n';
1429
1430         if (!contains(tmp.str(), '@'))
1431                 return tmp.str();
1432
1433         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1434 }
1435
1436
1437 docstring const LaTeXFeatures::getBabelPostsettings() const
1438 {
1439         odocstringstream tmp;
1440
1441         for (Language const * lang : UsedLanguages_)
1442                 if (!lang->babel_postsettings().empty())
1443                         tmp << lang->babel_postsettings() << '\n';
1444         if (!params_.language->babel_postsettings().empty())
1445                 tmp << params_.language->babel_postsettings() << '\n';
1446
1447         if (!contains(tmp.str(), '@'))
1448                 return tmp.str();
1449
1450         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1451 }
1452
1453
1454 bool LaTeXFeatures::needBabelLangOptions() const
1455 {
1456         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1457                 return true;
1458
1459         LanguageList::const_iterator it  = UsedLanguages_.begin();
1460         LanguageList::const_iterator end = UsedLanguages_.end();
1461         for (; it != end; ++it)
1462                 if ((*it)->asBabelOptions())
1463                         return true;
1464
1465         return false;
1466 }
1467
1468
1469 string const LaTeXFeatures::loadAMSPackages() const
1470 {
1471         ostringstream tmp;
1472
1473         if (mustProvide("amsmath")
1474             && params_.use_package("amsmath") != BufferParams::package_off) {
1475                 tmp << "\\usepackage{amsmath}\n";
1476         } else {
1477                 // amsbsy and amstext are already provided by amsmath
1478                 if (mustProvide("amsbsy"))
1479                         tmp << "\\usepackage{amsbsy}\n";
1480                 if (mustProvide("amstext"))
1481                         tmp << "\\usepackage{amstext}\n";
1482         }
1483
1484         if (mustProvide("amsthm"))
1485                 tmp << "\\usepackage{amsthm}\n";
1486
1487         if (mustProvide("amssymb")
1488             && params_.use_package("amssymb") != BufferParams::package_off)
1489                 tmp << "\\usepackage{amssymb}\n";
1490
1491         return tmp.str();
1492 }
1493
1494
1495 docstring const LaTeXFeatures::getTClassPreamble() const
1496 {
1497         // the text class specific preamble
1498         DocumentClass const & tclass = params_.documentClass();
1499         odocstringstream tcpreamble;
1500
1501         tcpreamble << tclass.preamble();
1502
1503         list<docstring>::const_iterator cit = usedLayouts_.begin();
1504         list<docstring>::const_iterator end = usedLayouts_.end();
1505         for (; cit != end; ++cit)
1506                 tcpreamble << tclass[*cit].preamble();
1507
1508         cit = usedInsetLayouts_.begin();
1509         end = usedInsetLayouts_.end();
1510         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1511         for (; cit != end; ++cit) {
1512                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1513                 if (it == ils.end())
1514                         continue;
1515                 tcpreamble << it->second.preamble();
1516         }
1517
1518         return tcpreamble.str();
1519 }
1520
1521
1522 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1523 {
1524         DocumentClass const & tclass = params_.documentClass();
1525         odocstringstream tcpreamble;
1526
1527         tcpreamble << tclass.htmlpreamble();
1528
1529         list<docstring>::const_iterator cit = usedLayouts_.begin();
1530         list<docstring>::const_iterator end = usedLayouts_.end();
1531         for (; cit != end; ++cit)
1532                 tcpreamble << tclass[*cit].htmlpreamble();
1533
1534         cit = usedInsetLayouts_.begin();
1535         end = usedInsetLayouts_.end();
1536         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1537         for (; cit != end; ++cit) {
1538                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1539                 if (it == ils.end())
1540                         continue;
1541                 tcpreamble << it->second.htmlpreamble();
1542         }
1543
1544         return tcpreamble.str();
1545 }
1546
1547
1548 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1549 {
1550         DocumentClass const & tclass = params_.documentClass();
1551         odocstringstream tcpreamble;
1552
1553         if (mustProvide("noun"))
1554                 tcpreamble << lyxnoun_style;
1555         // this isn't exact, but it won't hurt that much if it
1556         // wasn't for this.
1557         if (mustProvide("ulem"))
1558                 tcpreamble << lyxstrikeout_style;
1559
1560         tcpreamble << tclass.htmlstyles();
1561
1562         list<docstring>::const_iterator cit = usedLayouts_.begin();
1563         list<docstring>::const_iterator end = usedLayouts_.end();
1564         for (; cit != end; ++cit)
1565                 tcpreamble << tclass[*cit].htmlstyle();
1566
1567         cit = usedInsetLayouts_.begin();
1568         end = usedInsetLayouts_.end();
1569         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1570         for (; cit != end; ++cit) {
1571                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1572                 if (it == ils.end())
1573                         continue;
1574                 tcpreamble << it->second.htmlstyle();
1575         }
1576
1577         return tcpreamble.str();
1578 }
1579
1580
1581 namespace {
1582
1583 docstring const getFloatI18nPreamble(docstring const & type,
1584                         docstring const & name, Language const * lang,
1585                         Encoding const & enc, bool const polyglossia)
1586 {
1587         // Check whether name can be encoded in the buffer encoding
1588         bool encodable = true;
1589         for (size_t i = 0; i < name.size(); ++i) {
1590                 if (!enc.encodable(name[i])) {
1591                         encodable = false;
1592                         break;
1593                 }
1594         }
1595
1596         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1597                                                : from_ascii(lang->babel());
1598         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1599         docstring const texenc = from_ascii(lang->encoding()->latexName());
1600         docstring const bufenc = from_ascii(enc.iconvName());
1601         docstring const s1 = docstring(1, 0xF0000);
1602         docstring const s2 = docstring(1, 0xF0001);
1603         docstring const translated = encodable ? name
1604                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1605                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1606
1607         odocstringstream os;
1608         os << "\\addto\\captions" << language
1609            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1610         return os.str();
1611 }
1612
1613
1614 docstring const i18npreamble(docstring const & templ, Language const * lang,
1615                              Encoding const & enc, bool const polyglossia,
1616                              bool const need_fixedwidth)
1617 {
1618         if (templ.empty())
1619                 return templ;
1620
1621         string preamble = polyglossia ?
1622                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1623                 subst(to_utf8(templ), "$$lang", lang->babel());
1624
1625         string const langenc = lang->encoding()->iconvName();
1626         string const texenc = lang->encoding()->latexName();
1627         string const bufenc = enc.iconvName();
1628         Encoding const * testenc(&enc);
1629         bool lang_fallback = false;
1630         bool ascii_fallback = false;
1631         if (need_fixedwidth && !enc.hasFixedWidth()) {
1632                 if (lang->encoding()->hasFixedWidth()) {
1633                         testenc = lang->encoding();
1634                         lang_fallback = true;
1635                 } else {
1636                         // We need a fixed width encoding, but both the buffer
1637                         // encoding and the language encoding are variable
1638                         // width. As a last fallback, try to convert to pure
1639                         // ASCII using the LaTeX commands defined in unicodesymbols.
1640                         testenc = encodings.fromLyXName("ascii");
1641                         if (!testenc)
1642                                 return docstring();
1643                         ascii_fallback = true;
1644                 }
1645         }
1646         // First and second character of plane 15 (Private Use Area)
1647         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1648         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1649         // FIXME UNICODE
1650         // lyx::regex is not unicode-safe.
1651         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1652         static regex const reg("_\\(([^\\)]+)\\)");
1653         smatch sub;
1654         while (regex_search(preamble, sub, reg)) {
1655                 string const key = sub.str(1);
1656                 docstring const name = lang->translateLayout(key);
1657                 // Check whether name can be encoded in the buffer encoding
1658                 bool encodable = true;
1659                 for (size_t i = 0; i < name.size() && encodable; ++i)
1660                         if (!testenc->encodable(name[i]))
1661                                 encodable = false;
1662                 string translated;
1663                 if (encodable && !lang_fallback)
1664                         translated = to_utf8(name);
1665                 else if (ascii_fallback)
1666                         translated = to_ascii(testenc->latexString(name).first);
1667                 else
1668                         translated = "\\inputencoding{" + texenc + "}"
1669                                 + s1 + langenc + s2 + to_utf8(name)
1670                                 + s1 + bufenc + s2;
1671                 preamble = subst(preamble, sub.str(), translated);
1672         }
1673         return from_utf8(preamble);
1674 }
1675
1676 }
1677
1678
1679 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1680 {
1681         DocumentClass const & tclass = params_.documentClass();
1682         // collect preamble snippets in a set to prevent multiple identical
1683         // commands (would happen if e.g. both theorem and theorem* are used)
1684         set<docstring> snippets;
1685         typedef LanguageList::const_iterator lang_it;
1686         lang_it const lbeg = UsedLanguages_.begin();
1687         lang_it const lend =  UsedLanguages_.end();
1688         list<docstring>::const_iterator cit = usedLayouts_.begin();
1689         list<docstring>::const_iterator end = usedLayouts_.end();
1690         for (; cit != end; ++cit) {
1691                 // language dependent commands (once per document)
1692                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1693                                                 buffer().language(),
1694                                                 buffer().params().encoding(),
1695                                                 use_polyglossia, false));
1696                 // commands for language changing (for multilanguage documents)
1697                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1698                         snippets.insert(i18npreamble(
1699                                                 tclass[*cit].babelpreamble(),
1700                                                 buffer().language(),
1701                                                 buffer().params().encoding(),
1702                                                 use_polyglossia, false));
1703                         for (lang_it lit = lbeg; lit != lend; ++lit)
1704                                 snippets.insert(i18npreamble(
1705                                                 tclass[*cit].babelpreamble(),
1706                                                 *lit,
1707                                                 buffer().params().encoding(),
1708                                                 use_polyglossia, false));
1709                 }
1710         }
1711         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1712                 FloatList const & floats = params_.documentClass().floats();
1713                 UsedFloats::const_iterator fit = usedFloats_.begin();
1714                 UsedFloats::const_iterator fend = usedFloats_.end();
1715                 for (; fit != fend; ++fit) {
1716                         Floating const & fl = floats.getType(fit->first);
1717                         // we assume builtin floats are translated
1718                         if (fl.isPredefined())
1719                                 continue;
1720                         docstring const type = from_ascii(fl.floattype());
1721                         docstring const flname = from_utf8(fl.name());
1722                         docstring name = buffer().language()->translateLayout(fl.name());
1723                         // only request translation if we have a real translation
1724                         // (that differs from the source)
1725                         if (flname != name)
1726                                 snippets.insert(getFloatI18nPreamble(
1727                                                 type, name, buffer().language(),
1728                                                 buffer().params().encoding(),
1729                                                 use_polyglossia));
1730                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1731                                 string const code = (*lit)->code();
1732                                 name = (*lit)->translateLayout(fl.name());
1733                                 // we assume we have a suitable translation if
1734                                 // either the language is English (we need to
1735                                 // translate into English if English is a secondary
1736                                 // language) or if translateIfPossible returns
1737                                 // something different to the English source.
1738                                 bool const have_translation =
1739                                         (flname != name || contains(code, "en"));
1740                                 if (have_translation)
1741                                         snippets.insert(getFloatI18nPreamble(
1742                                                 type, name, *lit,
1743                                                 buffer().params().encoding(),
1744                                                 use_polyglossia));
1745                         }
1746                 }
1747         }
1748
1749         cit = usedInsetLayouts_.begin();
1750         end = usedInsetLayouts_.end();
1751         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1752         for (; cit != end; ++cit) {
1753                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1754                 if (it == ils.end())
1755                         continue;
1756                 // The listings package does not work with variable width
1757                 // encodings, only with fixed width encodings. Therefore we
1758                 // need to force a fixed width encoding for
1759                 // \lstlistlistingname and \lstlistingname (bug 9382).
1760                 // This needs to be consistent with InsetListings::latex().
1761                 bool const need_fixedwidth = !runparams_.isFullUnicode() &&
1762                                 it->second.fixedwidthpreambleencoding();
1763                 // language dependent commands (once per document)
1764                 snippets.insert(i18npreamble(it->second.langpreamble(),
1765                                                 buffer().language(),
1766                                                 buffer().params().encoding(),
1767                                                 use_polyglossia, need_fixedwidth));
1768                 // commands for language changing (for multilanguage documents)
1769                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1770                         snippets.insert(i18npreamble(
1771                                                 it->second.babelpreamble(),
1772                                                 buffer().language(),
1773                                                 buffer().params().encoding(),
1774                                                 use_polyglossia, need_fixedwidth));
1775                         for (lang_it lit = lbeg; lit != lend; ++lit)
1776                                 snippets.insert(i18npreamble(
1777                                                 it->second.babelpreamble(),
1778                                                 *lit,
1779                                                 buffer().params().encoding(),
1780                                                 use_polyglossia, need_fixedwidth));
1781                 }
1782         }
1783
1784         odocstringstream tcpreamble;
1785         set<docstring>::const_iterator const send = snippets.end();
1786         set<docstring>::const_iterator it = snippets.begin();
1787         for (; it != send; ++it)
1788                 tcpreamble << *it;
1789         return tcpreamble.str();
1790 }
1791
1792
1793 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1794 {
1795         // Definition of entities used in the document that are LyX related.
1796         odocstringstream entities;
1797
1798         if (mustProvide("lyxarrow")) {
1799                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1800         }
1801
1802         return entities.str();
1803 }
1804
1805
1806 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1807 {
1808         odocstringstream sgmlpreamble;
1809         // FIXME UNICODE
1810         docstring const basename(from_utf8(onlyPath(fname)));
1811
1812         FileMap::const_iterator end = IncludedFiles_.end();
1813         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1814              fi != end; ++fi)
1815                 // FIXME UNICODE
1816                 sgmlpreamble << "\n<!ENTITY " << fi->first
1817                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1818                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1819
1820         return sgmlpreamble.str();
1821 }
1822
1823
1824 void LaTeXFeatures::showStruct() const
1825 {
1826         lyxerr << "LyX needs the following commands when LaTeXing:"
1827                << "\n***** Packages:" << getPackages()
1828                << "\n***** Macros:" << to_utf8(getMacros().str)
1829                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1830                << "\n***** done." << endl;
1831 }
1832
1833
1834 Buffer const & LaTeXFeatures::buffer() const
1835 {
1836         return *buffer_;
1837 }
1838
1839
1840 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1841 {
1842         buffer_ = &buffer;
1843 }
1844
1845
1846 BufferParams const & LaTeXFeatures::bufferParams() const
1847 {
1848         return params_;
1849 }
1850
1851
1852 void LaTeXFeatures::getFloatDefinitions(otexstream & os) const
1853 {
1854         FloatList const & floats = params_.documentClass().floats();
1855
1856         // Here we will output the code to create the needed float styles.
1857         // We will try to do this as minimal as possible.
1858         // \floatstyle{ruled}
1859         // \newfloat{algorithm}{htbp}{loa}
1860         // \providecommand{\algorithmname}{Algorithm}
1861         // \floatname{algorithm}{\protect\algorithmname}
1862         UsedFloats::const_iterator cit = usedFloats_.begin();
1863         UsedFloats::const_iterator end = usedFloats_.end();
1864         for (; cit != end; ++cit) {
1865                 Floating const & fl = floats.getType(cit->first);
1866
1867                 // For builtin floats we do nothing.
1868                 if (fl.isPredefined())
1869                         continue;
1870
1871                 // We have to special case "table" and "figure"
1872                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1873                         // Output code to modify "table" or "figure"
1874                         // but only if builtin == false
1875                         // and that have to be true at this point in the
1876                         // function.
1877                         docstring const type = from_ascii(fl.floattype());
1878                         docstring const placement = from_ascii(fl.placement());
1879                         docstring const style = from_ascii(fl.style());
1880                         if (!style.empty()) {
1881                                 os << "\\floatstyle{" << style << "}\n"
1882                                    << "\\restylefloat{" << type << "}\n";
1883                         }
1884                         if (!placement.empty()) {
1885                                 os << "\\floatplacement{" << type << "}{"
1886                                    << placement << "}\n";
1887                         }
1888                 } else {
1889                         // The other non builtin floats.
1890
1891                         docstring const type = from_ascii(fl.floattype());
1892                         docstring const placement = from_ascii(fl.placement());
1893                         docstring const ext = from_ascii(fl.ext());
1894                         docstring const within = from_ascii(fl.within());
1895                         docstring const style = from_ascii(fl.style());
1896                         docstring const name =
1897                                 buffer().language()->translateLayout(fl.name());
1898                         os << "\\floatstyle{" << style << "}\n"
1899                            << "\\newfloat{" << type << "}{" << placement
1900                            << "}{" << ext << '}';
1901                         if (!within.empty())
1902                                 os << '[' << within << ']';
1903                         os << '\n'
1904                            << "\\providecommand{\\" << type << "name}{"
1905                            << name << "}\n"
1906                            << "\\floatname{" << type << "}{\\protect\\"
1907                            << type << "name}\n";
1908
1909                         // What missing here is to code to minimalize the code
1910                         // output so that the same floatstyle will not be
1911                         // used several times, when the same style is still in
1912                         // effect. (Lgb)
1913                 }
1914                 if (cit->second)
1915                         // The subfig package is loaded later
1916                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
1917         }
1918 }
1919
1920
1921 void LaTeXFeatures::resolveAlternatives()
1922 {
1923         for (Features::iterator it = features_.begin(); it != features_.end();) {
1924                 if (contains(*it, '|')) {
1925                         vector<string> const alternatives = getVectorFromString(*it, "|");
1926                         vector<string>::const_iterator const end = alternatives.end();
1927                         vector<string>::const_iterator ita = alternatives.begin();
1928                         // Is any alternative already required? => use that
1929                         for (; ita != end; ++ita) {
1930                                 if (isRequired(*ita))
1931                                         break;
1932                         }
1933                         // Is any alternative available? => use the first one
1934                         // (bug 9498)
1935                         if (ita == end) {
1936                                 for (ita = alternatives.begin(); ita != end; ++ita) {
1937                                         if (isAvailable(*ita)) {
1938                                                 require(*ita);
1939                                                 break;
1940                                         }
1941                                 }
1942                         }
1943                         // This will not work, but not requiring something
1944                         // would be more confusing
1945                         if (ita == end)
1946                                 require(alternatives.front());
1947                         features_.erase(it);
1948                         it = features_.begin();
1949                 } else
1950                         ++it;
1951         }
1952 }
1953
1954
1955 void LaTeXFeatures::expandMultiples()
1956 {
1957         for (Features::iterator it = features_.begin(); it != features_.end();) {
1958                 if (contains(*it, ',')) {
1959                         vector<string> const multiples = getVectorFromString(*it, ",");
1960                         vector<string>::const_iterator const end = multiples.end();
1961                         vector<string>::const_iterator itm = multiples.begin();
1962                         // Do nothing if any multiple is already required
1963                         for (; itm != end; ++itm) {
1964                                 if (!isRequired(*itm))
1965                                         require(*itm);
1966                         }
1967                         features_.erase(it);
1968                         it = features_.begin();
1969                 } else
1970                         ++it;
1971         }
1972 }
1973
1974
1975 } // namespace lyx