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