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