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