]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
fix bug 5798: Translate float names
[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         "\\DeclareRobustCommand{\\greektext}{%\n"
199         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
200         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
201         "\\DeclareFontEncoding{LGR}{}{}\n");
202
203 static docstring const textcyr_def = from_ascii(
204         "\\DeclareRobustCommand{\\cyrtext}{%\n"
205         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
206         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
207         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
208
209 static docstring const lyxmathsym_def = from_ascii(
210         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
211         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
212
213 static docstring const papersizedvi_def = from_ascii(
214         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
215
216 static docstring const papersizepdf_def = from_ascii(
217         "\\pdfpageheight\\paperheight\n"
218         "\\pdfpagewidth\\paperwidth\n");
219
220 static docstring const cedilla_def = from_ascii(
221         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
222         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
223
224 static docstring const subring_def = from_ascii(
225         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
226         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
227
228 static docstring const subdot_def = from_ascii(
229         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
230         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
231
232 static docstring const subhat_def = from_ascii(
233         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
234         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
235
236 static docstring const subtilde_def = from_ascii(
237         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
238         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
239
240 static docstring const dacute_def = from_ascii(
241         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
242
243 static docstring const tipasymb_def = from_ascii(
244         "\\DeclareFontEncoding{T3}{}{}\n"
245         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
246
247 static docstring const dgrave_def = from_ascii(
248         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
249
250 static docstring const rcap_def = from_ascii(
251         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
252
253 static docstring const ogonek_def = from_ascii(
254         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
255         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
256         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
257         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
258         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
259
260 /////////////////////////////////////////////////////////////////////
261 //
262 // LaTeXFeatures
263 //
264 /////////////////////////////////////////////////////////////////////
265
266 LaTeXFeatures::Packages LaTeXFeatures::packages_;
267
268
269 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
270                              OutputParams const & r)
271         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
272 {}
273
274
275 bool LaTeXFeatures::useBabel() const
276 {
277         return lyxrc.language_use_babel ||
278                 (bufferParams().language->lang() != lyxrc.default_language &&
279                  !bufferParams().language->babel().empty()) ||
280                 this->hasLanguages();
281 }
282
283
284 void LaTeXFeatures::require(string const & name)
285 {
286         features_.insert(name);
287 }
288
289
290 void LaTeXFeatures::require(set<string> const & names)
291 {
292         features_.insert(names.begin(), names.end());
293 }
294
295
296 void LaTeXFeatures::getAvailable()
297 {
298         Lexer lex;
299         support::FileName const real_file = libFileSearch("", "packages.lst");
300
301         if (real_file.empty())
302                 return;
303
304         lex.setFile(real_file);
305
306         if (!lex.isOK())
307                 return;
308
309         // Make sure that we are clean
310         packages_.clear();
311
312         bool finished = false;
313         // Parse config-file
314         while (lex.isOK() && !finished) {
315                 switch (lex.lex()) {
316                 case Lexer::LEX_FEOF:
317                         finished = true;
318                         break;
319                 default:
320                         packages_.insert(lex.getString());
321                 }
322         }
323 }
324
325
326 void LaTeXFeatures::useLayout(docstring const & layoutname)
327 {
328         // Some code to avoid loops in dependency definition
329         static int level = 0;
330         const int maxlevel = 30;
331         if (level > maxlevel) {
332                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
333                        << "recursion attained by layout "
334                        << to_utf8(layoutname) << endl;
335                 return;
336         }
337
338         DocumentClass const & tclass = params_.documentClass();
339         if (tclass.hasLayout(layoutname)) {
340                 // Is this layout already in usedLayouts?
341                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
342                     != usedLayouts_.end())
343                         return;
344
345                 Layout const & layout = tclass[layoutname];
346                 require(layout.requires());
347
348                 if (!layout.depends_on().empty()) {
349                         ++level;
350                         useLayout(layout.depends_on());
351                         --level;
352                 }
353                 usedLayouts_.push_back(layoutname);
354         } else {
355                 lyxerr << "LaTeXFeatures::useLayout: layout `"
356                        << to_utf8(layoutname) << "' does not exist in this class"
357                        << endl;
358         }
359
360         --level;
361 }
362
363
364 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
365 {
366         docstring const & lname = lay.name();
367         DocumentClass const & tclass = params_.documentClass();
368         if (!tclass.hasInsetLayout(lname)) {
369                 lyxerr << "LaTeXFeatures::useInsetLayout: layout `"
370                        << to_utf8(lname) << "' does not exist in this class"
371                        << endl;
372                 return;
373         }
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         // [x]color and pdfcolmk are handled in getColorOptions() above
653         
654         // makeidx.sty
655         if (isRequired("makeidx") || isRequired("splitidx")) {
656                 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
657                         packages << "\\usepackage{makeidx}\n";
658                 if (!tclass.provides("splitidx") && isRequired("splitidx"))
659                         packages << "\\usepackage{splitidx}\n";
660                 packages << "\\makeindex\n";
661         }
662
663         // graphicx.sty
664         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
665                 if (params_.graphicsDriver == "default")
666                         packages << "\\usepackage{graphicx}\n";
667                 else
668                         packages << "\\usepackage["
669                                  << params_.graphicsDriver
670                                  << "]{graphicx}\n";
671         }
672         // shadecolor for shaded
673         if (isRequired("framed") && mustProvide("color")) {
674                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
675                 //255.0 to force conversion to double
676                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
677                 //to use the xcolor package instead, and then we can do
678                 // \define{shadcolor}{RGB}...
679                 //and not do any conversion. We'd then need to require xcolor
680                 //in InsetNote::validate().
681                 int const stmSize = packages.precision(2);
682                 packages << "\\definecolor{shadecolor}{rgb}{"
683                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
684                 packages.precision(stmSize);
685         }
686
687         // lyxskak.sty --- newer chess support based on skak.sty
688         if (mustProvide("chess"))
689                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
690
691         // setspace.sty
692         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
693                 packages << "\\usepackage{setspace}\n";
694
695         // amssymb.sty
696         if (mustProvide("amssymb")
697             || params_.use_amsmath == BufferParams::package_on)
698                 packages << "\\usepackage{amssymb}\n";
699
700         // esint must be after amsmath and wasysym, since it will redeclare
701         // inconsistent integral symbols
702         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
703             params_.use_esint != BufferParams::package_off)
704                 packages << "\\usepackage{esint}\n";
705
706         // natbib.sty
707         // Some classes load natbib themselves, but still allow (or even require)
708         // plain numeric citations (ReVTeX is such a case, see bug 5182).
709         // This special case is indicated by the "natbib-internal" key.
710         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
711                 packages << "\\usepackage[";
712                 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
713                         packages << "numbers";
714                 else
715                         packages << "authoryear";
716                 packages << "]{natbib}\n";
717         }
718
719         // jurabib -- we need version 0.6 at least.
720         if (mustProvide("jurabib"))
721                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
722         
723         // xargs -- we need version 1.09 at least
724         if (mustProvide("xargs"))
725                 packages << "\\usepackage{xargs}[2008/03/08]\n";
726
727         // bibtopic -- the dot provides the aux file naming which
728         // LyX can detect.
729         if (mustProvide("bibtopic"))
730                 packages << "\\usepackage[dot]{bibtopic}\n";
731
732         if (mustProvide("xy"))
733                 packages << "\\usepackage[all]{xy}\n";
734
735         if (mustProvide("ulem"))
736                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
737                             "\\usepackage{ulem}\n";
738
739         if (mustProvide("nomencl")) {
740                 // Make it work with the new and old version of the package,
741                 // but don't use the compatibility option since it is
742                 // incompatible to other packages.
743                 packages << "\\usepackage{nomencl}\n"
744                             "% the following is useful when we have the old nomencl.sty package\n"
745                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
746                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
747                             "\\makenomenclature\n";
748         }
749
750         return packages.str();
751 }
752
753
754 docstring const LaTeXFeatures::getMacros() const
755 {
756         odocstringstream macros;
757
758         if (!preamble_snippets_.empty())
759                 macros << '\n';
760         SnippetList::const_iterator pit  = preamble_snippets_.begin();
761         SnippetList::const_iterator pend = preamble_snippets_.end();
762         for (; pit != pend; ++pit)
763                 macros << *pit << '\n';
764
765         if (mustProvide("papersize")) {
766                 if (runparams_.flavor == OutputParams::LATEX)
767                         macros << papersizedvi_def << '\n';
768                 else
769                         macros << papersizepdf_def << '\n';
770         }
771
772         if (mustProvide("LyX"))
773                 macros << lyx_def << '\n';
774
775         if (mustProvide("lyxline"))
776                 macros << lyxline_def << '\n';
777
778         if (mustProvide("noun"))
779                 macros << noun_def << '\n';
780
781         if (mustProvide("lyxarrow"))
782                 macros << lyxarrow_def << '\n';
783
784         if (mustProvide("textgreek"))
785                 macros << textgreek_def << '\n';
786
787         if (mustProvide("textcyr"))
788                 macros << textcyr_def << '\n';
789
790         if (mustProvide("lyxmathsym"))
791                 macros << lyxmathsym_def << '\n';
792
793         if (mustProvide("cedilla"))
794                 macros << cedilla_def << '\n';
795
796         if (mustProvide("subring"))
797                 macros << subring_def << '\n';
798
799         if (mustProvide("subdot"))
800                 macros << subdot_def << '\n';
801
802         if (mustProvide("subhat"))
803                 macros << subhat_def << '\n';
804
805         if (mustProvide("subtilde"))
806                 macros << subtilde_def << '\n';
807
808         if (mustProvide("dacute"))
809                 macros << dacute_def << '\n';
810
811         if (mustProvide("tipasymb"))
812                 macros << tipasymb_def << '\n';
813
814         if (mustProvide("dgrave"))
815                 macros << dgrave_def << '\n';
816
817         if (mustProvide("rcap"))
818                 macros << rcap_def << '\n';
819
820         if (mustProvide("ogonek"))
821                 macros << ogonek_def << '\n';
822
823         // quotes.
824         if (mustProvide("quotesinglbase"))
825                 macros << quotesinglbase_def << '\n';
826         if (mustProvide("quotedblbase"))
827                 macros << quotedblbase_def << '\n';
828         if (mustProvide("guilsinglleft"))
829                 macros << guilsinglleft_def << '\n';
830         if (mustProvide("guilsinglright"))
831                 macros << guilsinglright_def << '\n';
832         if (mustProvide("guillemotleft"))
833                 macros << guillemotleft_def << '\n';
834         if (mustProvide("guillemotright"))
835                 macros << guillemotright_def << '\n';
836
837         // Math mode
838         if (mustProvide("binom") && !isRequired("amsmath"))
839                 macros << binom_def << '\n';
840         if (mustProvide("mathcircumflex"))
841                 macros << mathcircumflex_def << '\n';
842
843         // other
844         if (mustProvide("ParagraphLeftIndent"))
845                 macros << paragraphleftindent_def;
846         if (mustProvide("NeedLyXFootnoteCode"))
847                 macros << floatingfootnote_def;
848
849         // some problems with tex->html converters
850         if (mustProvide("NeedTabularnewline"))
851                 macros << tabularnewline_def;
852
853         // greyedout environment (note inset)
854         if (mustProvide("lyxgreyedout"))
855                 macros << lyxgreyedout_def;
856
857         if (mustProvide("lyxdot"))
858                 macros << lyxdot_def << '\n';
859
860         // floats
861         getFloatDefinitions(macros);
862
863         // change tracking
864         if (mustProvide("ct-dvipost"))
865                 macros << changetracking_dvipost_def;
866
867         if (mustProvide("ct-xcolor-ulem")) {
868                 int const prec = macros.precision(2);
869         
870                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
871                 macros << "\\providecolor{lyxadded}{rgb}{"
872                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
873
874                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
875                 macros << "\\providecolor{lyxdeleted}{rgb}{"
876                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
877
878                 macros.precision(prec);
879                 
880                 if (isRequired("hyperref"))
881                         macros << changetracking_xcolor_ulem_hyperref_def;
882                 else
883                         macros << changetracking_xcolor_ulem_def;
884         }
885
886         if (mustProvide("ct-none"))
887                 macros << changetracking_none_def;
888
889         return macros.str();
890 }
891
892
893 string const LaTeXFeatures::getBabelOptions() const
894 {
895         ostringstream tmp;
896
897         LanguageList::const_iterator it  = UsedLanguages_.begin();
898         LanguageList::const_iterator end =  UsedLanguages_.end();
899         for (; it != end; ++it)
900                 if (!(*it)->latex_options().empty())
901                         tmp << (*it)->latex_options() << '\n';
902         if (!params_.language->latex_options().empty())
903                 tmp << params_.language->latex_options() << '\n';
904
905         return tmp.str();
906 }
907
908
909 docstring const LaTeXFeatures::getTClassPreamble() const
910 {
911         // the text class specific preamble
912         DocumentClass const & tclass = params_.documentClass();
913         odocstringstream tcpreamble;
914
915         tcpreamble << tclass.preamble();
916
917         list<docstring>::const_iterator cit = usedLayouts_.begin();
918         list<docstring>::const_iterator end = usedLayouts_.end();
919         for (; cit != end; ++cit)
920                 tcpreamble << tclass[*cit].preamble();
921
922         cit = usedInsetLayouts_.begin();
923         end = usedInsetLayouts_.end();
924         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
925         for (; cit != end; ++cit) {
926                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
927                 if (it == ils.end())
928                         continue;
929                 tcpreamble << it->second.preamble();
930         }
931
932         return tcpreamble.str();
933 }
934
935
936 docstring const LaTeXFeatures::getTClassHTMLPreamble() const 
937 {
938         DocumentClass const & tclass = params_.documentClass();
939         odocstringstream tcpreamble;
940
941         tcpreamble << tclass.htmlpreamble();
942
943         list<docstring>::const_iterator cit = usedLayouts_.begin();
944         list<docstring>::const_iterator end = usedLayouts_.end();
945         for (; cit != end; ++cit)
946                 tcpreamble << tclass[*cit].htmlpreamble();
947
948         cit = usedInsetLayouts_.begin();
949         end = usedInsetLayouts_.end();
950         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
951         for (; cit != end; ++cit) {
952                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
953                 if (it == ils.end())
954                         continue;
955                 tcpreamble << it->second.htmlpreamble();
956         }
957
958         return tcpreamble.str();
959 }
960
961
962 docstring const LaTeXFeatures::getTClassHTMLStyles() const {
963         DocumentClass const & tclass = params_.documentClass();
964         odocstringstream tcpreamble;
965
966         list<docstring>::const_iterator cit = usedLayouts_.begin();
967         list<docstring>::const_iterator end = usedLayouts_.end();
968         for (; cit != end; ++cit)
969                 tcpreamble << tclass[*cit].htmlstyle();
970
971         cit = usedInsetLayouts_.begin();
972         end = usedInsetLayouts_.end();
973         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
974         for (; cit != end; ++cit) {
975                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
976                 if (it == ils.end())
977                         continue;
978                 tcpreamble << it->second.htmlstyle();
979         }
980
981         return tcpreamble.str();
982 }
983
984
985 namespace {
986 docstring const getFloatI18nPreamble(docstring const & type, docstring const & name, docstring const & lang)
987 {
988         odocstringstream os;
989         os << "\\addto\\captions" << lang
990            << "{\\renewcommand{\\" << type << "name}{" << name << "}}\n";
991         return os.str();
992 }
993 }
994
995
996 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel) const
997 {
998         DocumentClass const & tclass = params_.documentClass();
999         // collect preamble snippets in a set to prevent multiple identical
1000         // commands (would happen if e.g. both theorem and theorem* are used)
1001         set<docstring> snippets;
1002         typedef LanguageList::const_iterator lang_it;
1003         lang_it const lbeg = UsedLanguages_.begin();
1004         lang_it const lend =  UsedLanguages_.end();
1005         list<docstring>::const_iterator cit = usedLayouts_.begin();
1006         list<docstring>::const_iterator end = usedLayouts_.end();
1007         for (; cit != end; ++cit) {
1008                 // language dependent commands (once per document)
1009                 snippets.insert(tclass[*cit].langpreamble(buffer().language()));
1010                 // commands for language changing (for multilanguage documents)
1011                 if (use_babel && !UsedLanguages_.empty()) {
1012                         snippets.insert(tclass[*cit].babelpreamble(buffer().language()));
1013                         for (lang_it lit = lbeg; lit != lend; ++lit)
1014                                 snippets.insert(tclass[*cit].babelpreamble(*lit));
1015                 }
1016         }
1017         if (use_babel && !UsedLanguages_.empty()) {
1018                 FloatList const & floats = params_.documentClass().floats();
1019                 UsedFloats::const_iterator fit = usedFloats_.begin();
1020                 UsedFloats::const_iterator fend = usedFloats_.end();
1021                 for (; fit != fend; ++fit) {
1022                         Floating const & fl = floats.getType(fit->first);
1023                         docstring const type = from_ascii(fl.type());
1024                         docstring const flname = from_utf8(fl.name());
1025                         docstring name = translateIfPossible(flname,
1026                                 buffer().language()->code());
1027                         snippets.insert(getFloatI18nPreamble(
1028                                 type, name,
1029                                 from_ascii(buffer().language()->babel())));
1030                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1031                                 name = translateIfPossible(flname,
1032                                         (*lit)->code());
1033                                 snippets.insert(getFloatI18nPreamble(
1034                                         type, name,
1035                                         from_ascii((*lit)->babel())));
1036                         }
1037                 }
1038         }
1039
1040         odocstringstream tcpreamble;
1041         set<docstring>::const_iterator const send = snippets.end();
1042         set<docstring>::const_iterator it = snippets.begin();
1043         for (; it != send; ++it)
1044                 tcpreamble << *it;
1045         return tcpreamble.str();
1046 }
1047
1048
1049 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1050 {
1051         // Definition of entities used in the document that are LyX related.
1052         odocstringstream entities;
1053
1054         if (mustProvide("lyxarrow")) {
1055                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1056         }
1057
1058         return entities.str();
1059 }
1060
1061
1062 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1063 {
1064         odocstringstream sgmlpreamble;
1065         // FIXME UNICODE
1066         docstring const basename(from_utf8(onlyPath(fname)));
1067
1068         FileMap::const_iterator end = IncludedFiles_.end();
1069         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1070              fi != end; ++fi)
1071                 // FIXME UNICODE
1072                 sgmlpreamble << "\n<!ENTITY " << fi->first
1073                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
1074                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1075
1076         return sgmlpreamble.str();
1077 }
1078
1079
1080 void LaTeXFeatures::showStruct() const
1081 {
1082         lyxerr << "LyX needs the following commands when LaTeXing:"
1083                << "\n***** Packages:" << getPackages()
1084                << "\n***** Macros:" << to_utf8(getMacros())
1085                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1086                << "\n***** done." << endl;
1087 }
1088
1089
1090 Buffer const & LaTeXFeatures::buffer() const
1091 {
1092         return *buffer_;
1093 }
1094
1095
1096 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1097 {
1098         buffer_ = &buffer;
1099 }
1100
1101
1102 BufferParams const & LaTeXFeatures::bufferParams() const
1103 {
1104         return params_;
1105 }
1106
1107
1108 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1109 {
1110         FloatList const & floats = params_.documentClass().floats();
1111
1112         // Here we will output the code to create the needed float styles.
1113         // We will try to do this as minimal as possible.
1114         // \floatstyle{ruled}
1115         // \newfloat{algorithm}{htbp}{loa}
1116         // \providecommand{\algorithmname}{Algorithm}
1117         // \floatname{algorithm}{\protect\algorithmname}
1118         UsedFloats::const_iterator cit = usedFloats_.begin();
1119         UsedFloats::const_iterator end = usedFloats_.end();
1120         for (; cit != end; ++cit) {
1121                 Floating const & fl = floats.getType(cit->first);
1122
1123                 // For builtin floats we do nothing.
1124                 if (fl.builtin()) continue;
1125
1126                 // We have to special case "table" and "figure"
1127                 if (fl.type() == "tabular" || fl.type() == "figure") {
1128                         // Output code to modify "table" or "figure"
1129                         // but only if builtin == false
1130                         // and that have to be true at this point in the
1131                         // function.
1132                         docstring const type = from_ascii(fl.type());
1133                         docstring const placement = from_ascii(fl.placement());
1134                         docstring const style = from_ascii(fl.style());
1135                         if (!style.empty()) {
1136                                 os << "\\floatstyle{" << style << "}\n"
1137                                    << "\\restylefloat{" << type << "}\n";
1138                         }
1139                         if (!placement.empty()) {
1140                                 os << "\\floatplacement{" << type << "}{"
1141                                    << placement << "}\n";
1142                         }
1143                 } else {
1144                         // The other non builtin floats.
1145
1146                         docstring const type = from_ascii(fl.type());
1147                         docstring const placement = from_ascii(fl.placement());
1148                         docstring const ext = from_ascii(fl.ext());
1149                         docstring const within = from_ascii(fl.within());
1150                         docstring const style = from_ascii(fl.style());
1151                         docstring const name = translateIfPossible(
1152                                         from_utf8(fl.name()),
1153                                         buffer().language()->code());
1154                         os << "\\floatstyle{" << style << "}\n"
1155                            << "\\newfloat{" << type << "}{" << placement
1156                            << "}{" << ext << '}';
1157                         if (!within.empty())
1158                                 os << '[' << within << ']';
1159                         os << '\n'
1160                            << "\\providecommand{\\" << type << "name}{"
1161                            << name << "}\n"
1162                            << "\\floatname{" << type << "}{\\protect\\"
1163                            << type << "name}\n";
1164
1165                         // What missing here is to code to minimalize the code
1166                         // output so that the same floatstyle will not be
1167                         // used several times, when the same style is still in
1168                         // effect. (Lgb)
1169                 }
1170                 if (cit->second)
1171                         os << "\n\\newsubfloat{" << from_ascii(fl.type()) << "}\n";
1172         }
1173 }
1174
1175
1176 } // namespace lyx