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