]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
78e31eb93d4bc683c098ae4f45cd508589c12ebf
[features.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "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 std::map<std::string, std::string> LaTeXFeatures::getPolyglossiaLanguages() const
797 {
798         std::map<std::string, std::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                 languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts();
805         }
806         return languages;
807 }
808
809
810 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
811 {
812         // This does only find encodings of languages supported by babel, but
813         // that does not matter since we don't have a language with an
814         // encoding supported by inputenc but without babel support.
815         set<string> encodings;
816         LanguageList::const_iterator it  = UsedLanguages_.begin();
817         LanguageList::const_iterator end = UsedLanguages_.end();
818         for (; it != end; ++it)
819                 if ((*it)->encoding()->latexName() != doc_encoding &&
820                     ((*it)->encoding()->package() == Encoding::inputenc
821                      || (*it)->encoding()->package() == Encoding::japanese))
822                         encodings.insert((*it)->encoding()->latexName());
823         return encodings;
824 }
825
826
827 void LaTeXFeatures::getFontEncodings(vector<string> & encodings) const
828 {
829         // these must be loaded if glyphs of this script are used
830         // unless a language providing them is used in the document
831         // FIXME: currently the option is written twice in this case
832         if (mustProvide("textgreek"))
833                 encodings.insert(encodings.begin(), "LGR");
834         if (mustProvide("textcyr"))
835                 encodings.insert(encodings.begin(), "T2A");
836
837         LanguageList::const_iterator it  = UsedLanguages_.begin();
838         LanguageList::const_iterator end = UsedLanguages_.end();
839         for (; it != end; ++it)
840                 if (!(*it)->fontenc().empty()
841                     && ascii_lowercase((*it)->fontenc()) != "none") {
842                         vector<string> extraencs = getVectorFromString((*it)->fontenc());
843                         vector<string>::const_iterator fit = extraencs.begin();
844                         for (; fit != extraencs.end(); ++fit) {
845                                 if (find(encodings.begin(), encodings.end(), *fit) == encodings.end())
846                                         encodings.insert(encodings.begin(), *fit);
847                         }
848                 }
849 }
850
851 namespace {
852
853 char const * simplefeatures[] = {
854 // note that the package order here will be the same in the LaTeX-output
855         "array",
856         "verbatim",
857         "longtable",
858         "rotating",
859         "latexsym",
860         "pifont",
861         // subfig is handled in BufferParams.cpp
862         "varioref",
863         "prettyref",
864         "refstyle",
865         /*For a successful cooperation of the `wrapfig' package with the
866           `float' package you should load the `wrapfig' package *after*
867           the `float' package. See the caption package documentation
868           for explanation.*/
869         "float",
870         "rotfloat",
871         "wrapfig",
872         "booktabs",
873         "dvipost",
874         "fancybox",
875         "calc",
876         "units",
877         "framed",
878         "soul",
879         "textcomp",
880         "pmboxdraw",
881         "bbding",
882         "ifsym",
883         "txfonts",
884         "pxfonts",
885         "mathdesign",
886         "mathrsfs",
887         "mathabx",
888         "mathtools",
889         // "cancel",
890         "ascii",
891         "url",
892         "covington",
893         "csquotes",
894         "enumitem",
895         "endnotes",
896         "hhline",
897         "ifthen",
898         // listings is handled in BufferParams.cpp
899         "bm",
900         "pdfpages",
901         "amscd",
902         "slashed",
903         "multicol",
904         "multirow",
905         "tfrupee",
906         "shapepar",
907         "rsphrase",
908         "hpstatement",
909         "algorithm2e",
910         "sectionbox",
911         "tcolorbox",
912         "pdfcomment",
913         "fixme",
914         "todonotes",
915         "forest",
916         "varwidth"
917 };
918
919 char const * bibliofeatures[] = {
920         // Known bibliography packages (will be loaded before natbib)
921         "achicago",
922         "apacite",
923         "apalike",
924         "astron",
925         "authordate1-4",
926         "babelbib",
927         "bibgerm",
928         "chicago",
929         "chscite",
930         "harvard",
931         "mslapa",
932         "named"
933 };
934
935 int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *);
936
937 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
938
939 }
940
941
942 string const LaTeXFeatures::getColorOptions() const
943 {
944         ostringstream colors;
945
946         // Handling the color packages separately is needed to be able to load them
947         // before babel when hyperref is loaded with the colorlinks option
948         // for more info see Bufferparams.cpp
949
950         // [x]color.sty
951         if (mustProvide("color") || mustProvide("xcolor")) {
952                 string const package =
953                         (mustProvide("xcolor") ? "xcolor" : "color");
954                 if (params_.graphics_driver == "default"
955                         || params_.graphics_driver == "none")
956                         colors << "\\usepackage{" << package << "}\n";
957                 else
958                         colors << "\\usepackage["
959                                  << params_.graphics_driver
960                                  << "]{" << package << "}\n";
961         }
962
963         // pdfcolmk must be loaded after color
964         if (mustProvide("pdfcolmk"))
965                 colors << "\\usepackage{pdfcolmk}\n";
966
967         // the following 3 color commands must be set after color
968         // is loaded and before pdfpages, therefore add the command
969         // here define the set color
970         if (mustProvide("pagecolor")) {
971                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
972                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
973                 // set the page color
974                 colors << "\\pagecolor{page_backgroundcolor}\n";
975         }
976
977         if (mustProvide("fontcolor")) {
978                 colors << "\\definecolor{document_fontcolor}{rgb}{";
979                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
980                 // set the color
981                 colors << "\\color{document_fontcolor}\n";
982         }
983
984         if (mustProvide("lyxgreyedout")) {
985                 colors << "\\definecolor{note_fontcolor}{rgb}{";
986                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
987                 // the color will be set together with the definition of
988                 // the lyxgreyedout environment (see lyxgreyedout_def)
989         }
990
991         // color for shaded boxes
992         if (isRequired("framed") && mustProvide("color")) {
993                 colors << "\\definecolor{shadecolor}{rgb}{";
994                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
995                 // this color is automatically used by the LaTeX-package "framed"
996         }
997
998         return colors.str();
999 }
1000
1001
1002 string const LaTeXFeatures::getPackageOptions() const
1003 {
1004         ostringstream packageopts;
1005         // Output all the package option stuff we have been asked to do.
1006         map<string, string>::const_iterator it =
1007                 params_.documentClass().packageOptions().begin();
1008         map<string, string>::const_iterator en =
1009                 params_.documentClass().packageOptions().end();
1010         for (; it != en; ++it)
1011                 if (mustProvide(it->first))
1012                         packageopts << "\\PassOptionsToPackage{" << it->second << "}"
1013                                  << "{" << it->first << "}\n";
1014         return packageopts.str();
1015 }
1016
1017
1018 string const LaTeXFeatures::getPackages() const
1019 {
1020         ostringstream packages;
1021
1022         // FIXME: currently, we can only load packages and macros known
1023         // to LyX.
1024         // However, with the Require tag of layouts/custom insets,
1025         // also unknown packages can be requested. They are silently
1026         // swallowed now. We should change this eventually.
1027
1028         //  These are all the 'simple' includes.  i.e
1029         //  packages which we just \usepackage{package}
1030         for (int i = 0; i < nb_simplefeatures; ++i) {
1031                 if (mustProvide(simplefeatures[i]))
1032                         packages << "\\usepackage{" << simplefeatures[i] << "}\n";
1033         }
1034
1035         // The rest of these packages are somewhat more complicated
1036         // than those above.
1037
1038         // The tipa package and its extensions (tipx, tone) must not
1039         // be loaded with non-TeX fonts, since fontspec includes the
1040         // respective macros
1041         if (mustProvide("tipa") && !params_.useNonTeXFonts)
1042                 packages << "\\usepackage{tipa}\n";
1043         if (mustProvide("tipx") && !params_.useNonTeXFonts)
1044                 packages << "\\usepackage{tipx}\n";
1045         if (mustProvide("extraipa") && !params_.useNonTeXFonts)
1046                 packages << "\\usepackage{extraipa}\n";
1047         if (mustProvide("tone") && !params_.useNonTeXFonts)
1048                 packages << "\\usepackage{tone}\n";
1049
1050         // if fontspec or newtxmath is used, AMS packages have to be loaded
1051         // before fontspec (in BufferParams)
1052         string const amsPackages = loadAMSPackages();
1053         bool const ot1 = (params_.font_encoding() == "default" || params_.font_encoding() == "OT1");
1054         bool const use_newtxmath =
1055                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fontsMath())).getUsedPackage(
1056                         ot1, false, false) == "newtxmath";
1057
1058         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
1059                 packages << amsPackages;
1060
1061         if (mustProvide("cancel") &&
1062             params_.use_package("cancel") != BufferParams::package_off)
1063                 packages << "\\usepackage{cancel}\n";
1064
1065         // marvosym and bbding both define the \Cross macro
1066         if (mustProvide("marvosym")) {
1067             if (mustProvide("bbding"))
1068                 packages << "\\let\\Cross\\relax\n";
1069             packages << "\\usepackage{marvosym}\n";
1070         }
1071
1072         // accents must be loaded after amsmath
1073         if (mustProvide("accents") &&
1074             params_.use_package("accents") != BufferParams::package_off)
1075                 packages << "\\usepackage{accents}\n";
1076
1077         // mathdots must be loaded after amsmath
1078         if (mustProvide("mathdots") &&
1079                 params_.use_package("mathdots") != BufferParams::package_off)
1080                 packages << "\\usepackage{mathdots}\n";
1081
1082         // yhmath must be loaded after amsmath
1083         if (mustProvide("yhmath") &&
1084             params_.use_package("yhmath") != BufferParams::package_off)
1085                 packages << "\\usepackage{yhmath}\n";
1086
1087         // stmaryrd must be loaded after amsmath
1088         if (mustProvide("stmaryrd") &&
1089             params_.use_package("stmaryrd") != BufferParams::package_off)
1090                 packages << "\\usepackage{stmaryrd}\n";
1091
1092         if (mustProvide("stackrel") &&
1093             params_.use_package("stackrel") != BufferParams::package_off)
1094                 packages << "\\usepackage{stackrel}\n";
1095
1096         if (mustProvide("undertilde") &&
1097                 params_.use_package("undertilde") != BufferParams::package_off)
1098                 packages << "\\usepackage{undertilde}\n";
1099
1100         // [x]color and pdfcolmk are handled in getColorOptions() above
1101
1102         // makeidx.sty
1103         if (isRequired("makeidx") || isRequired("splitidx")) {
1104                 if (!isProvided("makeidx") && !isRequired("splitidx"))
1105                         packages << "\\usepackage{makeidx}\n";
1106                 if (mustProvide("splitidx"))
1107                         packages << "\\usepackage{splitidx}\n";
1108                 packages << "\\makeindex\n";
1109         }
1110
1111         // graphicx.sty
1112         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
1113                 if (params_.graphics_driver == "default")
1114                         packages << "\\usepackage{graphicx}\n";
1115                 else
1116                         packages << "\\usepackage["
1117                                  << params_.graphics_driver
1118                                  << "]{graphicx}\n";
1119         }
1120
1121         // lyxskak.sty --- newer chess support based on skak.sty
1122         if (mustProvide("chess"))
1123                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
1124
1125         // setspace.sty
1126         if (mustProvide("setspace") && !isProvided("SetSpace"))
1127                 packages << "\\usepackage{setspace}\n";
1128
1129         // we need to assure that mhchem is loaded before esint and every other
1130         // package that redefines command of amsmath because mhchem loads amlatex
1131         // (this info is from the author of mhchem from June 2013)
1132         if (mustProvide("mhchem") &&
1133             params_.use_package("mhchem") != BufferParams::package_off)
1134                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
1135                             "\\usepackage{mhchem}\n";
1136
1137         // wasysym is a simple feature, but it must be after amsmath if both
1138         // are used
1139         // wasysym redefines some integrals (e.g. iint) from amsmath. That
1140         // leads to inconsistent integrals. We only load this package if
1141         // the document does not contain integrals (then isRequired("esint")
1142         // is false) or if esint is used, since esint redefines all relevant
1143         // integral symbols from wasysym and amsmath.
1144         // See http://www.lyx.org/trac/ticket/1942
1145         if (mustProvide("wasysym") &&
1146             params_.use_package("wasysym") != BufferParams::package_off &&
1147             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
1148                 packages << "\\usepackage{wasysym}\n";
1149
1150         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
1151         // and wasysym, since it will redeclare inconsistent integral symbols
1152         if (mustProvide("esint") &&
1153             params_.use_package("esint") != BufferParams::package_off)
1154                 packages << "\\usepackage{esint}\n";
1155
1156         // Known bibliography packages (simple \usepackage{package})
1157         for (int i = 0; i < nb_bibliofeatures; ++i) {
1158                 if (mustProvide(bibliofeatures[i]))
1159                         packages << "\\usepackage{"
1160                                  << bibliofeatures[i] << "}\n";
1161         }
1162
1163         // Compatibility between achicago and natbib
1164         if (mustProvide("achicago") && mustProvide("natbib"))
1165                 packages << "\\let\\achicagobib\\thebibliography\n";
1166
1167         // natbib.sty
1168         // Some classes load natbib themselves, but still allow (or even require)
1169         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1170         // This special case is indicated by the "natbib-internal" key.
1171         if (mustProvide("natbib") && !isProvided("natbib-internal")) {
1172                 packages << "\\usepackage[";
1173                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1174                         packages << "numbers";
1175                 else
1176                         packages << "authoryear";
1177                 packages << "]{natbib}\n";
1178         }
1179
1180         // Compatibility between achicago and natbib
1181         if (mustProvide("achicago") && mustProvide("natbib")) {
1182                 packages << "\\let\\thebibliography\\achicagobib\n";
1183                 packages << "\\let\\SCcite\\astroncite\n";
1184                 packages << "\\let\\UnexpandableProtect\\protect\n";
1185         }
1186
1187         // jurabib -- we need version 0.6 at least.
1188         if (mustProvide("jurabib"))
1189                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
1190
1191         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1192         if (mustProvide("opcit")) {
1193                 if (isRequired("hyperref"))
1194                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1195                 else
1196                         packages << "\\usepackage[custombst]{opcit}\n";
1197         }
1198
1199         // xargs -- we need version 1.09 at least
1200         if (mustProvide("xargs"))
1201                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1202
1203         if (mustProvide("xy"))
1204                 packages << "\\usepackage[all]{xy}\n";
1205
1206         if (mustProvide("feyn"))
1207                 packages << "\\usepackage{feyn}\n"; //Diagram
1208
1209         if (mustProvide("ulem"))
1210                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1211                             "\\usepackage{ulem}\n";
1212
1213         if (mustProvide("nomencl")) {
1214                 // Make it work with the new and old version of the package,
1215                 // but don't use the compatibility option since it is
1216                 // incompatible to other packages.
1217                 packages << "\\usepackage{nomencl}\n"
1218                             "% the following is useful when we have the old nomencl.sty package\n"
1219                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1220                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1221                             "\\makenomenclature\n";
1222         }
1223
1224         // fixltx2e provides subscript
1225         if (mustProvide("subscript") && !isRequired("fixltx2e"))
1226                 packages << "\\usepackage{subscript}\n";
1227
1228         // footmisc must be loaded after setspace
1229         // Set options here, load the package after the user preamble to
1230         // avoid problems with manual loaded footmisc.
1231         if (mustProvide("footmisc"))
1232                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1233
1234         if (mustProvide("microtype")){
1235                 packages << "\\usepackage{microtype}\n";
1236         }
1237
1238         return packages.str();
1239 }
1240
1241
1242 TexString LaTeXFeatures::getMacros() const
1243 {
1244         otexstringstream macros;
1245
1246         if (!preamble_snippets_.empty()) {
1247                 macros << '\n';
1248                 macros << getPreambleSnippets();
1249         }
1250
1251         if (mustProvide("papersize")) {
1252                 if (runparams_.flavor == OutputParams::LATEX
1253                     || runparams_.flavor == OutputParams::DVILUATEX)
1254                         macros << papersizedvi_def << '\n';
1255                 else if  (runparams_.flavor == OutputParams::LUATEX)
1256                         macros << papersizepdflua_def << '\n';
1257                 else
1258                         macros << papersizepdf_def << '\n';
1259         }
1260
1261         if (mustProvide("LyX")) {
1262                 if (isRequired("hyperref"))
1263                         macros << lyx_hyperref_def << '\n';
1264                 else
1265                         macros << lyx_def << '\n';
1266         }
1267
1268         if (mustProvide("noun"))
1269                 macros << noun_def << '\n';
1270
1271         if (mustProvide("lyxarrow"))
1272                 macros << lyxarrow_def << '\n';
1273
1274         if (!usePolyglossia() && mustProvide("textgreek")) {
1275                 // ensure LGR font encoding is defined also if fontenc is not loaded by LyX
1276                 if (params_.font_encoding() == "default")
1277                         macros << textgreek_LGR_def;
1278                 macros << textgreek_def << '\n';
1279         }
1280
1281         if (!usePolyglossia() && mustProvide("textcyr")) {
1282                 // ensure T2A font encoding is set up also if fontenc is not loaded by LyX
1283                 if (params_.font_encoding() == "default")
1284                         macros << textcyr_T2A_def;
1285                 macros << textcyr_def << '\n';
1286         }
1287
1288         // non-standard text accents:
1289         if (mustProvide("textcommaabove") || mustProvide("textcommaaboveright") ||
1290             mustProvide("textcommabelow") || mustProvide("textbaltic"))
1291                 macros << lyxaccent_def;
1292
1293         if (mustProvide("textcommabelow") || mustProvide("textbaltic"))
1294                 macros << textcommabelow_def << '\n';
1295
1296         if (mustProvide("textcommaabove") || mustProvide("textbaltic"))
1297                 macros << textcommaabove_def << '\n';
1298
1299         if (mustProvide("textcommaaboveright"))
1300                 macros << textcommaaboveright_def << '\n';
1301
1302         if (mustProvide("textbaltic"))
1303                 macros << textbaltic_def << '\n';
1304
1305         if (mustProvide("lyxmathsym"))
1306                 macros << lyxmathsym_def << '\n';
1307
1308         if (mustProvide("cedilla"))
1309                 macros << cedilla_def << '\n';
1310
1311         if (mustProvide("subring"))
1312                 macros << subring_def << '\n';
1313
1314         if (mustProvide("subdot"))
1315                 macros << subdot_def << '\n';
1316
1317         if (mustProvide("subhat"))
1318                 macros << subhat_def << '\n';
1319
1320         if (mustProvide("subtilde"))
1321                 macros << subtilde_def << '\n';
1322
1323         if (mustProvide("dacute"))
1324                 macros << dacute_def << '\n';
1325
1326         if (mustProvide("tipasymb"))
1327                 macros << tipasymb_def << '\n';
1328
1329         if (mustProvide("dgrave"))
1330                 macros << dgrave_def << '\n';
1331
1332         if (mustProvide("rcap"))
1333                 macros << rcap_def << '\n';
1334
1335         if (mustProvide("ogonek"))
1336                 macros << ogonek_def << '\n';
1337
1338         // quotes.
1339         if (mustProvide("quotesinglbase"))
1340                 macros << quotesinglbase_def << '\n';
1341         if (mustProvide("quotedblbase"))
1342                 macros << quotedblbase_def << '\n';
1343         if (mustProvide("guilsinglleft"))
1344                 macros << guilsinglleft_def << '\n';
1345         if (mustProvide("guilsinglright"))
1346                 macros << guilsinglright_def << '\n';
1347         if (mustProvide("guillemotleft"))
1348                 macros << guillemotleft_def << '\n';
1349         if (mustProvide("guillemotright"))
1350                 macros << guillemotright_def << '\n';
1351
1352         // Math mode
1353         if (mustProvide("binom") && !isRequired("amsmath"))
1354                 macros << binom_def << '\n';
1355         if (mustProvide("mathcircumflex"))
1356                 macros << mathcircumflex_def << '\n';
1357
1358         // other
1359         if (mustProvide("ParagraphLeftIndent"))
1360                 macros << paragraphleftindent_def;
1361         if (mustProvide("NeedLyXFootnoteCode"))
1362                 macros << floatingfootnote_def;
1363
1364         // some problems with tex->html converters
1365         if (mustProvide("NeedTabularnewline"))
1366                 macros << tabularnewline_def;
1367
1368         // greyed-out environment (note inset)
1369         // the color is specified in the routine
1370         // getColorOptions() to avoid LaTeX-package clashes
1371         if (mustProvide("lyxgreyedout"))
1372                 macros << lyxgreyedout_def;
1373
1374         if (mustProvide("lyxdot"))
1375                 macros << lyxdot_def << '\n';
1376
1377         // floats
1378         getFloatDefinitions(macros);
1379
1380         if (mustProvide("refstyle"))
1381                 macros << lyxref_def << '\n';
1382
1383         // change tracking
1384         if (mustProvide("ct-dvipost"))
1385                 macros << changetracking_dvipost_def;
1386
1387         if (mustProvide("ct-xcolor-ulem")) {
1388                 streamsize const prec = macros.os().precision(2);
1389
1390                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1391                 macros << "\\providecolor{lyxadded}{rgb}{"
1392                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1393
1394                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1395                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1396                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1397
1398                 macros.os().precision(prec);
1399
1400                 if (isRequired("hyperref"))
1401                         macros << changetracking_xcolor_ulem_hyperref_def;
1402                 else
1403                         macros << changetracking_xcolor_ulem_def;
1404         }
1405
1406         if (mustProvide("ct-tikz-math-sout"))
1407                         macros << changetracking_tikz_math_sout_def;
1408
1409         if (mustProvide("ct-none"))
1410                 macros << changetracking_none_def;
1411
1412         if (mustProvide("rtloutputdblcol"))
1413                 macros << rtloutputdblcol_def;
1414
1415         return macros.release();
1416 }
1417
1418
1419 docstring const LaTeXFeatures::getBabelPresettings() const
1420 {
1421         odocstringstream tmp;
1422
1423         for (Language const * lang : UsedLanguages_)
1424                 if (!lang->babel_presettings().empty())
1425                         tmp << lang->babel_presettings() << '\n';
1426         if (!params_.language->babel_presettings().empty())
1427                 tmp << params_.language->babel_presettings() << '\n';
1428
1429         if (!contains(tmp.str(), '@'))
1430                 return tmp.str();
1431
1432         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1433 }
1434
1435
1436 docstring const LaTeXFeatures::getBabelPostsettings() const
1437 {
1438         odocstringstream tmp;
1439
1440         for (Language const * lang : UsedLanguages_)
1441                 if (!lang->babel_postsettings().empty())
1442                         tmp << lang->babel_postsettings() << '\n';
1443         if (!params_.language->babel_postsettings().empty())
1444                 tmp << params_.language->babel_postsettings() << '\n';
1445
1446         if (!contains(tmp.str(), '@'))
1447                 return tmp.str();
1448
1449         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1450 }
1451
1452
1453 bool LaTeXFeatures::needBabelLangOptions() const
1454 {
1455         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1456                 return true;
1457
1458         LanguageList::const_iterator it  = UsedLanguages_.begin();
1459         LanguageList::const_iterator end = UsedLanguages_.end();
1460         for (; it != end; ++it)
1461                 if ((*it)->asBabelOptions())
1462                         return true;
1463
1464         return false;
1465 }
1466
1467
1468 string const LaTeXFeatures::loadAMSPackages() const
1469 {
1470         ostringstream tmp;
1471
1472         if (mustProvide("amsmath")
1473             && params_.use_package("amsmath") != BufferParams::package_off) {
1474                 tmp << "\\usepackage{amsmath}\n";
1475         } else {
1476                 // amsbsy and amstext are already provided by amsmath
1477                 if (mustProvide("amsbsy"))
1478                         tmp << "\\usepackage{amsbsy}\n";
1479                 if (mustProvide("amstext"))
1480                         tmp << "\\usepackage{amstext}\n";
1481         }
1482
1483         if (mustProvide("amsthm"))
1484                 tmp << "\\usepackage{amsthm}\n";
1485
1486         if (mustProvide("amssymb")
1487             && params_.use_package("amssymb") != BufferParams::package_off)
1488                 tmp << "\\usepackage{amssymb}\n";
1489
1490         return tmp.str();
1491 }
1492
1493
1494 docstring const LaTeXFeatures::getTClassPreamble() const
1495 {
1496         // the text class specific preamble
1497         DocumentClass const & tclass = params_.documentClass();
1498         odocstringstream tcpreamble;
1499
1500         tcpreamble << tclass.preamble();
1501
1502         list<docstring>::const_iterator cit = usedLayouts_.begin();
1503         list<docstring>::const_iterator end = usedLayouts_.end();
1504         for (; cit != end; ++cit)
1505                 tcpreamble << tclass[*cit].preamble();
1506
1507         cit = usedInsetLayouts_.begin();
1508         end = usedInsetLayouts_.end();
1509         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1510         for (; cit != end; ++cit) {
1511                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1512                 if (it == ils.end())
1513                         continue;
1514                 tcpreamble << it->second.preamble();
1515         }
1516
1517         return tcpreamble.str();
1518 }
1519
1520
1521 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1522 {
1523         DocumentClass const & tclass = params_.documentClass();
1524         odocstringstream tcpreamble;
1525
1526         tcpreamble << tclass.htmlpreamble();
1527
1528         list<docstring>::const_iterator cit = usedLayouts_.begin();
1529         list<docstring>::const_iterator end = usedLayouts_.end();
1530         for (; cit != end; ++cit)
1531                 tcpreamble << tclass[*cit].htmlpreamble();
1532
1533         cit = usedInsetLayouts_.begin();
1534         end = usedInsetLayouts_.end();
1535         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1536         for (; cit != end; ++cit) {
1537                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1538                 if (it == ils.end())
1539                         continue;
1540                 tcpreamble << it->second.htmlpreamble();
1541         }
1542
1543         return tcpreamble.str();
1544 }
1545
1546
1547 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1548 {
1549         DocumentClass const & tclass = params_.documentClass();
1550         odocstringstream tcpreamble;
1551
1552         if (mustProvide("noun"))
1553                 tcpreamble << lyxnoun_style;
1554         // this isn't exact, but it won't hurt that much if it
1555         // wasn't for this.
1556         if (mustProvide("ulem"))
1557                 tcpreamble << lyxstrikeout_style;
1558
1559         tcpreamble << tclass.htmlstyles();
1560
1561         list<docstring>::const_iterator cit = usedLayouts_.begin();
1562         list<docstring>::const_iterator end = usedLayouts_.end();
1563         for (; cit != end; ++cit)
1564                 tcpreamble << tclass[*cit].htmlstyle();
1565
1566         cit = usedInsetLayouts_.begin();
1567         end = usedInsetLayouts_.end();
1568         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1569         for (; cit != end; ++cit) {
1570                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1571                 if (it == ils.end())
1572                         continue;
1573                 tcpreamble << it->second.htmlstyle();
1574         }
1575
1576         return tcpreamble.str();
1577 }
1578
1579
1580 namespace {
1581
1582 docstring const getFloatI18nPreamble(docstring const & type,
1583                         docstring const & name, Language const * lang,
1584                         Encoding const & enc, bool const polyglossia)
1585 {
1586         // Check whether name can be encoded in the buffer encoding
1587         bool encodable = true;
1588         for (size_t i = 0; i < name.size(); ++i) {
1589                 if (!enc.encodable(name[i])) {
1590                         encodable = false;
1591                         break;
1592                 }
1593         }
1594
1595         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1596                                                : from_ascii(lang->babel());
1597         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1598         docstring const texenc = from_ascii(lang->encoding()->latexName());
1599         docstring const bufenc = from_ascii(enc.iconvName());
1600         docstring const s1 = docstring(1, 0xF0000);
1601         docstring const s2 = docstring(1, 0xF0001);
1602         docstring const translated = encodable ? name
1603                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1604                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1605
1606         odocstringstream os;
1607         os << "\\addto\\captions" << language
1608            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1609         return os.str();
1610 }
1611
1612
1613 docstring const i18npreamble(docstring const & templ, Language const * lang,
1614                              Encoding const & enc, bool const polyglossia,
1615                              bool const need_fixedwidth)
1616 {
1617         if (templ.empty())
1618                 return templ;
1619
1620         string preamble = polyglossia ?
1621                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1622                 subst(to_utf8(templ), "$$lang", lang->babel());
1623
1624         string const langenc = lang->encoding()->iconvName();
1625         string const texenc = lang->encoding()->latexName();
1626         string const bufenc = enc.iconvName();
1627         Encoding const * testenc(&enc);
1628         bool lang_fallback = false;
1629         bool ascii_fallback = false;
1630         if (need_fixedwidth && !enc.hasFixedWidth()) {
1631                 if (lang->encoding()->hasFixedWidth()) {
1632                         testenc = lang->encoding();
1633                         lang_fallback = true;
1634                 } else {
1635                         // We need a fixed width encoding, but both the buffer
1636                         // encoding and the language encoding are variable
1637                         // width. As a last fallback, try to convert to pure
1638                         // ASCII using the LaTeX commands defined in unicodesymbols.
1639                         testenc = encodings.fromLyXName("ascii");
1640                         if (!testenc)
1641                                 return docstring();
1642                         ascii_fallback = true;
1643                 }
1644         }
1645         // First and second character of plane 15 (Private Use Area)
1646         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1647         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1648         // FIXME UNICODE
1649         // lyx::regex is not unicode-safe.
1650         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1651         static regex const reg("_\\(([^\\)]+)\\)");
1652         smatch sub;
1653         while (regex_search(preamble, sub, reg)) {
1654                 string const key = sub.str(1);
1655                 docstring const name = lang->translateLayout(key);
1656                 // Check whether name can be encoded in the buffer encoding
1657                 bool encodable = true;
1658                 for (size_t i = 0; i < name.size() && encodable; ++i)
1659                         if (!testenc->encodable(name[i]))
1660                                 encodable = false;
1661                 string translated;
1662                 if (encodable && !lang_fallback)
1663                         translated = to_utf8(name);
1664                 else if (ascii_fallback)
1665                         translated = to_ascii(testenc->latexString(name).first);
1666                 else
1667                         translated = "\\inputencoding{" + texenc + "}"
1668                                 + s1 + langenc + s2 + to_utf8(name)
1669                                 + s1 + bufenc + s2;
1670                 preamble = subst(preamble, sub.str(), translated);
1671         }
1672         return from_utf8(preamble);
1673 }
1674
1675 }
1676
1677
1678 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1679 {
1680         DocumentClass const & tclass = params_.documentClass();
1681         // collect preamble snippets in a set to prevent multiple identical
1682         // commands (would happen if e.g. both theorem and theorem* are used)
1683         set<docstring> snippets;
1684         typedef LanguageList::const_iterator lang_it;
1685         lang_it const lbeg = UsedLanguages_.begin();
1686         lang_it const lend =  UsedLanguages_.end();
1687         list<docstring>::const_iterator cit = usedLayouts_.begin();
1688         list<docstring>::const_iterator end = usedLayouts_.end();
1689         for (; cit != end; ++cit) {
1690                 // language dependent commands (once per document)
1691                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1692                                                 buffer().language(),
1693                                                 buffer().params().encoding(),
1694                                                 use_polyglossia, false));
1695                 // commands for language changing (for multilanguage documents)
1696                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1697                         snippets.insert(i18npreamble(
1698                                                 tclass[*cit].babelpreamble(),
1699                                                 buffer().language(),
1700                                                 buffer().params().encoding(),
1701                                                 use_polyglossia, false));
1702                         for (lang_it lit = lbeg; lit != lend; ++lit)
1703                                 snippets.insert(i18npreamble(
1704                                                 tclass[*cit].babelpreamble(),
1705                                                 *lit,
1706                                                 buffer().params().encoding(),
1707                                                 use_polyglossia, false));
1708                 }
1709         }
1710         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1711                 FloatList const & floats = params_.documentClass().floats();
1712                 UsedFloats::const_iterator fit = usedFloats_.begin();
1713                 UsedFloats::const_iterator fend = usedFloats_.end();
1714                 for (; fit != fend; ++fit) {
1715                         Floating const & fl = floats.getType(fit->first);
1716                         // we assume builtin floats are translated
1717                         if (fl.isPredefined())
1718                                 continue;
1719                         docstring const type = from_ascii(fl.floattype());
1720                         docstring const flname = from_utf8(fl.name());
1721                         docstring name = buffer().language()->translateLayout(fl.name());
1722                         // only request translation if we have a real translation
1723                         // (that differs from the source)
1724                         if (flname != name)
1725                                 snippets.insert(getFloatI18nPreamble(
1726                                                 type, name, buffer().language(),
1727                                                 buffer().params().encoding(),
1728                                                 use_polyglossia));
1729                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1730                                 string const code = (*lit)->code();
1731                                 name = (*lit)->translateLayout(fl.name());
1732                                 // we assume we have a suitable translation if
1733                                 // either the language is English (we need to
1734                                 // translate into English if English is a secondary
1735                                 // language) or if translateIfPossible returns
1736                                 // something different to the English source.
1737                                 bool const have_translation =
1738                                         (flname != name || contains(code, "en"));
1739                                 if (have_translation)
1740                                         snippets.insert(getFloatI18nPreamble(
1741                                                 type, name, *lit,
1742                                                 buffer().params().encoding(),
1743                                                 use_polyglossia));
1744                         }
1745                 }
1746         }
1747
1748         cit = usedInsetLayouts_.begin();
1749         end = usedInsetLayouts_.end();
1750         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1751         for (; cit != end; ++cit) {
1752                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1753                 if (it == ils.end())
1754                         continue;
1755                 // The listings package does not work with variable width
1756                 // encodings, only with fixed width encodings. Therefore we
1757                 // need to force a fixed width encoding for
1758                 // \lstlistlistingname and \lstlistingname (bug 9382).
1759                 // This needs to be consistent with InsetListings::latex().
1760                 bool const need_fixedwidth = !runparams_.isFullUnicode() &&
1761                                 it->second.fixedwidthpreambleencoding();
1762                 // language dependent commands (once per document)
1763                 snippets.insert(i18npreamble(it->second.langpreamble(),
1764                                                 buffer().language(),
1765                                                 buffer().params().encoding(),
1766                                                 use_polyglossia, need_fixedwidth));
1767                 // commands for language changing (for multilanguage documents)
1768                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1769                         snippets.insert(i18npreamble(
1770                                                 it->second.babelpreamble(),
1771                                                 buffer().language(),
1772                                                 buffer().params().encoding(),
1773                                                 use_polyglossia, need_fixedwidth));
1774                         for (lang_it lit = lbeg; lit != lend; ++lit)
1775                                 snippets.insert(i18npreamble(
1776                                                 it->second.babelpreamble(),
1777                                                 *lit,
1778                                                 buffer().params().encoding(),
1779                                                 use_polyglossia, need_fixedwidth));
1780                 }
1781         }
1782
1783         odocstringstream tcpreamble;
1784         set<docstring>::const_iterator const send = snippets.end();
1785         set<docstring>::const_iterator it = snippets.begin();
1786         for (; it != send; ++it)
1787                 tcpreamble << *it;
1788         return tcpreamble.str();
1789 }
1790
1791
1792 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1793 {
1794         // Definition of entities used in the document that are LyX related.
1795         odocstringstream entities;
1796
1797         if (mustProvide("lyxarrow")) {
1798                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1799         }
1800
1801         return entities.str();
1802 }
1803
1804
1805 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1806 {
1807         odocstringstream sgmlpreamble;
1808         // FIXME UNICODE
1809         docstring const basename(from_utf8(onlyPath(fname)));
1810
1811         FileMap::const_iterator end = IncludedFiles_.end();
1812         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1813              fi != end; ++fi)
1814                 // FIXME UNICODE
1815                 sgmlpreamble << "\n<!ENTITY " << fi->first
1816                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1817                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1818
1819         return sgmlpreamble.str();
1820 }
1821
1822
1823 void LaTeXFeatures::showStruct() const
1824 {
1825         lyxerr << "LyX needs the following commands when LaTeXing:"
1826                << "\n***** Packages:" << getPackages()
1827                << "\n***** Macros:" << to_utf8(getMacros().str)
1828                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1829                << "\n***** done." << endl;
1830 }
1831
1832
1833 Buffer const & LaTeXFeatures::buffer() const
1834 {
1835         return *buffer_;
1836 }
1837
1838
1839 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1840 {
1841         buffer_ = &buffer;
1842 }
1843
1844
1845 BufferParams const & LaTeXFeatures::bufferParams() const
1846 {
1847         return params_;
1848 }
1849
1850
1851 void LaTeXFeatures::getFloatDefinitions(otexstream & os) const
1852 {
1853         FloatList const & floats = params_.documentClass().floats();
1854
1855         // Here we will output the code to create the needed float styles.
1856         // We will try to do this as minimal as possible.
1857         // \floatstyle{ruled}
1858         // \newfloat{algorithm}{htbp}{loa}
1859         // \providecommand{\algorithmname}{Algorithm}
1860         // \floatname{algorithm}{\protect\algorithmname}
1861         UsedFloats::const_iterator cit = usedFloats_.begin();
1862         UsedFloats::const_iterator end = usedFloats_.end();
1863         for (; cit != end; ++cit) {
1864                 Floating const & fl = floats.getType(cit->first);
1865
1866                 // For builtin floats we do nothing.
1867                 if (fl.isPredefined())
1868                         continue;
1869
1870                 // We have to special case "table" and "figure"
1871                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1872                         // Output code to modify "table" or "figure"
1873                         // but only if builtin == false
1874                         // and that have to be true at this point in the
1875                         // function.
1876                         docstring const type = from_ascii(fl.floattype());
1877                         docstring const placement = from_ascii(fl.placement());
1878                         docstring const style = from_ascii(fl.style());
1879                         if (!style.empty()) {
1880                                 os << "\\floatstyle{" << style << "}\n"
1881                                    << "\\restylefloat{" << type << "}\n";
1882                         }
1883                         if (!placement.empty()) {
1884                                 os << "\\floatplacement{" << type << "}{"
1885                                    << placement << "}\n";
1886                         }
1887                 } else {
1888                         // The other non builtin floats.
1889
1890                         docstring const type = from_ascii(fl.floattype());
1891                         docstring const placement = from_ascii(fl.placement());
1892                         docstring const ext = from_ascii(fl.ext());
1893                         docstring const within = from_ascii(fl.within());
1894                         docstring const style = from_ascii(fl.style());
1895                         docstring const name =
1896                                 buffer().language()->translateLayout(fl.name());
1897                         os << "\\floatstyle{" << style << "}\n"
1898                            << "\\newfloat{" << type << "}{" << placement
1899                            << "}{" << ext << '}';
1900                         if (!within.empty())
1901                                 os << '[' << within << ']';
1902                         os << '\n'
1903                            << "\\providecommand{\\" << type << "name}{"
1904                            << name << "}\n"
1905                            << "\\floatname{" << type << "}{\\protect\\"
1906                            << type << "name}\n";
1907
1908                         // What missing here is to code to minimalize the code
1909                         // output so that the same floatstyle will not be
1910                         // used several times, when the same style is still in
1911                         // effect. (Lgb)
1912                 }
1913                 if (cit->second)
1914                         // The subfig package is loaded later
1915                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
1916         }
1917 }
1918
1919
1920 void LaTeXFeatures::resolveAlternatives()
1921 {
1922         for (Features::iterator it = features_.begin(); it != features_.end();) {
1923                 if (contains(*it, '|')) {
1924                         vector<string> const alternatives = getVectorFromString(*it, "|");
1925                         vector<string>::const_iterator const end = alternatives.end();
1926                         vector<string>::const_iterator ita = alternatives.begin();
1927                         // Is any alternative already required? => use that
1928                         for (; ita != end; ++ita) {
1929                                 if (isRequired(*ita))
1930                                         break;
1931                         }
1932                         // Is any alternative available? => use the first one
1933                         // (bug 9498)
1934                         if (ita == end) {
1935                                 for (ita = alternatives.begin(); ita != end; ++ita) {
1936                                         if (isAvailable(*ita)) {
1937                                                 require(*ita);
1938                                                 break;
1939                                         }
1940                                 }
1941                         }
1942                         // This will not work, but not requiring something
1943                         // would be more confusing
1944                         if (ita == end)
1945                                 require(alternatives.front());
1946                         features_.erase(it);
1947                         it = features_.begin();
1948                 } else
1949                         ++it;
1950         }
1951 }
1952
1953
1954 void LaTeXFeatures::expandMultiples()
1955 {
1956         for (Features::iterator it = features_.begin(); it != features_.end();) {
1957                 if (contains(*it, ',')) {
1958                         vector<string> const multiples = getVectorFromString(*it, ",");
1959                         vector<string>::const_iterator const end = multiples.end();
1960                         vector<string>::const_iterator itm = multiples.begin();
1961                         // Do nothing if any multiple is already required
1962                         for (; itm != end; ++itm) {
1963                                 if (!isRequired(*itm))
1964                                         require(*itm);
1965                         }
1966                         features_.erase(it);
1967                         it = features_.begin();
1968                 } else
1969                         ++it;
1970         }
1971 }
1972
1973
1974 } // namespace lyx