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