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