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