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