]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Rework language package detection
[lyx.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "LaTeXPackages.h"
28 #include "Layout.h"
29 #include "Lexer.h"
30 #include "LyXRC.h"
31 #include "TextClass.h"
32
33 #include "insets/InsetLayout.h"
34
35 #include "support/debug.h"
36 #include "support/docstream.h"
37 #include "support/FileName.h"
38 #include "support/filetools.h"
39 #include "support/gettext.h"
40 #include "support/lstrings.h"
41 #include "support/regex.h"
42
43 #include <algorithm>
44
45
46 using namespace std;
47 using namespace lyx::support;
48
49
50 namespace lyx {
51
52 /////////////////////////////////////////////////////////////////////
53 //
54 // Strings
55 //
56 /////////////////////////////////////////////////////////////////////
57
58 //\NeedsTeXFormat{LaTeX2e}
59 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
60 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
61
62 static docstring const lyx_def = from_ascii(
63         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
64
65 static docstring const lyx_hyperref_def = from_ascii(
66         "\\providecommand{\\LyX}{\\texorpdfstring%\n"
67         "  {L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}\n"
68         "  {LyX}}");
69
70 static docstring const noun_def = from_ascii(
71         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
72
73 static docstring const lyxarrow_def = from_ascii(
74         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
75         "\\@ifstar\n"
76         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
77         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
78
79 // for quotes without babel. This does not give perfect results, but
80 // anybody serious about non-english quotes should use babel (JMarc).
81
82 static docstring const quotedblbase_def = from_ascii(
83         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
84         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
85         "  \\penalty10000\\hskip0em\\relax%\n"
86         "}");
87
88 static docstring const quotesinglbase_def = from_ascii(
89         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
90         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
91         "  \\penalty10000\\hskip0em\\relax%\n"
92         "}");
93
94 static docstring const guillemotleft_def = from_ascii(
95         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
96         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
97         "\\penalty10000\\hskip0pt\\relax%\n"
98         "}");
99
100 static docstring const guillemotright_def = from_ascii(
101         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
102         "  \\penalty10000\\hskip0pt%\n"
103         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
104         "}");
105
106 static docstring const guilsinglleft_def = from_ascii(
107         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
108         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
109         "  \\penalty10000\\hskip0pt\\relax%\n"
110         "}");
111
112 static docstring const guilsinglright_def = from_ascii(
113         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
114         "  \\penalty10000\\hskip0pt%\n"
115         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
116         "}");
117
118 static docstring const paragraphleftindent_def = from_ascii(
119         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
120         "{\n"
121         "  \\begin{list}{}{%\n"
122         "    \\setlength{\\topsep}{0pt}%\n"
123         "    \\addtolength{\\leftmargin}{#1}\n"
124 // ho hum, yet more things commented out with no hint as to why they
125 // weren't just removed
126 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
127 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
128 //      "%%    \\setlength\\listparindent\\parindent%\n"
129 //      "%%    \\setlength\\itemindent\\parindent%\n"
130         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
131         "  }\n"
132         "  \\item[]\n"
133         "}\n"
134         "{\\end{list}}\n");
135
136 static docstring const floatingfootnote_def = from_ascii(
137         "%% Special footnote code from the package 'stblftnt.sty'\n"
138         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
139         "\\let\\SF@@footnote\\footnote\n"
140         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
141         "    \\expandafter\\SF@@footnote\n"
142         "  \\else\n"
143         "    \\expandafter\\SF@gobble@opt\n"
144         "  \\fi\n"
145         "}\n"
146         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
147         "  \\SF@gobble@twobracket\n"
148         "  \\@gobble\n"
149         "}\n"
150         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
151         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
152         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
153
154 static docstring const binom_def = from_ascii(
155         "%% Binom macro for standard LaTeX users\n"
156         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
157
158 static docstring const mathcircumflex_def = from_ascii(
159         "%% For printing a cirumflex inside a formula\n"
160         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
161
162 static docstring const tabularnewline_def = from_ascii(
163         "%% Because html converters don't know tabularnewline\n"
164         "\\providecommand{\\tabularnewline}{\\\\}\n");
165
166 static docstring const lyxgreyedout_def = from_ascii(
167         "%% The greyedout annotation environment\n"
168         "\\newenvironment{lyxgreyedout}\n"
169         "  {\\textcolor{note_fontcolor}\\bgroup\\ignorespaces}\n"
170         "  {\\ignorespacesafterend\\egroup}\n");
171
172 // We want to omit the file extension for includegraphics, but this does not
173 // work when the filename contains other dots.
174 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
175 static docstring const lyxdot_def = from_ascii(
176         "%% A simple dot to overcome graphicx limitations\n"
177         "\\newcommand{\\lyxdot}{.}\n");
178
179 static docstring const changetracking_dvipost_def = from_ascii(
180         "%% Change tracking with dvipost\n"
181         "\\dvipostlayout\n"
182         "\\dvipost{osstart color push Red}\n"
183         "\\dvipost{osend color pop}\n"
184         "\\dvipost{cbstart color push Blue}\n"
185         "\\dvipost{cbend color pop}\n"
186         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
187         "\\newcommand{\\lyxdeleted}[3]{%\n"
188         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
189
190 static docstring const changetracking_xcolor_ulem_def = from_ascii(
191         "%% Change tracking with ulem\n"
192         "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
193         "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
194
195 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
196         "%% Change tracking with ulem\n"
197         "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
198         "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
199
200 static docstring const changetracking_none_def = from_ascii(
201         "\\newcommand{\\lyxadded}[3]{#3}\n"
202         "\\newcommand{\\lyxdeleted}[3]{}\n");
203
204 static docstring const textgreek_def = from_ascii(
205         "\\DeclareRobustCommand{\\greektext}{%\n"
206         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
207         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
208         "\\DeclareFontEncoding{LGR}{}{}\n"
209         "\\DeclareTextSymbol{\\~}{LGR}{126}");
210
211 static docstring const textcyr_def = from_ascii(
212         "\\DeclareRobustCommand{\\cyrtext}{%\n"
213         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
214         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
215         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
216
217 static docstring const lyxmathsym_def = from_ascii(
218         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
219         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
220
221 static docstring const papersizedvi_def = from_ascii(
222         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
223
224 static docstring const papersizepdf_def = from_ascii(
225         "\\pdfpageheight\\paperheight\n"
226         "\\pdfpagewidth\\paperwidth\n");
227
228 static docstring const cedilla_def = from_ascii(
229         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
230         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
231
232 static docstring const subring_def = from_ascii(
233         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
234         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
235
236 static docstring const subdot_def = from_ascii(
237         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
238         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
239
240 static docstring const subhat_def = from_ascii(
241         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
242         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
243
244 static docstring const subtilde_def = from_ascii(
245         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
246         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
247
248 static docstring const dacute_def = from_ascii(
249         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
250
251 static docstring const tipasymb_def = from_ascii(
252         "\\DeclareFontEncoding{T3}{}{}\n"
253         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
254
255 static docstring const dgrave_def = from_ascii(
256         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
257
258 static docstring const rcap_def = from_ascii(
259         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
260
261 static docstring const ogonek_def = from_ascii(
262         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
263         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
264         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
265         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
266         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
267
268 static docstring const lyxref_def = from_ascii(
269                 "\\RS@ifundefined{subref}\n"
270                 "  {\\def\\RSsubtxt{section~}\\newref{sub}{name = \\RSsubtxt}}\n"
271                 "  {}\n"
272                 "\\RS@ifundefined{thmref}\n"
273                 "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
274                 "  {}\n"
275                 "\\RS@ifundefined{lemref}\n"
276                 "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n" 
277                 "  {}\n");
278
279
280 /////////////////////////////////////////////////////////////////////
281 //
282 // LaTeXFeatures
283 //
284 /////////////////////////////////////////////////////////////////////
285
286
287 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
288                              OutputParams const & r)
289         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
290 {}
291
292
293 LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const
294 {
295         string const local_lp = bufferParams().lang_package;
296
297         // Locally, custom is just stored as a string
298         // in bufferParams().lang_package.
299         if (local_lp != "auto"
300             && local_lp != "babel"
301             && local_lp != "default"
302             && local_lp != "none")
303                  return LANG_PACK_CUSTOM;
304
305         if (local_lp == "none")
306                 return LANG_PACK_NONE;
307
308         /* If "auto" is selected, we load polyglossia if required,
309          * else we select babel.
310          * If babel is selected (either directly or via the "auto"
311          * mechanism), we really do only require it if we have
312          * a language that needs it.
313          */
314         bool const polyglossia_required =
315                 isRequired("polyglossia")
316                 && isAvailable("polyglossia")
317                 && !params_.documentClass().provides("babel")
318                 && this->hasOnlyPolyglossiaLanguages();
319         bool const babel_required = 
320                 (bufferParams().language->lang() != lyxrc.default_language
321                  && !bufferParams().language->babel().empty())
322                 || !this->getBabelLanguages().empty();
323
324         if (local_lp == "auto") {
325                 // polyglossia requirement has priority over babel
326                 if (polyglossia_required)
327                         return LANG_PACK_POLYGLOSSIA;
328                 else if (babel_required)
329                         return LANG_PACK_BABEL;
330         }
331
332         if (local_lp == "babel") {
333                 if (babel_required)
334                         return LANG_PACK_BABEL;
335         }
336
337         if (local_lp == "default") {
338                 switch (lyxrc.language_package_selection) {
339                 case LyXRC::LP_AUTO:
340                         // polyglossia requirement has priority over babel
341                         if (polyglossia_required)
342                                 return LANG_PACK_POLYGLOSSIA;
343                         else if (babel_required)
344                                 return LANG_PACK_BABEL;
345                 case LyXRC::LP_BABEL:
346                         if (babel_required)
347                                 return LANG_PACK_BABEL;
348                 case LyXRC::LP_CUSTOM:
349                         return LANG_PACK_CUSTOM;
350                 case LyXRC::LP_NONE:
351                         return LANG_PACK_NONE;
352                 }
353         }
354
355         return LANG_PACK_NONE;
356 }
357
358
359 void LaTeXFeatures::require(string const & name)
360 {
361         features_.insert(name);
362 }
363
364
365 void LaTeXFeatures::require(set<string> const & names)
366 {
367         features_.insert(names.begin(), names.end());
368 }
369
370
371 void LaTeXFeatures::useLayout(docstring const & layoutname)
372 {
373         // Some code to avoid loops in dependency definition
374         static int level = 0;
375         const int maxlevel = 30;
376         if (level > maxlevel) {
377                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
378                        << "recursion attained by layout "
379                        << to_utf8(layoutname) << endl;
380                 return;
381         }
382
383         DocumentClass const & tclass = params_.documentClass();
384         if (tclass.hasLayout(layoutname)) {
385                 // Is this layout already in usedLayouts?
386                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
387                     != usedLayouts_.end())
388                         return;
389
390                 Layout const & layout = tclass[layoutname];
391                 require(layout.requires());
392
393                 if (!layout.depends_on().empty()) {
394                         ++level;
395                         useLayout(layout.depends_on());
396                         --level;
397                 }
398                 usedLayouts_.push_back(layoutname);
399         } else {
400                 lyxerr << "LaTeXFeatures::useLayout: layout `"
401                        << to_utf8(layoutname) << "' does not exist in this class"
402                        << endl;
403         }
404
405         --level;
406 }
407
408
409 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
410 {
411         docstring const & lname = lay.name();
412         DocumentClass const & tclass = params_.documentClass();
413
414         // this is a default inset layout, nothing useful here
415         if (!tclass.hasInsetLayout(lname))
416                 return;
417         // Is this layout already in usedInsetLayouts?
418         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
419                         != usedInsetLayouts_.end())
420                 return;
421
422         require(lay.requires());
423         usedInsetLayouts_.push_back(lname);
424 }
425
426
427 bool LaTeXFeatures::isRequired(string const & name) const
428 {
429         return features_.find(name) != features_.end();
430 }
431
432
433 bool LaTeXFeatures::mustProvide(string const & name) const
434 {
435         return isRequired(name) && !params_.documentClass().provides(name);
436 }
437
438
439 bool LaTeXFeatures::isAvailable(string const & name)
440 {
441         string::size_type const i = name.find("->");
442         if (i != string::npos) {
443                 string const from = name.substr(0,i);
444                 string const to = name.substr(i+2);
445                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
446                 return theConverters().isReachable(from, to);
447         }
448         return LaTeXPackages::isAvailable(name);
449 }
450
451
452 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
453 {
454         SnippetList::const_iterator begin = preamble_snippets_.begin();
455         SnippetList::const_iterator end   = preamble_snippets_.end();
456         if (find(begin, end, preamble) == end)
457                 preamble_snippets_.push_back(preamble);
458 }
459
460
461 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
462 {
463         SnippetList::const_iterator begin = css_snippets_.begin();
464         SnippetList::const_iterator end   = css_snippets_.end();
465         if (find(begin, end, snippet) == end)
466                 css_snippets_.push_back(snippet);
467 }
468
469
470 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
471 {
472         if (!usedFloats_[name])
473                 usedFloats_[name] = subfloat;
474         if (subfloat)
475                 require("subfig");
476         // We only need float.sty if we use non builtin floats, or if we
477         // use the "H" modifier. This includes modified table and
478         // figure floats. (Lgb)
479         Floating const & fl = params_.documentClass().floats().getType(name);
480         if (!fl.floattype().empty() && fl.usesFloatPkg()) {
481                 require("float");
482         }
483 }
484
485
486 void LaTeXFeatures::useLanguage(Language const * lang)
487 {
488         if (!lang->babel().empty() || !lang->polyglossia().empty())
489                 UsedLanguages_.insert(lang);
490         if (!lang->requires().empty())
491                 require(lang->requires());
492         // CJK languages do not have a babel name.
493         // They use the CJK package
494         if (lang->encoding()->package() == Encoding::CJK)
495                 require("CJK");
496         // japanese package is special
497         if (lang->encoding()->package() == Encoding::japanese)
498                 require("japanese");
499 }
500
501
502 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
503 {
504         IncludedFiles_[key] = name;
505 }
506
507
508 bool LaTeXFeatures::hasLanguages() const
509 {
510         return !UsedLanguages_.empty();
511 }
512
513
514 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
515 {
516         LanguageList::const_iterator const begin = UsedLanguages_.begin();
517         for (LanguageList::const_iterator cit = begin;
518              cit != UsedLanguages_.end();
519              ++cit) {
520                 if ((*cit)->polyglossia().empty())
521                         return false;
522         }
523         return true;
524 }
525
526
527 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
528 {
529         LanguageList::const_iterator const begin = UsedLanguages_.begin();
530         for (LanguageList::const_iterator cit = begin;
531              cit != UsedLanguages_.end();
532              ++cit) {
533                 if ((*cit)->babel().empty() && !(*cit)->polyglossia().empty() && (*cit)->requires().empty())
534                         return true;
535         }
536         return false;
537 }
538
539
540 string LaTeXFeatures::getBabelLanguages() const
541 {
542         ostringstream languages;
543
544         bool first = true;
545         LanguageList::const_iterator const begin = UsedLanguages_.begin();
546         for (LanguageList::const_iterator cit = begin;
547              cit != UsedLanguages_.end();
548              ++cit) {
549                 if ((*cit)->babel().empty())
550                         continue;
551                 if (!first)
552                         languages << ',';
553                 else
554                         first = false;
555                 languages << (*cit)->babel();
556         }
557         return languages.str();
558 }
559
560
561 std::map<std::string, std::string> LaTeXFeatures::getPolyglossiaLanguages() const
562 {
563         std::map<std::string, std::string> languages;
564
565         LanguageList::const_iterator const begin = UsedLanguages_.begin();
566         for (LanguageList::const_iterator cit = begin;
567              cit != UsedLanguages_.end();
568              ++cit) {
569                 languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts();
570         }
571         return languages;
572 }
573
574
575 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
576 {
577         // This does only find encodings of languages supported by babel, but
578         // that does not matter since we don't have a language with an
579         // encoding supported by inputenc but without babel support.
580         set<string> encodings;
581         LanguageList::const_iterator it  = UsedLanguages_.begin();
582         LanguageList::const_iterator end = UsedLanguages_.end();
583         for (; it != end; ++it)
584                 if ((*it)->encoding()->latexName() != doc_encoding &&
585                     ((*it)->encoding()->package() == Encoding::inputenc
586                      || (*it)->encoding()->package() == Encoding::japanese))
587                         encodings.insert((*it)->encoding()->latexName());
588         return encodings;
589 }
590
591 namespace {
592
593 char const * simplefeatures[] = {
594 // note that the package order here will be the same in the LaTeX-output
595         "array",
596         "verbatim",
597         "longtable",
598         "rotating",
599         "latexsym",
600         "pifont",
601         // subfig is handled in BufferParams.cpp
602         "varioref",
603         "prettyref",
604         "refstyle",
605         /*For a successful cooperation of the `wrapfig' package with the
606           `float' package you should load the `wrapfig' package *after*
607           the `float' package. See the caption package documentation
608           for explanation.*/
609         "float",
610         "rotfloat",
611         "wrapfig",
612         "booktabs",
613         "dvipost",
614         "fancybox",
615         "calc",
616         "units",
617         "tipa",
618         "tipx",
619         "framed",
620         "soul",
621         "textcomp",
622         "pmboxdraw",
623         "bbding",
624         "ifsym",
625         "marvosym",
626         "txfonts",
627         "pxfonts",
628         "mathdesign",
629         "mathrsfs",
630         "mathabx",
631         "mathtools",
632         "cancel",
633         "ascii",
634         "url",
635         "covington",
636         "csquotes",
637         "enumitem",
638         "endnotes",
639         "hhline",
640         "ifthen",
641         // listings is handled in BufferParams.cpp
642         "bm",
643         "pdfpages",
644         "amscd",
645         "slashed",
646         "multirow",
647         "tfrupee"
648 };
649
650 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
651
652 }
653
654
655 string const LaTeXFeatures::getColorOptions() const
656 {
657         ostringstream colors;
658
659         // Handling the color packages separately is needed to be able to load them
660         // before babel when hyperref is loaded with the colorlinks option
661         // for more info see Bufferparams.cpp
662
663         // [x]color.sty
664         if (mustProvide("color") || mustProvide("xcolor")) {
665                 string const package =
666                         (mustProvide("xcolor") ? "xcolor" : "color");
667                 if (params_.graphics_driver == "default"
668                         || params_.graphics_driver == "none")
669                         colors << "\\usepackage{" << package << "}\n";
670                 else
671                         colors << "\\usepackage["
672                                  << params_.graphics_driver
673                                  << "]{" << package << "}\n";
674         }
675
676         // pdfcolmk must be loaded after color
677         if (mustProvide("pdfcolmk"))
678                 colors << "\\usepackage{pdfcolmk}\n";
679
680         // the following 3 color commands must be set after color
681         // is loaded and before pdfpages, therefore add the command
682         // here define the set color
683         if (mustProvide("pagecolor")) {
684                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
685                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
686                 // set the page color
687                 colors << "\\pagecolor{page_backgroundcolor}\n";
688         }
689
690         if (mustProvide("fontcolor")) {
691                 colors << "\\definecolor{document_fontcolor}{rgb}{";
692                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
693                 // set the color
694                 colors << "\\color{document_fontcolor}\n";
695         }
696
697         if (mustProvide("lyxgreyedout")) {
698                 colors << "\\definecolor{note_fontcolor}{rgb}{";
699                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
700                 // the color will be set together with the definition of
701                 // the lyxgreyedout environment (see lyxgreyedout_def)
702         }
703
704         // color for shaded boxes
705         if (isRequired("framed") && mustProvide("color")) {
706                 colors << "\\definecolor{shadecolor}{rgb}{";
707                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
708                 // this color is automatically used by the LaTeX-package "framed"
709         }
710
711         return colors.str();
712 }
713
714
715 string const LaTeXFeatures::getPackages() const
716 {
717         ostringstream packages;
718         DocumentClass const & tclass = params_.documentClass();
719
720         // FIXME: currently, we can only load packages and macros known
721         // to LyX.
722         // However, with the Require tag of layouts/custom insets,
723         // also unknown packages can be requested. They are silently
724         // swallowed now. We should change this eventually.
725
726         //
727         //  These are all the 'simple' includes.  i.e
728         //  packages which we just \usepackage{package}
729         //
730         for (int i = 0; i < nb_simplefeatures; ++i) {
731                 if (mustProvide(simplefeatures[i]))
732                         packages << "\\usepackage{"
733                                  << simplefeatures[i] << "}\n";
734         }
735
736         //
737         // The rest of these packages are somewhat more complicated
738         // than those above.
739         //
740
741         // if fontspec is used, AMS packages have to be loaded before
742         // fontspec (in BufferParams)
743         string const amsPackages = loadAMSPackages();
744         if (!params_.useNonTeXFonts && !amsPackages.empty())
745                 packages << amsPackages;
746
747         // fixltx2e must be loaded after amsthm, since amsthm produces an error with
748         // the redefined \[ command (bug 7233). Load it as early as possible, since
749         // other packages might profit from it.
750         if (mustProvide("fixltx2e"))
751                 packages << "\\usepackage{fixltx2e}\n";
752
753         // wasysym is a simple feature, but it must be after amsmath if both
754         // are used
755         // wasysym redefines some integrals (e.g. iint) from amsmath. That
756         // leads to inconsistent integrals. We only load this package if
757         // the document does not contain integrals (then isRequired("esint")
758         // is false) or if esint is used, since esint redefines all relevant
759         // integral symbols from wasysym and amsmath.
760         // See http://www.lyx.org/trac/ticket/1942
761         if (mustProvide("wasysym") &&
762             params_.use_package("wasysym") != BufferParams::package_off &&
763             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
764                 packages << "\\usepackage{wasysym}\n";
765
766         // accents must be loaded after amsmath
767         if (mustProvide("accents") &&
768             params_.use_package("accents") != BufferParams::package_off)
769                 packages << "\\usepackage{accents}\n";
770
771         // mathdots must be loaded after amsmath
772         if (mustProvide("mathdots") &&
773                 params_.use_package("mathdots") != BufferParams::package_off)
774                 packages << "\\usepackage{mathdots}\n";
775
776         // yhmath must be loaded after amsmath
777         if (mustProvide("yhmath") &&
778             params_.use_package("yhmath") != BufferParams::package_off)
779                 packages << "\\usepackage{yhmath}\n";
780
781         if (mustProvide("undertilde") &&
782                 params_.use_package("undertilde") != BufferParams::package_off)
783                 packages << "\\usepackage{undertilde}\n";
784
785         // [x]color and pdfcolmk are handled in getColorOptions() above
786
787         // makeidx.sty
788         if (isRequired("makeidx") || isRequired("splitidx")) {
789                 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
790                         packages << "\\usepackage{makeidx}\n";
791                 if (!tclass.provides("splitidx") && isRequired("splitidx"))
792                         packages << "\\usepackage{splitidx}\n";
793                 packages << "\\makeindex\n";
794         }
795
796         // graphicx.sty
797         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
798                 if (params_.graphics_driver == "default")
799                         packages << "\\usepackage{graphicx}\n";
800                 else
801                         packages << "\\usepackage["
802                                  << params_.graphics_driver
803                                  << "]{graphicx}\n";
804         }
805
806         // lyxskak.sty --- newer chess support based on skak.sty
807         if (mustProvide("chess"))
808                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
809
810         // setspace.sty
811         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
812                 packages << "\\usepackage{setspace}\n";
813
814         // esint must be after amsmath and wasysym, since it will redeclare
815         // inconsistent integral symbols
816         if (mustProvide("esint") &&
817             params_.use_package("esint") != BufferParams::package_off)
818                 packages << "\\usepackage{esint}\n";
819
820         // natbib.sty
821         // Some classes load natbib themselves, but still allow (or even require)
822         // plain numeric citations (ReVTeX is such a case, see bug 5182).
823         // This special case is indicated by the "natbib-internal" key.
824         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
825                 packages << "\\usepackage[";
826                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
827                         packages << "numbers";
828                 else
829                         packages << "authoryear";
830                 packages << "]{natbib}\n";
831         }
832
833         // jurabib -- we need version 0.6 at least.
834         if (mustProvide("jurabib"))
835                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
836
837         // xargs -- we need version 1.09 at least
838         if (mustProvide("xargs"))
839                 packages << "\\usepackage{xargs}[2008/03/08]\n";
840
841         if (mustProvide("xy"))
842                 packages << "\\usepackage[all]{xy}\n";
843
844         if (mustProvide("feyn"))
845                 packages << "\\usepackage{feyn}\n"; //Diagram
846
847         if (mustProvide("ulem"))
848                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
849                             "\\usepackage{ulem}\n";
850
851         if (mustProvide("mhchem") &&
852             params_.use_package("mhchem") != BufferParams::package_off)
853                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
854                             "\\usepackage{mhchem}\n";
855
856         if (mustProvide("nomencl")) {
857                 // Make it work with the new and old version of the package,
858                 // but don't use the compatibility option since it is
859                 // incompatible to other packages.
860                 packages << "\\usepackage{nomencl}\n"
861                             "% the following is useful when we have the old nomencl.sty package\n"
862                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
863                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
864                             "\\makenomenclature\n";
865         }
866
867         // fixltx2e provides subscript
868         if (mustProvide("subscript") && !isRequired("fixltx2e"))
869                 packages << "\\usepackage{subscript}\n";
870
871         return packages.str();
872 }
873
874
875 string LaTeXFeatures::getPreambleSnippets() const
876 {
877         ostringstream snip;
878         SnippetList::const_iterator pit  = preamble_snippets_.begin();
879         SnippetList::const_iterator pend = preamble_snippets_.end();
880         for (; pit != pend; ++pit)
881                 snip << *pit << '\n';
882         return snip.str();
883 }
884
885
886 std::string LaTeXFeatures::getCSSSnippets() const
887 {
888         ostringstream snip;
889         SnippetList::const_iterator pit  = css_snippets_.begin();
890         SnippetList::const_iterator pend = css_snippets_.end();
891         for (; pit != pend; ++pit)
892                 snip << *pit << '\n';
893         return snip.str();
894 }
895
896
897 docstring const LaTeXFeatures::getMacros() const
898 {
899         odocstringstream macros;
900
901         if (!preamble_snippets_.empty()) {
902                 macros << '\n';
903                 macros << from_utf8(getPreambleSnippets());
904         }
905
906         if (mustProvide("papersize")) {
907                 if (runparams_.flavor == OutputParams::LATEX)
908                         macros << papersizedvi_def << '\n';
909                 else
910                         macros << papersizepdf_def << '\n';
911         }
912
913         if (mustProvide("LyX")) {
914                 if (isRequired("hyperref"))
915                         macros << lyx_hyperref_def << '\n';
916                 else
917                         macros << lyx_def << '\n';
918         }
919
920         if (mustProvide("noun"))
921                 macros << noun_def << '\n';
922
923         if (mustProvide("lyxarrow"))
924                 macros << lyxarrow_def << '\n';
925
926         if (!usePolyglossia() && mustProvide("textgreek")) {
927                 // Avoid a LaTeX error if times fonts are used and the grtimes
928                 // package is installed but actual fonts are not (bug 6469).
929                 if (params_.fonts_roman == "times")
930                         macros << subst(textgreek_def,
931                                         from_ascii("\\greektext #1"),
932                                         from_ascii("%\n  \\IfFileExists"
933                                                    "{grtm10.tfm}{}{\\fontfamily"
934                                                    "{cmr}}\\greektext #1"))
935                                << '\n';
936                 else
937                         macros << textgreek_def << '\n';
938         }
939
940         if (!usePolyglossia() && mustProvide("textcyr"))
941                 macros << textcyr_def << '\n';
942
943         if (mustProvide("lyxmathsym"))
944                 macros << lyxmathsym_def << '\n';
945
946         if (mustProvide("cedilla"))
947                 macros << cedilla_def << '\n';
948
949         if (mustProvide("subring"))
950                 macros << subring_def << '\n';
951
952         if (mustProvide("subdot"))
953                 macros << subdot_def << '\n';
954
955         if (mustProvide("subhat"))
956                 macros << subhat_def << '\n';
957
958         if (mustProvide("subtilde"))
959                 macros << subtilde_def << '\n';
960
961         if (mustProvide("dacute"))
962                 macros << dacute_def << '\n';
963
964         if (mustProvide("tipasymb"))
965                 macros << tipasymb_def << '\n';
966
967         if (mustProvide("dgrave"))
968                 macros << dgrave_def << '\n';
969
970         if (mustProvide("rcap"))
971                 macros << rcap_def << '\n';
972
973         if (mustProvide("ogonek"))
974                 macros << ogonek_def << '\n';
975
976         // quotes.
977         if (mustProvide("quotesinglbase"))
978                 macros << quotesinglbase_def << '\n';
979         if (mustProvide("quotedblbase"))
980                 macros << quotedblbase_def << '\n';
981         if (mustProvide("guilsinglleft"))
982                 macros << guilsinglleft_def << '\n';
983         if (mustProvide("guilsinglright"))
984                 macros << guilsinglright_def << '\n';
985         if (mustProvide("guillemotleft"))
986                 macros << guillemotleft_def << '\n';
987         if (mustProvide("guillemotright"))
988                 macros << guillemotright_def << '\n';
989
990         // Math mode
991         if (mustProvide("binom") && !isRequired("amsmath"))
992                 macros << binom_def << '\n';
993         if (mustProvide("mathcircumflex"))
994                 macros << mathcircumflex_def << '\n';
995
996         // other
997         if (mustProvide("ParagraphLeftIndent"))
998                 macros << paragraphleftindent_def;
999         if (mustProvide("NeedLyXFootnoteCode"))
1000                 macros << floatingfootnote_def;
1001
1002         // some problems with tex->html converters
1003         if (mustProvide("NeedTabularnewline"))
1004                 macros << tabularnewline_def;
1005
1006         // greyed-out environment (note inset)
1007         // the color is specified in the routine
1008         // getColorOptions() to avoid LaTeX-package clashes
1009         if (mustProvide("lyxgreyedout"))
1010                 macros << lyxgreyedout_def;
1011
1012         if (mustProvide("lyxdot"))
1013                 macros << lyxdot_def << '\n';
1014
1015         // floats
1016         getFloatDefinitions(macros);
1017
1018         if (mustProvide("refstyle"))
1019                 macros << lyxref_def << '\n';
1020
1021         // change tracking
1022         if (mustProvide("ct-dvipost"))
1023                 macros << changetracking_dvipost_def;
1024
1025         if (mustProvide("ct-xcolor-ulem")) {
1026                 streamsize const prec = macros.precision(2);
1027
1028                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1029                 macros << "\\providecolor{lyxadded}{rgb}{"
1030                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1031
1032                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1033                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1034                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1035
1036                 macros.precision(prec);
1037
1038                 if (isRequired("hyperref"))
1039                         macros << changetracking_xcolor_ulem_hyperref_def;
1040                 else
1041                         macros << changetracking_xcolor_ulem_def;
1042         }
1043
1044         if (mustProvide("ct-none"))
1045                 macros << changetracking_none_def;
1046
1047         return macros.str();
1048 }
1049
1050
1051 string const LaTeXFeatures::getBabelPresettings() const
1052 {
1053         ostringstream tmp;
1054
1055         LanguageList::const_iterator it  = UsedLanguages_.begin();
1056         LanguageList::const_iterator end = UsedLanguages_.end();
1057         for (; it != end; ++it)
1058                 if (!(*it)->babel_presettings().empty())
1059                         tmp << (*it)->babel_presettings() << '\n';
1060         if (!params_.language->babel_presettings().empty())
1061                 tmp << params_.language->babel_presettings() << '\n';
1062
1063         if (!contains(tmp.str(), '@'))
1064                 return tmp.str();
1065
1066         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1067 }
1068
1069
1070 string const LaTeXFeatures::getBabelPostsettings() const
1071 {
1072         ostringstream tmp;
1073
1074         LanguageList::const_iterator it  = UsedLanguages_.begin();
1075         LanguageList::const_iterator end = UsedLanguages_.end();
1076         for (; it != end; ++it)
1077                 if (!(*it)->babel_postsettings().empty())
1078                         tmp << (*it)->babel_postsettings() << '\n';
1079         if (!params_.language->babel_postsettings().empty())
1080                 tmp << params_.language->babel_postsettings() << '\n';
1081
1082         if (!contains(tmp.str(), '@'))
1083                 return tmp.str();
1084
1085         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1086 }
1087
1088
1089 bool LaTeXFeatures::needBabelLangOptions() const
1090 {
1091         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1092                 return true;
1093
1094         LanguageList::const_iterator it  = UsedLanguages_.begin();
1095         LanguageList::const_iterator end = UsedLanguages_.end();
1096         for (; it != end; ++it)
1097                 if ((*it)->asBabelOptions())
1098                         return true;
1099
1100         return false;
1101 }
1102
1103
1104 string const LaTeXFeatures::loadAMSPackages() const
1105 {
1106         ostringstream tmp;
1107         if (mustProvide("amsthm"))
1108                 tmp << "\\usepackage{amsthm}\n";
1109
1110         if (mustProvide("amsmath")
1111             && params_.use_package("amsmath") != BufferParams::package_off) {
1112                 tmp << "\\usepackage{amsmath}\n";
1113         } else {
1114                 // amsbsy and amstext are already provided by amsmath
1115                 if (mustProvide("amsbsy"))
1116                         tmp << "\\usepackage{amsbsy}\n";
1117                 if (mustProvide("amstext"))
1118                         tmp << "\\usepackage{amstext}\n";
1119         }
1120
1121         if (mustProvide("amssymb")
1122             && params_.use_package("amssymb") != BufferParams::package_off)
1123                 tmp << "\\usepackage{amssymb}\n";
1124
1125         return tmp.str();
1126 }
1127
1128
1129 docstring const LaTeXFeatures::getTClassPreamble() const
1130 {
1131         // the text class specific preamble
1132         DocumentClass const & tclass = params_.documentClass();
1133         odocstringstream tcpreamble;
1134
1135         tcpreamble << tclass.preamble();
1136
1137         list<docstring>::const_iterator cit = usedLayouts_.begin();
1138         list<docstring>::const_iterator end = usedLayouts_.end();
1139         for (; cit != end; ++cit)
1140                 tcpreamble << tclass[*cit].preamble();
1141
1142         cit = usedInsetLayouts_.begin();
1143         end = usedInsetLayouts_.end();
1144         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1145         for (; cit != end; ++cit) {
1146                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1147                 if (it == ils.end())
1148                         continue;
1149                 tcpreamble << it->second.preamble();
1150         }
1151
1152         return tcpreamble.str();
1153 }
1154
1155
1156 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1157 {
1158         DocumentClass const & tclass = params_.documentClass();
1159         odocstringstream tcpreamble;
1160
1161         tcpreamble << tclass.htmlpreamble();
1162
1163         list<docstring>::const_iterator cit = usedLayouts_.begin();
1164         list<docstring>::const_iterator end = usedLayouts_.end();
1165         for (; cit != end; ++cit)
1166                 tcpreamble << tclass[*cit].htmlpreamble();
1167
1168         cit = usedInsetLayouts_.begin();
1169         end = usedInsetLayouts_.end();
1170         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1171         for (; cit != end; ++cit) {
1172                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1173                 if (it == ils.end())
1174                         continue;
1175                 tcpreamble << it->second.htmlpreamble();
1176         }
1177
1178         return tcpreamble.str();
1179 }
1180
1181
1182 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1183 {
1184         DocumentClass const & tclass = params_.documentClass();
1185         odocstringstream tcpreamble;
1186
1187         tcpreamble << tclass.htmlstyles();
1188
1189         list<docstring>::const_iterator cit = usedLayouts_.begin();
1190         list<docstring>::const_iterator end = usedLayouts_.end();
1191         for (; cit != end; ++cit)
1192                 tcpreamble << tclass[*cit].htmlstyle();
1193
1194         cit = usedInsetLayouts_.begin();
1195         end = usedInsetLayouts_.end();
1196         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1197         for (; cit != end; ++cit) {
1198                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1199                 if (it == ils.end())
1200                         continue;
1201                 tcpreamble << it->second.htmlstyle();
1202         }
1203
1204         return tcpreamble.str();
1205 }
1206
1207
1208 namespace {
1209 docstring const getFloatI18nPreamble(docstring const & type,
1210                         docstring const & name, Language const * lang,
1211                         Encoding const & enc, bool const polyglossia)
1212 {
1213         // Check whether name can be encoded in the buffer encoding
1214         bool encodable = true;
1215         for (size_t i = 0; i < name.size(); ++i) {
1216                 if (!enc.encodable(name[i])) {
1217                         encodable = false;
1218                         break;
1219                 }
1220         }
1221
1222         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1223                                                : from_ascii(lang->babel());
1224         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1225         docstring const texenc = from_ascii(lang->encoding()->latexName());
1226         docstring const bufenc = from_ascii(enc.iconvName());
1227         docstring const s1 = docstring(1, 0xF0000);
1228         docstring const s2 = docstring(1, 0xF0001);
1229         docstring const translated = encodable ? name
1230                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1231                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1232
1233         odocstringstream os;
1234         os << "\\addto\\captions" << language
1235            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1236         return os.str();
1237 }
1238
1239
1240 docstring const i18npreamble(docstring const & templ, Language const * lang,
1241                 Encoding const & enc, bool const polyglossia)
1242 {
1243         if (templ.empty())
1244                 return templ;
1245
1246         string preamble = polyglossia ?
1247                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1248                 subst(to_utf8(templ), "$$lang", lang->babel());
1249
1250         string const langenc = lang->encoding()->iconvName();
1251         string const texenc = lang->encoding()->latexName();
1252         string const bufenc = enc.iconvName();
1253         // First and second character of plane 15 (Private Use Area)
1254         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1255         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1256         // FIXME UNICODE
1257         // lyx::regex is not unicode-safe.
1258         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1259         static regex const reg("_\\(([^\\)]+)\\)");
1260         smatch sub;
1261         while (regex_search(preamble, sub, reg)) {
1262                 string const key = sub.str(1);
1263                 docstring const name = lang->translateLayout(key);
1264                 // Check whether name can be encoded in the buffer encoding
1265                 bool encodable = true;
1266                 for (size_t i = 0; i < name.size(); ++i) {
1267                         if (!enc.encodable(name[i])) {
1268                                 encodable = false;
1269                                 break;
1270                         }
1271                 }
1272                 string const translated = encodable ? to_utf8(name)
1273                         : "\\inputencoding{" + texenc + "}"
1274                         + s1 + langenc + s2 + to_utf8(name)
1275                         + s1 + bufenc + s2;
1276                 preamble = subst(preamble, sub.str(), translated);
1277         }
1278         return from_utf8(preamble);
1279 }
1280
1281 }
1282
1283
1284 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1285 {
1286         DocumentClass const & tclass = params_.documentClass();
1287         // collect preamble snippets in a set to prevent multiple identical
1288         // commands (would happen if e.g. both theorem and theorem* are used)
1289         set<docstring> snippets;
1290         typedef LanguageList::const_iterator lang_it;
1291         lang_it const lbeg = UsedLanguages_.begin();
1292         lang_it const lend =  UsedLanguages_.end();
1293         list<docstring>::const_iterator cit = usedLayouts_.begin();
1294         list<docstring>::const_iterator end = usedLayouts_.end();
1295         for (; cit != end; ++cit) {
1296                 // language dependent commands (once per document)
1297                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1298                                                 buffer().language(),
1299                                                 buffer().params().encoding(),
1300                                                 use_polyglossia));
1301                 // commands for language changing (for multilanguage documents)
1302                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1303                         snippets.insert(i18npreamble(
1304                                                 tclass[*cit].babelpreamble(),
1305                                                 buffer().language(),
1306                                                 buffer().params().encoding(),
1307                                                 use_polyglossia));
1308                         for (lang_it lit = lbeg; lit != lend; ++lit)
1309                                 snippets.insert(i18npreamble(
1310                                                 tclass[*cit].babelpreamble(),
1311                                                 *lit,
1312                                                 buffer().params().encoding(),
1313                                                 use_polyglossia));
1314                 }
1315         }
1316         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1317                 FloatList const & floats = params_.documentClass().floats();
1318                 UsedFloats::const_iterator fit = usedFloats_.begin();
1319                 UsedFloats::const_iterator fend = usedFloats_.end();
1320                 for (; fit != fend; ++fit) {
1321                         Floating const & fl = floats.getType(fit->first);
1322                         // we assume builtin floats are translated
1323                         if (fl.isPredefined())
1324                                 continue;
1325                         docstring const type = from_ascii(fl.floattype());
1326                         docstring const flname = from_utf8(fl.name());
1327                         docstring name = buffer().language()->translateLayout(fl.name());
1328                         // only request translation if we have a real translation
1329                         // (that differs from the source)
1330                         if (flname != name)
1331                                 snippets.insert(getFloatI18nPreamble(
1332                                                 type, name, buffer().language(),
1333                                                 buffer().params().encoding(),
1334                                                 use_polyglossia));
1335                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1336                                 string const code = (*lit)->code();
1337                                 name = (*lit)->translateLayout(fl.name());
1338                                 // we assume we have a suitable translation if
1339                                 // either the language is English (we need to
1340                                 // translate into English if English is a secondary
1341                                 // language) or if translateIfPossible returns
1342                                 // something different to the English source.
1343                                 bool const have_translation =
1344                                         (flname != name || contains(code, "en"));
1345                                 if (have_translation)
1346                                         snippets.insert(getFloatI18nPreamble(
1347                                                 type, name, *lit,
1348                                                 buffer().params().encoding(),
1349                                                 use_polyglossia));
1350                         }
1351                 }
1352         }
1353
1354         cit = usedInsetLayouts_.begin();
1355         end = usedInsetLayouts_.end();
1356         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1357         for (; cit != end; ++cit) {
1358                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1359                 if (it == ils.end())
1360                         continue;
1361                 // language dependent commands (once per document)
1362                 snippets.insert(i18npreamble(it->second.langpreamble(),
1363                                                 buffer().language(),
1364                                                 buffer().params().encoding(),
1365                                                 use_polyglossia));
1366                 // commands for language changing (for multilanguage documents)
1367                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1368                         snippets.insert(i18npreamble(
1369                                                 it->second.babelpreamble(),
1370                                                 buffer().language(),
1371                                                 buffer().params().encoding(),
1372                                                 use_polyglossia));
1373                         for (lang_it lit = lbeg; lit != lend; ++lit)
1374                                 snippets.insert(i18npreamble(
1375                                                 it->second.babelpreamble(),
1376                                                 *lit,
1377                                                 buffer().params().encoding(),
1378                                                 use_polyglossia));
1379                 }
1380         }
1381
1382         odocstringstream tcpreamble;
1383         set<docstring>::const_iterator const send = snippets.end();
1384         set<docstring>::const_iterator it = snippets.begin();
1385         for (; it != send; ++it)
1386                 tcpreamble << *it;
1387         return tcpreamble.str();
1388 }
1389
1390
1391 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1392 {
1393         // Definition of entities used in the document that are LyX related.
1394         odocstringstream entities;
1395
1396         if (mustProvide("lyxarrow")) {
1397                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1398         }
1399
1400         return entities.str();
1401 }
1402
1403
1404 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1405 {
1406         odocstringstream sgmlpreamble;
1407         // FIXME UNICODE
1408         docstring const basename(from_utf8(onlyPath(fname)));
1409
1410         FileMap::const_iterator end = IncludedFiles_.end();
1411         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1412              fi != end; ++fi)
1413                 // FIXME UNICODE
1414                 sgmlpreamble << "\n<!ENTITY " << fi->first
1415                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1416                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1417
1418         return sgmlpreamble.str();
1419 }
1420
1421
1422 void LaTeXFeatures::showStruct() const
1423 {
1424         lyxerr << "LyX needs the following commands when LaTeXing:"
1425                << "\n***** Packages:" << getPackages()
1426                << "\n***** Macros:" << to_utf8(getMacros())
1427                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1428                << "\n***** done." << endl;
1429 }
1430
1431
1432 Buffer const & LaTeXFeatures::buffer() const
1433 {
1434         return *buffer_;
1435 }
1436
1437
1438 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1439 {
1440         buffer_ = &buffer;
1441 }
1442
1443
1444 BufferParams const & LaTeXFeatures::bufferParams() const
1445 {
1446         return params_;
1447 }
1448
1449
1450 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1451 {
1452         FloatList const & floats = params_.documentClass().floats();
1453
1454         // Here we will output the code to create the needed float styles.
1455         // We will try to do this as minimal as possible.
1456         // \floatstyle{ruled}
1457         // \newfloat{algorithm}{htbp}{loa}
1458         // \providecommand{\algorithmname}{Algorithm}
1459         // \floatname{algorithm}{\protect\algorithmname}
1460         UsedFloats::const_iterator cit = usedFloats_.begin();
1461         UsedFloats::const_iterator end = usedFloats_.end();
1462         for (; cit != end; ++cit) {
1463                 Floating const & fl = floats.getType(cit->first);
1464
1465                 // For builtin floats we do nothing.
1466                 if (fl.isPredefined())
1467                         continue;
1468
1469                 // We have to special case "table" and "figure"
1470                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1471                         // Output code to modify "table" or "figure"
1472                         // but only if builtin == false
1473                         // and that have to be true at this point in the
1474                         // function.
1475                         docstring const type = from_ascii(fl.floattype());
1476                         docstring const placement = from_ascii(fl.placement());
1477                         docstring const style = from_ascii(fl.style());
1478                         if (!style.empty()) {
1479                                 os << "\\floatstyle{" << style << "}\n"
1480                                    << "\\restylefloat{" << type << "}\n";
1481                         }
1482                         if (!placement.empty()) {
1483                                 os << "\\floatplacement{" << type << "}{"
1484                                    << placement << "}\n";
1485                         }
1486                 } else {
1487                         // The other non builtin floats.
1488
1489                         docstring const type = from_ascii(fl.floattype());
1490                         docstring const placement = from_ascii(fl.placement());
1491                         docstring const ext = from_ascii(fl.ext());
1492                         docstring const within = from_ascii(fl.within());
1493                         docstring const style = from_ascii(fl.style());
1494                         docstring const name =
1495                                 buffer().language()->translateLayout(fl.name());
1496                         os << "\\floatstyle{" << style << "}\n"
1497                            << "\\newfloat{" << type << "}{" << placement
1498                            << "}{" << ext << '}';
1499                         if (!within.empty())
1500                                 os << '[' << within << ']';
1501                         os << '\n'
1502                            << "\\providecommand{\\" << type << "name}{"
1503                            << name << "}\n"
1504                            << "\\floatname{" << type << "}{\\protect\\"
1505                            << type << "name}\n";
1506
1507                         // What missing here is to code to minimalize the code
1508                         // output so that the same floatstyle will not be
1509                         // used several times, when the same style is still in
1510                         // effect. (Lgb)
1511                 }
1512                 if (cit->second)
1513                         os << "\n\\newsubfloat{" << from_ascii(fl.floattype()) << "}\n";
1514         }
1515 }
1516
1517
1518 void LaTeXFeatures::resolveAlternatives()
1519 {
1520         for (Features::iterator it = features_.begin(); it != features_.end();) {
1521                 if (contains(*it, '|')) {
1522                         vector<string> const alternatives = getVectorFromString(*it, "|");
1523                         vector<string>::const_iterator const end = alternatives.end();
1524                         vector<string>::const_iterator ita = alternatives.begin();
1525                         for (; ita != end; ++ita) {
1526                                 if (isRequired(*ita))
1527                                         break;
1528                         }
1529                         if (ita == end)
1530                                 require(alternatives.front());
1531                         features_.erase(it);
1532                         it = features_.begin();
1533                 } else
1534                         ++it;
1535         }
1536 }
1537
1538
1539 } // namespace lyx