]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
21af63295490fcce16e2aae94ae089f73c8b4551
[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 "Layout.h"
28 #include "Lexer.h"
29 #include "LyXRC.h"
30 #include "TextClass.h"
31
32 #include "insets/InsetLayout.h"
33
34 #include "support/debug.h"
35 #include "support/docstream.h"
36 #include "support/FileName.h"
37 #include "support/filetools.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
40
41 using namespace std;
42 using namespace lyx::support;
43
44
45 namespace lyx {
46
47 /////////////////////////////////////////////////////////////////////
48 //
49 // Strings
50 //
51 /////////////////////////////////////////////////////////////////////
52
53 //\NeedsTeXFormat{LaTeX2e}
54 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
55 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
56
57 static docstring const lyx_def = from_ascii(
58         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
59
60 static docstring const lyxline_def = from_ascii(
61         "\\newcommand{\\lyxline}[1][1pt]{%\n"
62         "  \\par\\noindent%\n"
63         "  \\rule[.5ex]{\\linewidth}{#1}\\par}");
64
65 static docstring const noun_def = from_ascii(
66         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
67
68 static docstring const lyxarrow_def = from_ascii(
69         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
70         "\\@ifstar\n"
71         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
72         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
73
74 // for quotes without babel. This does not give perfect results, but
75 // anybody serious about non-english quotes should use babel (JMarc).
76
77 static docstring const quotedblbase_def = from_ascii(
78         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
79         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
80         "  \\penalty10000\\hskip0em\\relax%\n"
81         "}");
82
83 static docstring const quotesinglbase_def = from_ascii(
84         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
85         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
86         "  \\penalty10000\\hskip0em\\relax%\n"
87         "}");
88
89 static docstring const guillemotleft_def = from_ascii(
90         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
91         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
92         "\\penalty10000\\hskip0pt\\relax%\n"
93         "}");
94
95 static docstring const guillemotright_def = from_ascii(
96         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
97         "  \\penalty10000\\hskip0pt%\n"
98         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
99         "}");
100
101 static docstring const guilsinglleft_def = from_ascii(
102         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
103         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
104         "  \\penalty10000\\hskip0pt\\relax%\n"
105         "}");
106
107 static docstring const guilsinglright_def = from_ascii(
108         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
109         "  \\penalty10000\\hskip0pt%\n"
110         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
111         "}");
112
113 static docstring const paragraphleftindent_def = from_ascii(
114         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
115         "{\n"
116         "  \\begin{list}{}{%\n"
117         "    \\setlength{\\topsep}{0pt}%\n"
118         "    \\addtolength{\\leftmargin}{#1}\n"
119 // ho hum, yet more things commented out with no hint as to why they
120 // weren't just removed
121 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
122 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
123 //      "%%    \\setlength\\listparindent\\parindent%\n"
124 //      "%%    \\setlength\\itemindent\\parindent%\n"
125         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
126         "  }\n"
127         "  \\item[]\n"
128         "}\n"
129         "{\\end{list}}\n");
130
131 static docstring const floatingfootnote_def = from_ascii(
132         "%% Special footnote code from the package 'stblftnt.sty'\n"
133         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
134         "\\let\\SF@@footnote\\footnote\n"
135         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
136         "    \\expandafter\\SF@@footnote\n"
137         "  \\else\n"
138         "    \\expandafter\\SF@gobble@opt\n"
139         "  \\fi\n"
140         "}\n"
141         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
142         "  \\SF@gobble@twobracket\n"
143         "  \\@gobble\n"
144         "}\n"
145         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
146         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
147         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
148
149 static docstring const binom_def = from_ascii(
150         "%% Binom macro for standard LaTeX users\n"
151         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
152
153 static docstring const mathcircumflex_def = from_ascii(
154         "%% For printing a cirumflex inside a formula\n"
155         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
156
157 static docstring const tabularnewline_def = from_ascii(
158         "%% Because html converters don't know tabularnewline\n"
159         "\\providecommand{\\tabularnewline}{\\\\}\n");
160         
161 static docstring const lyxgreyedout_def = from_ascii(
162         "%% The greyedout annotation environment\n"
163         "\\newenvironment{lyxgreyedout}{\\textcolor[gray]{0.8}\\bgroup}{\\egroup}\n");
164
165 // We want to omit the file extension for includegraphics, but this does not
166 // work when the filename contains other dots.
167 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
168 static docstring const lyxdot_def = from_ascii(
169         "%% A simple dot to overcome graphicx limitations\n"
170         "\\newcommand{\\lyxdot}{.}\n");
171
172 static docstring const changetracking_dvipost_def = from_ascii(
173         "%% Change tracking with dvipost\n"
174         "\\dvipostlayout\n"
175         "\\dvipost{osstart color push Red}\n"
176         "\\dvipost{osend color pop}\n"
177         "\\dvipost{cbstart color push Blue}\n"
178         "\\dvipost{cbend color pop}\n"
179         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
180         "\\newcommand{\\lyxdeleted}[3]{%\n"
181         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
182
183 static docstring const changetracking_xcolor_ulem_def = from_ascii(
184         "%% Change tracking with ulem\n"
185         "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
186         "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
187
188 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
189         "%% Change tracking with ulem\n"
190         "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
191         "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
192
193 static docstring const changetracking_none_def = from_ascii(
194         "\\newcommand{\\lyxadded}[3]{#3}\n"
195         "\\newcommand{\\lyxdeleted}[3]{}\n");
196
197 static docstring const textgreek_def = from_ascii(
198         "\\providecommand*{\\perispomeni}{\\char126}\n"
199         "\\AtBeginDocument{\\DeclareRobustCommand{\\greektext}{%\n"
200         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}%\n"
201         "  \\renewcommand{\\~}{\\perispomeni}\n"
202         "}}\n"
203         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
204         "\\DeclareFontEncoding{LGR}{}{}\n");
205
206 static docstring const textcyr_def = from_ascii(
207         "\\DeclareRobustCommand{\\cyrtext}{%\n"
208         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
209         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
210         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
211
212 static docstring const lyxmathsym_def = from_ascii(
213         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
214         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
215
216 static docstring const papersizedvi_def = from_ascii(
217         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
218
219 static docstring const papersizepdf_def = from_ascii(
220         "\\pdfpageheight\\paperheight\n"
221         "\\pdfpagewidth\\paperwidth\n");
222
223 static docstring const cedilla_def = from_ascii(
224         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
225         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
226
227 static docstring const subring_def = from_ascii(
228         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
229         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
230
231 static docstring const subdot_def = from_ascii(
232         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
233         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
234
235 static docstring const subhat_def = from_ascii(
236         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
237         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
238
239 static docstring const subtilde_def = from_ascii(
240         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
241         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
242
243 static docstring const dacute_def = from_ascii(
244         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
245
246 static docstring const tipasymb_def = from_ascii(
247         "\\DeclareFontEncoding{T3}{}{}\n"
248         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
249
250 static docstring const dgrave_def = from_ascii(
251         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
252
253 static docstring const rcap_def = from_ascii(
254         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
255
256 static docstring const ogonek_def = from_ascii(
257         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
258         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
259         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
260         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
261         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
262
263 /////////////////////////////////////////////////////////////////////
264 //
265 // LaTeXFeatures
266 //
267 /////////////////////////////////////////////////////////////////////
268
269 LaTeXFeatures::Packages LaTeXFeatures::packages_;
270
271
272 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
273                              OutputParams const & r)
274         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
275 {}
276
277
278 bool LaTeXFeatures::useBabel() const
279 {
280         return lyxrc.language_use_babel ||
281                 (bufferParams().language->lang() != lyxrc.default_language &&
282                  !bufferParams().language->babel().empty()) ||
283                 this->hasLanguages();
284 }
285
286
287 void LaTeXFeatures::require(string const & name)
288 {
289         features_.insert(name);
290 }
291
292
293 void LaTeXFeatures::require(set<string> const & names)
294 {
295         features_.insert(names.begin(), names.end());
296 }
297
298
299 void LaTeXFeatures::getAvailable()
300 {
301         Lexer lex;
302         support::FileName const real_file = libFileSearch("", "packages.lst");
303
304         if (real_file.empty())
305                 return;
306
307         lex.setFile(real_file);
308
309         if (!lex.isOK())
310                 return;
311
312         // Make sure that we are clean
313         packages_.clear();
314
315         bool finished = false;
316         // Parse config-file
317         while (lex.isOK() && !finished) {
318                 switch (lex.lex()) {
319                 case Lexer::LEX_FEOF:
320                         finished = true;
321                         break;
322                 default:
323                         packages_.insert(lex.getString());
324                 }
325         }
326 }
327
328
329 void LaTeXFeatures::useLayout(docstring const & layoutname)
330 {
331         // Some code to avoid loops in dependency definition
332         static int level = 0;
333         const int maxlevel = 30;
334         if (level > maxlevel) {
335                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
336                        << "recursion attained by layout "
337                        << to_utf8(layoutname) << endl;
338                 return;
339         }
340
341         DocumentClass const & tclass = params_.documentClass();
342         if (tclass.hasLayout(layoutname)) {
343                 // Is this layout already in usedLayouts?
344                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
345                     != usedLayouts_.end())
346                         return;
347
348                 Layout const & layout = tclass[layoutname];
349                 require(layout.requires());
350
351                 if (!layout.depends_on().empty()) {
352                         ++level;
353                         useLayout(layout.depends_on());
354                         --level;
355                 }
356                 usedLayouts_.push_back(layoutname);
357         } else {
358                 lyxerr << "LaTeXFeatures::useLayout: layout `"
359                        << to_utf8(layoutname) << "' does not exist in this class"
360                        << endl;
361         }
362
363         --level;
364 }
365
366
367 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
368 {
369         docstring const & lname = lay.name();
370         DocumentClass const & tclass = params_.documentClass();
371
372         // this is a default inset layout, nothing useful here
373         if (!tclass.hasInsetLayout(lname))
374                 return;
375         // Is this layout already in usedInsetLayouts?
376         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname) 
377                         != usedInsetLayouts_.end())
378                 return;
379
380         require(lay.requires());
381         usedInsetLayouts_.push_back(lname);
382 }
383
384
385 bool LaTeXFeatures::isRequired(string const & name) const
386 {
387         return features_.find(name) != features_.end();
388 }
389
390
391 bool LaTeXFeatures::mustProvide(string const & name) const
392 {
393         return isRequired(name) && !params_.documentClass().provides(name);
394 }
395
396
397 bool LaTeXFeatures::isAvailable(string const & name)
398 {
399         string::size_type const i = name.find("->");
400         if (i != string::npos) {
401                 string const from = name.substr(0,i);
402                 string const to = name.substr(i+2);
403                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
404                 return theConverters().isReachable(from, to);
405         }
406
407         if (packages_.empty())
408                 getAvailable();
409         string n = name;
410         if (suffixIs(n, ".sty"))
411                 n.erase(name.length() - 4);
412         return packages_.find(n) != packages_.end();
413 }
414
415
416 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
417 {
418         LYXERR0(preamble);
419         SnippetList::const_iterator begin = preamble_snippets_.begin();
420         SnippetList::const_iterator end   = preamble_snippets_.end();
421         if (find(begin, end, preamble) == end)
422                 preamble_snippets_.push_back(preamble);
423 }
424
425
426 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
427 {
428         if (!usedFloats_[name])
429                 usedFloats_[name] = subfloat;
430         if (subfloat)
431                 require("subfig");
432         // We only need float.sty if we use non builtin floats, or if we
433         // use the "H" modifier. This includes modified table and
434         // figure floats. (Lgb)
435         Floating const & fl = params_.documentClass().floats().getType(name);
436         if (!fl.type().empty() && !fl.builtin()) {
437                 require("float");
438         }
439 }
440
441
442 void LaTeXFeatures::useLanguage(Language const * lang)
443 {
444         if (!lang->babel().empty())
445                 UsedLanguages_.insert(lang);
446         if (lang->lang() == "vietnamese")
447                 require("vietnamese");
448         // CJK languages do not have a babel name.
449         // They use the CJK package
450         if (lang->encoding()->package() == Encoding::CJK)
451                 require("CJK");
452         // japanese package is special
453         if (lang->encoding()->package() == Encoding::japanese)
454                 require("japanese");
455 }
456
457
458 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
459 {
460         IncludedFiles_[key] = name;
461 }
462
463
464 bool LaTeXFeatures::hasLanguages() const
465 {
466         return !UsedLanguages_.empty();
467 }
468
469
470 string LaTeXFeatures::getLanguages() const
471 {
472         ostringstream languages;
473
474         LanguageList::const_iterator const begin = UsedLanguages_.begin();
475         for (LanguageList::const_iterator cit = begin;
476              cit != UsedLanguages_.end();
477              ++cit) {
478                 if (cit != begin)
479                         languages << ',';
480                 languages << (*cit)->babel();
481         }
482         return languages.str();
483 }
484
485
486 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
487 {
488         // This does only find encodings of languages supported by babel, but
489         // that does not matter since we don't have a language with an
490         // encoding supported by inputenc but without babel support.
491         set<string> encodings;
492         LanguageList::const_iterator it  = UsedLanguages_.begin();
493         LanguageList::const_iterator end = UsedLanguages_.end();
494         for (; it != end; ++it)
495                 if ((*it)->encoding()->latexName() != doc_encoding &&
496                     ((*it)->encoding()->package() == Encoding::inputenc
497                      || (*it)->encoding()->package() == Encoding::japanese))
498                         encodings.insert((*it)->encoding()->latexName());
499         return encodings;
500 }
501
502 namespace {
503
504 char const * simplefeatures[] = {
505 // note that the package order here will be the same in the LaTeX-output
506         "array",
507         "verbatim",
508         "longtable",
509         "rotating",
510         "latexsym",
511         "pifont",
512         // subfig is handled in BufferParams.cpp
513         "varioref",
514         "prettyref",
515         /*For a successful cooperation of the `wrapfig' package with the
516           `float' package you should load the `wrapfig' package *after*
517           the `float' package. See the caption package documentation
518           for explanation.*/
519         "float",
520         "rotfloat",
521         "wrapfig",
522         "booktabs",
523         "dvipost",
524         "fancybox",
525         "calc",
526         "units",
527         "tipa",
528         "tipx",
529         "framed",
530         "soul",
531         "textcomp",
532         "pmboxdraw",
533         "bbding",
534         "ifsym",
535         "marvosym",
536         "txfonts",
537         "mathrsfs",
538         "ascii",
539         "url",
540         "covington",
541         "csquotes",
542         "enumitem",
543         "endnotes",
544         "ifthen",
545         "amsthm",
546         // listings is handled in BufferParams.cpp
547         "bm",
548         "pdfpages",
549         "amscd",
550         "slashed"
551 };
552
553 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
554
555 }
556
557
558 string const LaTeXFeatures::getColorOptions() const
559 {
560         ostringstream colors;
561
562         // Handling the color packages separately is needed to be able to load them
563         // before babel when hyperref is loaded with the colorlinks option
564         // for more info see Bufferparams.cpp
565
566         // [x]color.sty
567         if (mustProvide("color") || mustProvide("xcolor")) {
568                 string const package =
569                         (mustProvide("xcolor") ? "xcolor" : "color");
570                 if (params_.graphicsDriver == "default"
571                         || params_.graphicsDriver == "none")
572                         colors << "\\usepackage{" << package << "}\n";
573                 else
574                         colors << "\\usepackage["
575                                  << params_.graphicsDriver
576                                  << "]{" << package << "}\n";
577         }
578
579         // pdfcolmk must be loaded after color
580         if (mustProvide("pdfcolmk"))
581                 colors << "\\usepackage{pdfcolmk}\n";
582
583         if (mustProvide("pagecolor")) {
584                 // the \pagecolor command must be set after color is loaded and
585                 // before pdfpages, therefore add the command here
586                 // define the set color
587                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
588                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
589                 // set the page color
590                 colors << "\\pagecolor{page_backgroundcolor}\n";
591         }
592
593         return colors.str();
594 }
595
596
597 string const LaTeXFeatures::getPackages() const
598 {
599         ostringstream packages;
600         DocumentClass const & tclass = params_.documentClass();
601
602         // FIXME: currently, we can only load packages and macros known
603         // to LyX.
604         // However, with the Require tag of layouts/custom insets,
605         // also inknown packages can be requested. They are silently
606         // swallowed now. We should change this eventually.
607
608         //
609         //  These are all the 'simple' includes.  i.e
610         //  packages which we just \usepackage{package}
611         //
612         for (int i = 0; i < nb_simplefeatures; ++i) {
613                 if (mustProvide(simplefeatures[i]))
614                         packages << "\\usepackage{"
615                                  << simplefeatures[i] << "}\n";
616         }
617
618         //
619         // The rest of these packages are somewhat more complicated
620         // than those above.
621         //
622
623         // esint is preferred for esintoramsmath
624         if ((mustProvide("amsmath")
625              && params_.use_amsmath != BufferParams::package_off)
626             || (mustProvide("esintoramsmath")
627                 && params_.use_esint == BufferParams::package_off
628                 && params_.use_amsmath != BufferParams::package_off)) {
629                 packages << "\\usepackage{amsmath}\n";
630         } else {
631                 // amsbsy and amstext are already provided by amsmath
632                 if (mustProvide("amsbsy"))
633                         packages << "\\usepackage{amsbsy}\n";
634                 if (mustProvide("amstext"))
635                         packages << "\\usepackage{amstext}\n";
636         }
637         
638         // wasysym is a simple feature, but it must be after amsmath if both
639         // are used
640         // wasysym redefines some integrals (e.g. iint) from amsmath. That
641         // leads to inconsistent integrals. We only load this package if
642         // the document does not contain integrals (then isRequired("esint")
643         // is false) or if esint is used, since esint redefines all relevant
644         // integral symbols from wasysym and amsmath.
645         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
646         if (mustProvide("wasysym") &&
647             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
648                 packages << "\\usepackage{wasysym}\n";
649
650         // accents must be loaded after amsmath
651         if (mustProvide("accents"))
652                 packages << "\\usepackage{accents}\n";
653
654         // mathdots must be loaded after amsmath
655         if (mustProvide("mathdots"))
656                 packages << "\\usepackage{mathdots}\n";
657
658         // yhmath must be loaded after amsmath
659         if (mustProvide("yhmath"))
660                 packages << "\\usepackage{yhmath}\n";
661
662         // [x]color and pdfcolmk are handled in getColorOptions() above
663         
664         // makeidx.sty
665         if (isRequired("makeidx") || isRequired("splitidx")) {
666                 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
667                         packages << "\\usepackage{makeidx}\n";
668                 if (!tclass.provides("splitidx") && isRequired("splitidx"))
669                         packages << "\\usepackage{splitidx}\n";
670                 packages << "\\makeindex\n";
671         }
672
673         // graphicx.sty
674         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
675                 if (params_.graphicsDriver == "default")
676                         packages << "\\usepackage{graphicx}\n";
677                 else
678                         packages << "\\usepackage["
679                                  << params_.graphicsDriver
680                                  << "]{graphicx}\n";
681         }
682         // shadecolor for shaded
683         if (isRequired("framed") && mustProvide("color")) {
684                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
685                 //255.0 to force conversion to double
686                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
687                 //to use the xcolor package instead, and then we can do
688                 // \define{shadcolor}{RGB}...
689                 //and not do any conversion. We'd then need to require xcolor
690                 //in InsetNote::validate().
691                 int const stmSize = packages.precision(2);
692                 packages << "\\definecolor{shadecolor}{rgb}{"
693                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
694                 packages.precision(stmSize);
695         }
696
697         // lyxskak.sty --- newer chess support based on skak.sty
698         if (mustProvide("chess"))
699                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
700
701         // setspace.sty
702         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
703                 packages << "\\usepackage{setspace}\n";
704
705         // amssymb.sty
706         if (mustProvide("amssymb")
707             || params_.use_amsmath == BufferParams::package_on)
708                 packages << "\\usepackage{amssymb}\n";
709
710         // esint must be after amsmath and wasysym, since it will redeclare
711         // inconsistent integral symbols
712         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
713             params_.use_esint != BufferParams::package_off)
714                 packages << "\\usepackage{esint}\n";
715
716         // natbib.sty
717         // Some classes load natbib themselves, but still allow (or even require)
718         // plain numeric citations (ReVTeX is such a case, see bug 5182).
719         // This special case is indicated by the "natbib-internal" key.
720         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
721                 packages << "\\usepackage[";
722                 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
723                         packages << "numbers";
724                 else
725                         packages << "authoryear";
726                 packages << "]{natbib}\n";
727         }
728
729         // jurabib -- we need version 0.6 at least.
730         if (mustProvide("jurabib"))
731                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
732         
733         // xargs -- we need version 1.09 at least
734         if (mustProvide("xargs"))
735                 packages << "\\usepackage{xargs}[2008/03/08]\n";
736
737         // bibtopic -- the dot provides the aux file naming which
738         // LyX can detect.
739         if (mustProvide("bibtopic"))
740                 packages << "\\usepackage[dot]{bibtopic}\n";
741
742         if (mustProvide("xy"))
743                 packages << "\\usepackage[all]{xy}\n";
744
745         if (mustProvide("ulem"))
746                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
747                             "\\usepackage{ulem}\n";
748
749         if (mustProvide("mhchem") &&
750                 params_.use_mhchem != BufferParams::package_off)
751                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
752                             "\\usepackage{mhchem}\n";
753
754         if (mustProvide("nomencl")) {
755                 // Make it work with the new and old version of the package,
756                 // but don't use the compatibility option since it is
757                 // incompatible to other packages.
758                 packages << "\\usepackage{nomencl}\n"
759                             "% the following is useful when we have the old nomencl.sty package\n"
760                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
761                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
762                             "\\makenomenclature\n";
763         }
764
765         return packages.str();
766 }
767
768
769 string LaTeXFeatures::getPreambleSnippets() const 
770 {
771         ostringstream snip;
772         SnippetList::const_iterator pit  = preamble_snippets_.begin();
773         SnippetList::const_iterator pend = preamble_snippets_.end();
774         for (; pit != pend; ++pit) {
775                 LYXERR0(*pit);
776                 snip << *pit << '\n';
777         }
778         LYXERR0(snip.str());
779         return snip.str();
780 }
781
782
783 docstring const LaTeXFeatures::getMacros() const
784 {
785         odocstringstream macros;
786
787         if (!preamble_snippets_.empty()) {
788                 macros << '\n';
789                 macros << from_utf8(getPreambleSnippets());
790         }
791
792         if (mustProvide("papersize")) {
793                 if (runparams_.flavor == OutputParams::LATEX)
794                         macros << papersizedvi_def << '\n';
795                 else
796                         macros << papersizepdf_def << '\n';
797         }
798
799         if (mustProvide("LyX"))
800                 macros << lyx_def << '\n';
801
802         if (mustProvide("lyxline"))
803                 macros << lyxline_def << '\n';
804
805         if (mustProvide("noun"))
806                 macros << noun_def << '\n';
807
808         if (mustProvide("lyxarrow"))
809                 macros << lyxarrow_def << '\n';
810
811         if (mustProvide("textgreek"))
812                 macros << textgreek_def << '\n';
813
814         if (mustProvide("textcyr"))
815                 macros << textcyr_def << '\n';
816
817         if (mustProvide("lyxmathsym"))
818                 macros << lyxmathsym_def << '\n';
819
820         if (mustProvide("cedilla"))
821                 macros << cedilla_def << '\n';
822
823         if (mustProvide("subring"))
824                 macros << subring_def << '\n';
825
826         if (mustProvide("subdot"))
827                 macros << subdot_def << '\n';
828
829         if (mustProvide("subhat"))
830                 macros << subhat_def << '\n';
831
832         if (mustProvide("subtilde"))
833                 macros << subtilde_def << '\n';
834
835         if (mustProvide("dacute"))
836                 macros << dacute_def << '\n';
837
838         if (mustProvide("tipasymb"))
839                 macros << tipasymb_def << '\n';
840
841         if (mustProvide("dgrave"))
842                 macros << dgrave_def << '\n';
843
844         if (mustProvide("rcap"))
845                 macros << rcap_def << '\n';
846
847         if (mustProvide("ogonek"))
848                 macros << ogonek_def << '\n';
849
850         // quotes.
851         if (mustProvide("quotesinglbase"))
852                 macros << quotesinglbase_def << '\n';
853         if (mustProvide("quotedblbase"))
854                 macros << quotedblbase_def << '\n';
855         if (mustProvide("guilsinglleft"))
856                 macros << guilsinglleft_def << '\n';
857         if (mustProvide("guilsinglright"))
858                 macros << guilsinglright_def << '\n';
859         if (mustProvide("guillemotleft"))
860                 macros << guillemotleft_def << '\n';
861         if (mustProvide("guillemotright"))
862                 macros << guillemotright_def << '\n';
863
864         // Math mode
865         if (mustProvide("binom") && !isRequired("amsmath"))
866                 macros << binom_def << '\n';
867         if (mustProvide("mathcircumflex"))
868                 macros << mathcircumflex_def << '\n';
869
870         // other
871         if (mustProvide("ParagraphLeftIndent"))
872                 macros << paragraphleftindent_def;
873         if (mustProvide("NeedLyXFootnoteCode"))
874                 macros << floatingfootnote_def;
875
876         // some problems with tex->html converters
877         if (mustProvide("NeedTabularnewline"))
878                 macros << tabularnewline_def;
879
880         // greyedout environment (note inset)
881         if (mustProvide("lyxgreyedout"))
882                 macros << lyxgreyedout_def;
883
884         if (mustProvide("lyxdot"))
885                 macros << lyxdot_def << '\n';
886
887         // floats
888         getFloatDefinitions(macros);
889
890         // change tracking
891         if (mustProvide("ct-dvipost"))
892                 macros << changetracking_dvipost_def;
893
894         if (mustProvide("ct-xcolor-ulem")) {
895                 int const prec = macros.precision(2);
896         
897                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
898                 macros << "\\providecolor{lyxadded}{rgb}{"
899                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
900
901                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
902                 macros << "\\providecolor{lyxdeleted}{rgb}{"
903                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
904
905                 macros.precision(prec);
906                 
907                 if (isRequired("hyperref"))
908                         macros << changetracking_xcolor_ulem_hyperref_def;
909                 else
910                         macros << changetracking_xcolor_ulem_def;
911         }
912
913         if (mustProvide("ct-none"))
914                 macros << changetracking_none_def;
915
916         return macros.str();
917 }
918
919
920 string const LaTeXFeatures::getBabelOptions() const
921 {
922         ostringstream tmp;
923
924         LanguageList::const_iterator it  = UsedLanguages_.begin();
925         LanguageList::const_iterator end =  UsedLanguages_.end();
926         for (; it != end; ++it)
927                 if (!(*it)->latex_options().empty())
928                         tmp << (*it)->latex_options() << '\n';
929         if (!params_.language->latex_options().empty())
930                 tmp << params_.language->latex_options() << '\n';
931
932         return tmp.str();
933 }
934
935
936 docstring const LaTeXFeatures::getTClassPreamble() const
937 {
938         // the text class specific preamble
939         DocumentClass const & tclass = params_.documentClass();
940         odocstringstream tcpreamble;
941
942         tcpreamble << tclass.preamble();
943
944         list<docstring>::const_iterator cit = usedLayouts_.begin();
945         list<docstring>::const_iterator end = usedLayouts_.end();
946         for (; cit != end; ++cit)
947                 tcpreamble << tclass[*cit].preamble();
948
949         cit = usedInsetLayouts_.begin();
950         end = usedInsetLayouts_.end();
951         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
952         for (; cit != end; ++cit) {
953                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
954                 if (it == ils.end())
955                         continue;
956                 tcpreamble << it->second.preamble();
957         }
958
959         return tcpreamble.str();
960 }
961
962
963 docstring const LaTeXFeatures::getTClassHTMLPreamble() const 
964 {
965         DocumentClass const & tclass = params_.documentClass();
966         odocstringstream tcpreamble;
967
968         tcpreamble << tclass.htmlpreamble();
969
970         list<docstring>::const_iterator cit = usedLayouts_.begin();
971         list<docstring>::const_iterator end = usedLayouts_.end();
972         for (; cit != end; ++cit)
973                 tcpreamble << tclass[*cit].htmlpreamble();
974
975         cit = usedInsetLayouts_.begin();
976         end = usedInsetLayouts_.end();
977         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
978         for (; cit != end; ++cit) {
979                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
980                 if (it == ils.end())
981                         continue;
982                 tcpreamble << it->second.htmlpreamble();
983         }
984
985         return tcpreamble.str();
986 }
987
988
989 docstring const LaTeXFeatures::getTClassHTMLStyles() const {
990         DocumentClass const & tclass = params_.documentClass();
991         odocstringstream tcpreamble;
992
993         list<docstring>::const_iterator cit = usedLayouts_.begin();
994         list<docstring>::const_iterator end = usedLayouts_.end();
995         for (; cit != end; ++cit)
996                 tcpreamble << tclass[*cit].htmlstyle();
997
998         cit = usedInsetLayouts_.begin();
999         end = usedInsetLayouts_.end();
1000         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1001         for (; cit != end; ++cit) {
1002                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1003                 if (it == ils.end())
1004                         continue;
1005                 tcpreamble << it->second.htmlstyle();
1006         }
1007
1008         return tcpreamble.str();
1009 }
1010
1011
1012 namespace {
1013 docstring const getFloatI18nPreamble(docstring const & type, docstring const & name, docstring const & lang)
1014 {
1015         odocstringstream os;
1016         os << "\\addto\\captions" << lang
1017            << "{\\renewcommand{\\" << type << "name}{" << name << "}}\n";
1018         return os.str();
1019 }
1020 }
1021
1022
1023 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel) const
1024 {
1025         DocumentClass const & tclass = params_.documentClass();
1026         // collect preamble snippets in a set to prevent multiple identical
1027         // commands (would happen if e.g. both theorem and theorem* are used)
1028         set<docstring> snippets;
1029         typedef LanguageList::const_iterator lang_it;
1030         lang_it const lbeg = UsedLanguages_.begin();
1031         lang_it const lend =  UsedLanguages_.end();
1032         list<docstring>::const_iterator cit = usedLayouts_.begin();
1033         list<docstring>::const_iterator end = usedLayouts_.end();
1034         for (; cit != end; ++cit) {
1035                 // language dependent commands (once per document)
1036                 snippets.insert(tclass[*cit].langpreamble(buffer().language()));
1037                 // commands for language changing (for multilanguage documents)
1038                 if (use_babel && !UsedLanguages_.empty()) {
1039                         snippets.insert(tclass[*cit].babelpreamble(buffer().language()));
1040                         for (lang_it lit = lbeg; lit != lend; ++lit)
1041                                 snippets.insert(tclass[*cit].babelpreamble(*lit));
1042                 }
1043         }
1044         if (use_babel && !UsedLanguages_.empty()) {
1045                 FloatList const & floats = params_.documentClass().floats();
1046                 UsedFloats::const_iterator fit = usedFloats_.begin();
1047                 UsedFloats::const_iterator fend = usedFloats_.end();
1048                 for (; fit != fend; ++fit) {
1049                         Floating const & fl = floats.getType(fit->first);
1050                         docstring const type = from_ascii(fl.type());
1051                         docstring const flname = from_utf8(fl.name());
1052                         docstring name = translateIfPossible(flname,
1053                                 buffer().language()->code());
1054                         snippets.insert(getFloatI18nPreamble(
1055                                 type, name,
1056                                 from_ascii(buffer().language()->babel())));
1057                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1058                                 name = translateIfPossible(flname,
1059                                         (*lit)->code());
1060                                 snippets.insert(getFloatI18nPreamble(
1061                                         type, name,
1062                                         from_ascii((*lit)->babel())));
1063                         }
1064                 }
1065         }
1066
1067         odocstringstream tcpreamble;
1068         set<docstring>::const_iterator const send = snippets.end();
1069         set<docstring>::const_iterator it = snippets.begin();
1070         for (; it != send; ++it)
1071                 tcpreamble << *it;
1072         return tcpreamble.str();
1073 }
1074
1075
1076 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1077 {
1078         // Definition of entities used in the document that are LyX related.
1079         odocstringstream entities;
1080
1081         if (mustProvide("lyxarrow")) {
1082                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1083         }
1084
1085         return entities.str();
1086 }
1087
1088
1089 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1090 {
1091         odocstringstream sgmlpreamble;
1092         // FIXME UNICODE
1093         docstring const basename(from_utf8(onlyPath(fname)));
1094
1095         FileMap::const_iterator end = IncludedFiles_.end();
1096         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1097              fi != end; ++fi)
1098                 // FIXME UNICODE
1099                 sgmlpreamble << "\n<!ENTITY " << fi->first
1100                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
1101                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1102
1103         return sgmlpreamble.str();
1104 }
1105
1106
1107 void LaTeXFeatures::showStruct() const
1108 {
1109         lyxerr << "LyX needs the following commands when LaTeXing:"
1110                << "\n***** Packages:" << getPackages()
1111                << "\n***** Macros:" << to_utf8(getMacros())
1112                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1113                << "\n***** done." << endl;
1114 }
1115
1116
1117 Buffer const & LaTeXFeatures::buffer() const
1118 {
1119         return *buffer_;
1120 }
1121
1122
1123 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1124 {
1125         buffer_ = &buffer;
1126 }
1127
1128
1129 BufferParams const & LaTeXFeatures::bufferParams() const
1130 {
1131         return params_;
1132 }
1133
1134
1135 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1136 {
1137         FloatList const & floats = params_.documentClass().floats();
1138
1139         // Here we will output the code to create the needed float styles.
1140         // We will try to do this as minimal as possible.
1141         // \floatstyle{ruled}
1142         // \newfloat{algorithm}{htbp}{loa}
1143         // \providecommand{\algorithmname}{Algorithm}
1144         // \floatname{algorithm}{\protect\algorithmname}
1145         UsedFloats::const_iterator cit = usedFloats_.begin();
1146         UsedFloats::const_iterator end = usedFloats_.end();
1147         for (; cit != end; ++cit) {
1148                 Floating const & fl = floats.getType(cit->first);
1149
1150                 // For builtin floats we do nothing.
1151                 if (fl.builtin()) continue;
1152
1153                 // We have to special case "table" and "figure"
1154                 if (fl.type() == "tabular" || fl.type() == "figure") {
1155                         // Output code to modify "table" or "figure"
1156                         // but only if builtin == false
1157                         // and that have to be true at this point in the
1158                         // function.
1159                         docstring const type = from_ascii(fl.type());
1160                         docstring const placement = from_ascii(fl.placement());
1161                         docstring const style = from_ascii(fl.style());
1162                         if (!style.empty()) {
1163                                 os << "\\floatstyle{" << style << "}\n"
1164                                    << "\\restylefloat{" << type << "}\n";
1165                         }
1166                         if (!placement.empty()) {
1167                                 os << "\\floatplacement{" << type << "}{"
1168                                    << placement << "}\n";
1169                         }
1170                 } else {
1171                         // The other non builtin floats.
1172
1173                         docstring const type = from_ascii(fl.type());
1174                         docstring const placement = from_ascii(fl.placement());
1175                         docstring const ext = from_ascii(fl.ext());
1176                         docstring const within = from_ascii(fl.within());
1177                         docstring const style = from_ascii(fl.style());
1178                         docstring const name = translateIfPossible(
1179                                         from_utf8(fl.name()),
1180                                         buffer().language()->code());
1181                         os << "\\floatstyle{" << style << "}\n"
1182                            << "\\newfloat{" << type << "}{" << placement
1183                            << "}{" << ext << '}';
1184                         if (!within.empty())
1185                                 os << '[' << within << ']';
1186                         os << '\n'
1187                            << "\\providecommand{\\" << type << "name}{"
1188                            << name << "}\n"
1189                            << "\\floatname{" << type << "}{\\protect\\"
1190                            << type << "name}\n";
1191
1192                         // What missing here is to code to minimalize the code
1193                         // output so that the same floatstyle will not be
1194                         // used several times, when the same style is still in
1195                         // effect. (Lgb)
1196                 }
1197                 if (cit->second)
1198                         os << "\n\\newsubfloat{" << from_ascii(fl.type()) << "}\n";
1199         }
1200 }
1201
1202
1203 } // namespace lyx