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