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