]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Simplify the definition of multi-accented polytonic Greek, patch by Günter Milde.
[lyx.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "Layout.h"
28 #include "Lexer.h"
29 #include "LyXRC.h"
30 #include "TextClass.h"
31
32 #include "insets/InsetLayout.h"
33
34 #include "support/debug.h"
35 #include "support/docstream.h"
36 #include "support/FileName.h"
37 #include "support/filetools.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
40
41 using namespace std;
42 using namespace lyx::support;
43
44
45 namespace lyx {
46
47 /////////////////////////////////////////////////////////////////////
48 //
49 // Strings
50 //
51 /////////////////////////////////////////////////////////////////////
52
53 //\NeedsTeXFormat{LaTeX2e}
54 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
55 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
56
57 static docstring const lyx_def = from_ascii(
58         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
59
60 static docstring const lyxline_def = from_ascii(
61         "\\newcommand{\\lyxline}[1][1pt]{%\n"
62         "  \\par\\noindent%\n"
63         "  \\rule[.5ex]{\\linewidth}{#1}\\par}");
64
65 static docstring const noun_def = from_ascii(
66         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
67
68 static docstring const lyxarrow_def = from_ascii(
69         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
70         "\\@ifstar\n"
71         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
72         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
73
74 // for quotes without babel. This does not give perfect results, but
75 // anybody serious about non-english quotes should use babel (JMarc).
76
77 static docstring const quotedblbase_def = from_ascii(
78         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
79         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
80         "  \\penalty10000\\hskip0em\\relax%\n"
81         "}");
82
83 static docstring const quotesinglbase_def = from_ascii(
84         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
85         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
86         "  \\penalty10000\\hskip0em\\relax%\n"
87         "}");
88
89 static docstring const guillemotleft_def = from_ascii(
90         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
91         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
92         "\\penalty10000\\hskip0pt\\relax%\n"
93         "}");
94
95 static docstring const guillemotright_def = from_ascii(
96         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
97         "  \\penalty10000\\hskip0pt%\n"
98         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
99         "}");
100
101 static docstring const guilsinglleft_def = from_ascii(
102         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
103         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
104         "  \\penalty10000\\hskip0pt\\relax%\n"
105         "}");
106
107 static docstring const guilsinglright_def = from_ascii(
108         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
109         "  \\penalty10000\\hskip0pt%\n"
110         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
111         "}");
112
113 static docstring const paragraphleftindent_def = from_ascii(
114         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
115         "{\n"
116         "  \\begin{list}{}{%\n"
117         "    \\setlength{\\topsep}{0pt}%\n"
118         "    \\addtolength{\\leftmargin}{#1}\n"
119 // ho hum, yet more things commented out with no hint as to why they
120 // weren't just removed
121 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
122 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
123 //      "%%    \\setlength\\listparindent\\parindent%\n"
124 //      "%%    \\setlength\\itemindent\\parindent%\n"
125         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
126         "  }\n"
127         "  \\item[]\n"
128         "}\n"
129         "{\\end{list}}\n");
130
131 static docstring const floatingfootnote_def = from_ascii(
132         "%% Special footnote code from the package 'stblftnt.sty'\n"
133         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
134         "\\let\\SF@@footnote\\footnote\n"
135         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
136         "    \\expandafter\\SF@@footnote\n"
137         "  \\else\n"
138         "    \\expandafter\\SF@gobble@opt\n"
139         "  \\fi\n"
140         "}\n"
141         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
142         "  \\SF@gobble@twobracket\n"
143         "  \\@gobble\n"
144         "}\n"
145         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
146         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
147         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
148
149 static docstring const binom_def = from_ascii(
150         "%% Binom macro for standard LaTeX users\n"
151         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
152
153 static docstring const mathcircumflex_def = from_ascii(
154         "%% For printing a cirumflex inside a formula\n"
155         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
156
157 static docstring const tabularnewline_def = from_ascii(
158         "%% Because html converters don't know tabularnewline\n"
159         "\\providecommand{\\tabularnewline}{\\\\}\n");
160         
161 static docstring const lyxgreyedout_def = from_ascii(
162         "%% The greyedout annotation environment\n"
163         "\\newenvironment{lyxgreyedout}{\\textcolor[gray]{0.8}\\bgroup}{\\egroup}\n");
164
165 // We want to omit the file extension for includegraphics, but this does not
166 // work when the filename contains other dots.
167 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
168 static docstring const lyxdot_def = from_ascii(
169         "%% A simple dot to overcome graphicx limitations\n"
170         "\\newcommand{\\lyxdot}{.}\n");
171
172 static docstring const changetracking_dvipost_def = from_ascii(
173         "%% Change tracking with dvipost\n"
174         "\\dvipostlayout\n"
175         "\\dvipost{osstart color push Red}\n"
176         "\\dvipost{osend color pop}\n"
177         "\\dvipost{cbstart color push Blue}\n"
178         "\\dvipost{cbend color pop}\n"
179         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
180         "\\newcommand{\\lyxdeleted}[3]{%\n"
181         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
182
183 static docstring const changetracking_xcolor_ulem_def = from_ascii(
184         "%% Change tracking with ulem\n"
185         "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
186         "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
187
188 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
189         "%% Change tracking with ulem\n"
190         "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
191         "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
192
193 static docstring const changetracking_none_def = from_ascii(
194         "\\newcommand{\\lyxadded}[3]{#3}\n"
195         "\\newcommand{\\lyxdeleted}[3]{}\n");
196
197 static docstring const textgreek_def = from_ascii(
198         "\\AtBeginDocument{\\DeclareRobustCommand{\\greektext}{%\n"
199         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}%\n"
200         "  \\renewcommand{\\~}{\\char126}%\n"
201         "}}\n"
202         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
203         "\\DeclareFontEncoding{LGR}{}{}\n");
204
205 static docstring const textcyr_def = from_ascii(
206         "\\DeclareRobustCommand{\\cyrtext}{%\n"
207         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
208         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
209         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
210
211 static docstring const lyxmathsym_def = from_ascii(
212         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
213         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
214
215 static docstring const papersizedvi_def = from_ascii(
216         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
217
218 static docstring const papersizepdf_def = from_ascii(
219         "\\pdfpageheight\\paperheight\n"
220         "\\pdfpagewidth\\paperwidth\n");
221
222 static docstring const cedilla_def = from_ascii(
223         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
224         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
225
226 static docstring const subring_def = from_ascii(
227         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
228         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
229
230 static docstring const subdot_def = from_ascii(
231         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
232         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
233
234 static docstring const subhat_def = from_ascii(
235         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
236         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
237
238 static docstring const subtilde_def = from_ascii(
239         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
240         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
241
242 static docstring const dacute_def = from_ascii(
243         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
244
245 static docstring const tipasymb_def = from_ascii(
246         "\\DeclareFontEncoding{T3}{}{}\n"
247         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
248
249 static docstring const dgrave_def = from_ascii(
250         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
251
252 static docstring const rcap_def = from_ascii(
253         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
254
255 static docstring const ogonek_def = from_ascii(
256         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
257         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
258         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
259         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
260         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
261
262 /////////////////////////////////////////////////////////////////////
263 //
264 // LaTeXFeatures
265 //
266 /////////////////////////////////////////////////////////////////////
267
268 LaTeXFeatures::Packages LaTeXFeatures::packages_;
269
270
271 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
272                              OutputParams const & r)
273         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
274 {}
275
276
277 bool LaTeXFeatures::useBabel() const
278 {
279         return lyxrc.language_use_babel ||
280                 (bufferParams().language->lang() != lyxrc.default_language &&
281                  !bufferParams().language->babel().empty()) ||
282                 this->hasLanguages();
283 }
284
285
286 void LaTeXFeatures::require(string const & name)
287 {
288         features_.insert(name);
289 }
290
291
292 void LaTeXFeatures::require(set<string> const & names)
293 {
294         features_.insert(names.begin(), names.end());
295 }
296
297
298 void LaTeXFeatures::getAvailable()
299 {
300         Lexer lex;
301         support::FileName const real_file = libFileSearch("", "packages.lst");
302
303         if (real_file.empty())
304                 return;
305
306         lex.setFile(real_file);
307
308         if (!lex.isOK())
309                 return;
310
311         // Make sure that we are clean
312         packages_.clear();
313
314         bool finished = false;
315         // Parse config-file
316         while (lex.isOK() && !finished) {
317                 switch (lex.lex()) {
318                 case Lexer::LEX_FEOF:
319                         finished = true;
320                         break;
321                 default:
322                         packages_.insert(lex.getString());
323                 }
324         }
325 }
326
327
328 void LaTeXFeatures::useLayout(docstring const & layoutname)
329 {
330         // Some code to avoid loops in dependency definition
331         static int level = 0;
332         const int maxlevel = 30;
333         if (level > maxlevel) {
334                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
335                        << "recursion attained by layout "
336                        << to_utf8(layoutname) << endl;
337                 return;
338         }
339
340         DocumentClass const & tclass = params_.documentClass();
341         if (tclass.hasLayout(layoutname)) {
342                 // Is this layout already in usedLayouts?
343                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
344                     != usedLayouts_.end())
345                         return;
346
347                 Layout const & layout = tclass[layoutname];
348                 require(layout.requires());
349
350                 if (!layout.depends_on().empty()) {
351                         ++level;
352                         useLayout(layout.depends_on());
353                         --level;
354                 }
355                 usedLayouts_.push_back(layoutname);
356         } else {
357                 lyxerr << "LaTeXFeatures::useLayout: layout `"
358                        << to_utf8(layoutname) << "' does not exist in this class"
359                        << endl;
360         }
361
362         --level;
363 }
364
365
366 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
367 {
368         docstring const & lname = lay.name();
369         DocumentClass const & tclass = params_.documentClass();
370
371         // this is a default inset layout, nothing useful here
372         if (!tclass.hasInsetLayout(lname))
373                 return;
374         // Is this layout already in usedInsetLayouts?
375         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname) 
376                         != usedInsetLayouts_.end())
377                 return;
378
379         require(lay.requires());
380         usedInsetLayouts_.push_back(lname);
381 }
382
383
384 bool LaTeXFeatures::isRequired(string const & name) const
385 {
386         return features_.find(name) != features_.end();
387 }
388
389
390 bool LaTeXFeatures::mustProvide(string const & name) const
391 {
392         return isRequired(name) && !params_.documentClass().provides(name);
393 }
394
395
396 bool LaTeXFeatures::isAvailable(string const & name)
397 {
398         string::size_type const i = name.find("->");
399         if (i != string::npos) {
400                 string const from = name.substr(0,i);
401                 string const to = name.substr(i+2);
402                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
403                 return theConverters().isReachable(from, to);
404         }
405
406         if (packages_.empty())
407                 getAvailable();
408         string n = name;
409         if (suffixIs(n, ".sty"))
410                 n.erase(name.length() - 4);
411         return packages_.find(n) != packages_.end();
412 }
413
414
415 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
416 {
417         LYXERR0(preamble);
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://bugzilla.lyx.org/show_bug.cgi?id=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                 LYXERR0(*pit);
775                 snip << *pit << '\n';
776         }
777         LYXERR0(snip.str());
778         return snip.str();
779 }
780
781
782 docstring const LaTeXFeatures::getMacros() const
783 {
784         odocstringstream macros;
785
786         if (!preamble_snippets_.empty()) {
787                 macros << '\n';
788                 macros << from_utf8(getPreambleSnippets());
789         }
790
791         if (mustProvide("papersize")) {
792                 if (runparams_.flavor == OutputParams::LATEX)
793                         macros << papersizedvi_def << '\n';
794                 else
795                         macros << papersizepdf_def << '\n';
796         }
797
798         if (mustProvide("LyX"))
799                 macros << lyx_def << '\n';
800
801         if (mustProvide("lyxline"))
802                 macros << lyxline_def << '\n';
803
804         if (mustProvide("noun"))
805                 macros << noun_def << '\n';
806
807         if (mustProvide("lyxarrow"))
808                 macros << lyxarrow_def << '\n';
809
810         if (mustProvide("textgreek"))
811                 macros << textgreek_def << '\n';
812
813         if (mustProvide("textcyr"))
814                 macros << textcyr_def << '\n';
815
816         if (mustProvide("lyxmathsym"))
817                 macros << lyxmathsym_def << '\n';
818
819         if (mustProvide("cedilla"))
820                 macros << cedilla_def << '\n';
821
822         if (mustProvide("subring"))
823                 macros << subring_def << '\n';
824
825         if (mustProvide("subdot"))
826                 macros << subdot_def << '\n';
827
828         if (mustProvide("subhat"))
829                 macros << subhat_def << '\n';
830
831         if (mustProvide("subtilde"))
832                 macros << subtilde_def << '\n';
833
834         if (mustProvide("dacute"))
835                 macros << dacute_def << '\n';
836
837         if (mustProvide("tipasymb"))
838                 macros << tipasymb_def << '\n';
839
840         if (mustProvide("dgrave"))
841                 macros << dgrave_def << '\n';
842
843         if (mustProvide("rcap"))
844                 macros << rcap_def << '\n';
845
846         if (mustProvide("ogonek"))
847                 macros << ogonek_def << '\n';
848
849         // quotes.
850         if (mustProvide("quotesinglbase"))
851                 macros << quotesinglbase_def << '\n';
852         if (mustProvide("quotedblbase"))
853                 macros << quotedblbase_def << '\n';
854         if (mustProvide("guilsinglleft"))
855                 macros << guilsinglleft_def << '\n';
856         if (mustProvide("guilsinglright"))
857                 macros << guilsinglright_def << '\n';
858         if (mustProvide("guillemotleft"))
859                 macros << guillemotleft_def << '\n';
860         if (mustProvide("guillemotright"))
861                 macros << guillemotright_def << '\n';
862
863         // Math mode
864         if (mustProvide("binom") && !isRequired("amsmath"))
865                 macros << binom_def << '\n';
866         if (mustProvide("mathcircumflex"))
867                 macros << mathcircumflex_def << '\n';
868
869         // other
870         if (mustProvide("ParagraphLeftIndent"))
871                 macros << paragraphleftindent_def;
872         if (mustProvide("NeedLyXFootnoteCode"))
873                 macros << floatingfootnote_def;
874
875         // some problems with tex->html converters
876         if (mustProvide("NeedTabularnewline"))
877                 macros << tabularnewline_def;
878
879         // greyedout environment (note inset)
880         if (mustProvide("lyxgreyedout"))
881                 macros << lyxgreyedout_def;
882
883         if (mustProvide("lyxdot"))
884                 macros << lyxdot_def << '\n';
885
886         // floats
887         getFloatDefinitions(macros);
888
889         // change tracking
890         if (mustProvide("ct-dvipost"))
891                 macros << changetracking_dvipost_def;
892
893         if (mustProvide("ct-xcolor-ulem")) {
894                 int const prec = macros.precision(2);
895         
896                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
897                 macros << "\\providecolor{lyxadded}{rgb}{"
898                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
899
900                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
901                 macros << "\\providecolor{lyxdeleted}{rgb}{"
902                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
903
904                 macros.precision(prec);
905                 
906                 if (isRequired("hyperref"))
907                         macros << changetracking_xcolor_ulem_hyperref_def;
908                 else
909                         macros << changetracking_xcolor_ulem_def;
910         }
911
912         if (mustProvide("ct-none"))
913                 macros << changetracking_none_def;
914
915         return macros.str();
916 }
917
918
919 string const LaTeXFeatures::getBabelOptions() const
920 {
921         ostringstream tmp;
922
923         LanguageList::const_iterator it  = UsedLanguages_.begin();
924         LanguageList::const_iterator end =  UsedLanguages_.end();
925         for (; it != end; ++it)
926                 if (!(*it)->latex_options().empty())
927                         tmp << (*it)->latex_options() << '\n';
928         if (!params_.language->latex_options().empty())
929                 tmp << params_.language->latex_options() << '\n';
930
931         return tmp.str();
932 }
933
934
935 docstring const LaTeXFeatures::getTClassPreamble() const
936 {
937         // the text class specific preamble
938         DocumentClass const & tclass = params_.documentClass();
939         odocstringstream tcpreamble;
940
941         tcpreamble << tclass.preamble();
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].preamble();
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.preamble();
956         }
957
958         return tcpreamble.str();
959 }
960
961
962 docstring const LaTeXFeatures::getTClassHTMLPreamble() const 
963 {
964         DocumentClass const & tclass = params_.documentClass();
965         odocstringstream tcpreamble;
966
967         tcpreamble << tclass.htmlpreamble();
968
969         list<docstring>::const_iterator cit = usedLayouts_.begin();
970         list<docstring>::const_iterator end = usedLayouts_.end();
971         for (; cit != end; ++cit)
972                 tcpreamble << tclass[*cit].htmlpreamble();
973
974         cit = usedInsetLayouts_.begin();
975         end = usedInsetLayouts_.end();
976         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
977         for (; cit != end; ++cit) {
978                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
979                 if (it == ils.end())
980                         continue;
981                 tcpreamble << it->second.htmlpreamble();
982         }
983
984         return tcpreamble.str();
985 }
986
987
988 docstring const LaTeXFeatures::getTClassHTMLStyles() const {
989         DocumentClass const & tclass = params_.documentClass();
990         odocstringstream tcpreamble;
991
992         list<docstring>::const_iterator cit = usedLayouts_.begin();
993         list<docstring>::const_iterator end = usedLayouts_.end();
994         for (; cit != end; ++cit)
995                 tcpreamble << tclass[*cit].htmlstyle();
996
997         cit = usedInsetLayouts_.begin();
998         end = usedInsetLayouts_.end();
999         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1000         for (; cit != end; ++cit) {
1001                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1002                 if (it == ils.end())
1003                         continue;
1004                 tcpreamble << it->second.htmlstyle();
1005         }
1006
1007         return tcpreamble.str();
1008 }
1009
1010
1011 namespace {
1012 docstring const getFloatI18nPreamble(docstring const & type, docstring const & name, docstring const & lang)
1013 {
1014         odocstringstream os;
1015         os << "\\addto\\captions" << lang
1016            << "{\\renewcommand{\\" << type << "name}{" << name << "}}\n";
1017         return os.str();
1018 }
1019 }
1020
1021
1022 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel) const
1023 {
1024         DocumentClass const & tclass = params_.documentClass();
1025         // collect preamble snippets in a set to prevent multiple identical
1026         // commands (would happen if e.g. both theorem and theorem* are used)
1027         set<docstring> snippets;
1028         typedef LanguageList::const_iterator lang_it;
1029         lang_it const lbeg = UsedLanguages_.begin();
1030         lang_it const lend =  UsedLanguages_.end();
1031         list<docstring>::const_iterator cit = usedLayouts_.begin();
1032         list<docstring>::const_iterator end = usedLayouts_.end();
1033         for (; cit != end; ++cit) {
1034                 // language dependent commands (once per document)
1035                 snippets.insert(tclass[*cit].langpreamble(buffer().language()));
1036                 // commands for language changing (for multilanguage documents)
1037                 if (use_babel && !UsedLanguages_.empty()) {
1038                         snippets.insert(tclass[*cit].babelpreamble(buffer().language()));
1039                         for (lang_it lit = lbeg; lit != lend; ++lit)
1040                                 snippets.insert(tclass[*cit].babelpreamble(*lit));
1041                 }
1042         }
1043         if (use_babel && !UsedLanguages_.empty()) {
1044                 FloatList const & floats = params_.documentClass().floats();
1045                 UsedFloats::const_iterator fit = usedFloats_.begin();
1046                 UsedFloats::const_iterator fend = usedFloats_.end();
1047                 for (; fit != fend; ++fit) {
1048                         Floating const & fl = floats.getType(fit->first);
1049                         docstring const type = from_ascii(fl.type());
1050                         docstring const flname = from_utf8(fl.name());
1051                         docstring name = translateIfPossible(flname,
1052                                 buffer().language()->code());
1053                         snippets.insert(getFloatI18nPreamble(
1054                                 type, name,
1055                                 from_ascii(buffer().language()->babel())));
1056                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1057                                 name = translateIfPossible(flname,
1058                                         (*lit)->code());
1059                                 snippets.insert(getFloatI18nPreamble(
1060                                         type, name,
1061                                         from_ascii((*lit)->babel())));
1062                         }
1063                 }
1064         }
1065
1066         odocstringstream tcpreamble;
1067         set<docstring>::const_iterator const send = snippets.end();
1068         set<docstring>::const_iterator it = snippets.begin();
1069         for (; it != send; ++it)
1070                 tcpreamble << *it;
1071         return tcpreamble.str();
1072 }
1073
1074
1075 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1076 {
1077         // Definition of entities used in the document that are LyX related.
1078         odocstringstream entities;
1079
1080         if (mustProvide("lyxarrow")) {
1081                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1082         }
1083
1084         return entities.str();
1085 }
1086
1087
1088 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1089 {
1090         odocstringstream sgmlpreamble;
1091         // FIXME UNICODE
1092         docstring const basename(from_utf8(onlyPath(fname)));
1093
1094         FileMap::const_iterator end = IncludedFiles_.end();
1095         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1096              fi != end; ++fi)
1097                 // FIXME UNICODE
1098                 sgmlpreamble << "\n<!ENTITY " << fi->first
1099                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
1100                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1101
1102         return sgmlpreamble.str();
1103 }
1104
1105
1106 void LaTeXFeatures::showStruct() const
1107 {
1108         lyxerr << "LyX needs the following commands when LaTeXing:"
1109                << "\n***** Packages:" << getPackages()
1110                << "\n***** Macros:" << to_utf8(getMacros())
1111                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1112                << "\n***** done." << endl;
1113 }
1114
1115
1116 Buffer const & LaTeXFeatures::buffer() const
1117 {
1118         return *buffer_;
1119 }
1120
1121
1122 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1123 {
1124         buffer_ = &buffer;
1125 }
1126
1127
1128 BufferParams const & LaTeXFeatures::bufferParams() const
1129 {
1130         return params_;
1131 }
1132
1133
1134 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1135 {
1136         FloatList const & floats = params_.documentClass().floats();
1137
1138         // Here we will output the code to create the needed float styles.
1139         // We will try to do this as minimal as possible.
1140         // \floatstyle{ruled}
1141         // \newfloat{algorithm}{htbp}{loa}
1142         // \providecommand{\algorithmname}{Algorithm}
1143         // \floatname{algorithm}{\protect\algorithmname}
1144         UsedFloats::const_iterator cit = usedFloats_.begin();
1145         UsedFloats::const_iterator end = usedFloats_.end();
1146         for (; cit != end; ++cit) {
1147                 Floating const & fl = floats.getType(cit->first);
1148
1149                 // For builtin floats we do nothing.
1150                 if (fl.builtin()) continue;
1151
1152                 // We have to special case "table" and "figure"
1153                 if (fl.type() == "tabular" || fl.type() == "figure") {
1154                         // Output code to modify "table" or "figure"
1155                         // but only if builtin == false
1156                         // and that have to be true at this point in the
1157                         // function.
1158                         docstring const type = from_ascii(fl.type());
1159                         docstring const placement = from_ascii(fl.placement());
1160                         docstring const style = from_ascii(fl.style());
1161                         if (!style.empty()) {
1162                                 os << "\\floatstyle{" << style << "}\n"
1163                                    << "\\restylefloat{" << type << "}\n";
1164                         }
1165                         if (!placement.empty()) {
1166                                 os << "\\floatplacement{" << type << "}{"
1167                                    << placement << "}\n";
1168                         }
1169                 } else {
1170                         // The other non builtin floats.
1171
1172                         docstring const type = from_ascii(fl.type());
1173                         docstring const placement = from_ascii(fl.placement());
1174                         docstring const ext = from_ascii(fl.ext());
1175                         docstring const within = from_ascii(fl.within());
1176                         docstring const style = from_ascii(fl.style());
1177                         docstring const name = translateIfPossible(
1178                                         from_utf8(fl.name()),
1179                                         buffer().language()->code());
1180                         os << "\\floatstyle{" << style << "}\n"
1181                            << "\\newfloat{" << type << "}{" << placement
1182                            << "}{" << ext << '}';
1183                         if (!within.empty())
1184                                 os << '[' << within << ']';
1185                         os << '\n'
1186                            << "\\providecommand{\\" << type << "name}{"
1187                            << name << "}\n"
1188                            << "\\floatname{" << type << "}{\\protect\\"
1189                            << type << "name}\n";
1190
1191                         // What missing here is to code to minimalize the code
1192                         // output so that the same floatstyle will not be
1193                         // used several times, when the same style is still in
1194                         // effect. (Lgb)
1195                 }
1196                 if (cit->second)
1197                         os << "\n\\newsubfloat{" << from_ascii(fl.type()) << "}\n";
1198         }
1199 }
1200
1201
1202 } // namespace lyx