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