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