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