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