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