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