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