]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
LaTeXFeatures.cpp: fix part of http://bugzilla.lyx.org/show_bug.cgi?id=5294 also...
[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 string LaTeXFeatures::getLanguages() const
435 {
436         ostringstream languages;
437
438         LanguageList::const_iterator const begin = UsedLanguages_.begin();
439         for (LanguageList::const_iterator cit = begin;
440              cit != UsedLanguages_.end();
441              ++cit) {
442                 if (cit != begin)
443                         languages << ',';
444                 languages << (*cit)->babel();
445         }
446         return languages.str();
447 }
448
449
450 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
451 {
452         // This does only find encodings of languages supported by babel, but
453         // that does not matter since we don't have a language with an
454         // encoding supported by inputenc but without babel support.
455         set<string> encodings;
456         LanguageList::const_iterator it  = UsedLanguages_.begin();
457         LanguageList::const_iterator end = UsedLanguages_.end();
458         for (; it != end; ++it)
459                 if ((*it)->encoding()->latexName() != doc_encoding &&
460                     ((*it)->encoding()->package() == Encoding::inputenc
461                      || (*it)->encoding()->package() == Encoding::japanese))
462                         encodings.insert((*it)->encoding()->latexName());
463         return encodings;
464 }
465
466 namespace {
467
468 char const * simplefeatures[] = {
469 // note that the package order here will be the same in the LaTeX-output
470         "array",
471         "verbatim",
472         "longtable",
473         "rotating",
474         "latexsym",
475         "pifont",
476         // subfig is handled in BufferParams.cpp
477         "varioref",
478         "prettyref",
479         /*For a successful cooperation of the `wrapfig' package with the
480           `float' package you should load the `wrapfig' package *after*
481           the `float' package. See the caption package documentation
482           for explanation.*/
483         "float",
484         "rotfloat",
485         "wrapfig",
486         "booktabs",
487         "dvipost",
488         "fancybox",
489         "calc",
490         "units",
491         "tipa",
492         "tipx",
493         "framed",
494         "soul",
495         "textcomp",
496         "pmboxdraw",
497         "bbding",
498         "ifsym",
499         "marvosym",
500         "txfonts",
501         "mathrsfs",
502         "ascii",
503         "url",
504         "covington",
505         "csquotes",
506         "enumitem",
507         "endnotes",
508         "ifthen",
509         "amsthm",
510         // listings is handled in BufferParams.cpp
511         "bm",
512         "pdfpages",
513         "relsize",
514         "amscd",
515         "slashed"
516 };
517
518 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
519
520 }
521
522
523 string const LaTeXFeatures::getPackages() const
524 {
525         ostringstream packages;
526         DocumentClass const & tclass = params_.documentClass();
527
528         // FIXME: currently, we can only load packages and macros known
529         // to LyX.
530         // However, with the Require tag of layouts/custom insets,
531         // also inknown packages can be requested. They are silently
532         // swallowed now. We should change this eventually.
533
534         //
535         //  These are all the 'simple' includes.  i.e
536         //  packages which we just \usepackage{package}
537         //
538         for (int i = 0; i < nb_simplefeatures; ++i) {
539                 if (mustProvide(simplefeatures[i]))
540                         packages << "\\usepackage{"
541                                  << simplefeatures[i] << "}\n";
542         }
543
544         //
545         // The rest of these packages are somewhat more complicated
546         // than those above.
547         //
548
549         // esint is preferred for esintoramsmath
550         if ((mustProvide("amsmath") &&
551              params_.use_amsmath != BufferParams::package_off) ||
552             (mustProvide("esintoramsmath") &&
553              params_.use_esint == BufferParams::package_off)) {
554                 packages << "\\usepackage{amsmath}\n";
555         } else if (mustProvide("amsbsy")) {
556                 // amsbsy is already provided by amsmath
557                 packages << "\\usepackage{amsbsy}\n";
558         }
559         
560         // wasysym is a simple feature, but it must be after amsmath if both
561         // are used
562         // wasysym redefines some integrals (e.g. iint) from amsmath. That
563         // leads to inconsistent integrals. We only load this package if
564         // the document does not contain integrals (then isRequired("esint")
565         // is false) or if esint is used, since esint redefines all relevant
566         // integral symbols from wasysym and amsmath.
567         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
568         if (mustProvide("wasysym") &&
569             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
570                 packages << "\\usepackage{wasysym}\n";
571
572         // accents must be loaded after amsmath
573         if (mustProvide("accents"))
574                 packages << "\\usepackage{accents}\n";
575
576         // [x]color.sty
577         if (mustProvide("color") || mustProvide("xcolor")) {
578                 string const package =
579                         (mustProvide("xcolor") ? "xcolor" : "color");
580                 if (params_.graphicsDriver == "default"
581                         || params_.graphicsDriver == "none")
582                         packages << "\\usepackage{" << package << "}\n";
583                 else
584                         packages << "\\usepackage["
585                                  << params_.graphicsDriver
586                                  << "]{" << package << "}\n";
587         }
588
589         // pdfcolmk must be loaded after color
590         if (mustProvide("pdfcolmk"))
591                 packages << "\\usepackage{pdfcolmk}\n";
592
593         // makeidx.sty
594         if (isRequired("makeidx")) {
595                 if (!tclass.provides("makeidx"))
596                         packages << "\\usepackage{makeidx}\n";
597                 packages << "\\makeindex\n";
598         }
599
600         // graphicx.sty
601         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
602                 if (params_.graphicsDriver == "default")
603                         packages << "\\usepackage{graphicx}\n";
604                 else
605                         packages << "\\usepackage["
606                                  << params_.graphicsDriver
607                                  << "]{graphicx}\n";
608         }
609         // shadecolor for shaded
610         if (isRequired("framed") && mustProvide("color")) {
611                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
612                 //255.0 to force conversion to double
613                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
614                 //to use the xcolor package instead, and then we can do
615                 // \define{shadcolor}{RGB}...
616                 //and not do any conversion. We'd then need to require xcolor
617                 //in InsetNote::validate().
618                 int const stmSize = packages.precision(2);
619                 packages << "\\definecolor{shadecolor}{rgb}{"
620                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
621                 packages.precision(stmSize);
622         }
623
624         // lyxskak.sty --- newer chess support based on skak.sty
625         if (mustProvide("chess"))
626                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
627
628         // setspace.sty
629         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
630                 packages << "\\usepackage{setspace}\n";
631
632         // amssymb.sty
633         if (mustProvide("amssymb")
634             || params_.use_amsmath == BufferParams::package_on)
635                 packages << "\\usepackage{amssymb}\n";
636
637         // esint must be after amsmath and wasysym, since it will redeclare
638         // inconsistent integral symbols
639         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
640             params_.use_esint != BufferParams::package_off)
641                 packages << "\\usepackage{esint}\n";
642
643         // natbib.sty
644         // Some classes load natbib themselves, but still allow (or even require)
645         // plain numeric citations (ReVTeX is such a case, see bug 5182).
646         // This special case is indicated by the "natbib-internal" key.
647         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
648                 packages << "\\usepackage[";
649                 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
650                         packages << "numbers";
651                 else
652                         packages << "authoryear";
653                 packages << "]{natbib}\n";
654         }
655
656         // jurabib -- we need version 0.6 at least.
657         if (mustProvide("jurabib"))
658                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
659         
660         // xargs -- we need version 1.09 at least
661         if (mustProvide("xargs"))
662                 packages << "\\usepackage{xargs}[2008/03/08]\n";
663
664         // bibtopic -- the dot provides the aux file naming which
665         // LyX can detect.
666         if (mustProvide("bibtopic"))
667                 packages << "\\usepackage[dot]{bibtopic}\n";
668
669         if (mustProvide("xy"))
670                 packages << "\\usepackage[all]{xy}\n";
671
672         if (mustProvide("nomencl")) {
673                 // Make it work with the new and old version of the package,
674                 // but don't use the compatibility option since it is
675                 // incompatible to other packages.
676                 packages << "\\usepackage{nomencl}\n"
677                             "% the following is useful when we have the old nomencl.sty package\n"
678                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
679                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
680                             "\\makenomenclature\n";
681         }
682
683         return packages.str();
684 }
685
686
687 string const LaTeXFeatures::getMacros() const
688 {
689         ostringstream macros;
690
691         if (!preamble_snippets_.empty())
692                 macros << '\n';
693         SnippetList::const_iterator pit  = preamble_snippets_.begin();
694         SnippetList::const_iterator pend = preamble_snippets_.end();
695         for (; pit != pend; ++pit)
696                 macros << *pit << '\n';
697
698         if (mustProvide("papersize"))
699                 if (runparams_.flavor == OutputParams::LATEX)
700                         macros << papersizedvi_def << '\n';
701                 else
702                         macros << papersizepdf_def << '\n';
703
704         if (mustProvide("LyX"))
705                 macros << lyx_def << '\n';
706
707         if (mustProvide("lyxline"))
708                 macros << lyxline_def << '\n';
709
710         if (mustProvide("noun"))
711                 macros << noun_def << '\n';
712
713         if (mustProvide("lyxarrow"))
714                 macros << lyxarrow_def << '\n';
715
716         if (mustProvide("textgreek"))
717                 macros << textgreek_def << '\n';
718
719         if (mustProvide("textcyr"))
720                 macros << textcyr_def << '\n';
721
722         if (mustProvide("lyxmathsym"))
723                 macros << lyxmathsym_def << '\n';
724
725         if (mustProvide("cedilla"))
726                 macros << cedilla_def << '\n';
727
728         if (mustProvide("subring"))
729                 macros << subring_def << '\n';
730
731         if (mustProvide("subdot"))
732                 macros << subdot_def << '\n';
733
734         if (mustProvide("subhat"))
735                 macros << subhat_def << '\n';
736
737         if (mustProvide("subtilde"))
738                 macros << subtilde_def << '\n';
739
740         if (mustProvide("dacute"))
741                 macros << dacute_def << '\n';
742
743         if (mustProvide("tipasymb"))
744                 macros << tipasymb_def << '\n';
745
746         if (mustProvide("dgrave"))
747                 macros << dgrave_def << '\n';
748
749         if (mustProvide("rcap"))
750                 macros << rcap_def << '\n';
751
752         if (mustProvide("ogonek"))
753                 macros << ogonek_def << '\n';
754
755         // quotes.
756         if (mustProvide("quotesinglbase"))
757                 macros << quotesinglbase_def << '\n';
758         if (mustProvide("quotedblbase"))
759                 macros << quotedblbase_def << '\n';
760         if (mustProvide("guilsinglleft"))
761                 macros << guilsinglleft_def << '\n';
762         if (mustProvide("guilsinglright"))
763                 macros << guilsinglright_def << '\n';
764         if (mustProvide("guillemotleft"))
765                 macros << guillemotleft_def << '\n';
766         if (mustProvide("guillemotright"))
767                 macros << guillemotright_def << '\n';
768
769         // Math mode
770         if (mustProvide("binom") && !isRequired("amsmath"))
771                 macros << binom_def << '\n';
772         if (mustProvide("mathcircumflex"))
773                 macros << mathcircumflex_def << '\n';
774
775         // other
776         if (mustProvide("ParagraphLeftIndent"))
777                 macros << paragraphleftindent_def;
778         if (mustProvide("NeedLyXFootnoteCode"))
779                 macros << floatingfootnote_def;
780
781         // some problems with tex->html converters
782         if (mustProvide("NeedTabularnewline"))
783                 macros << tabularnewline_def;
784
785         // greyedout environment (note inset)
786         if (mustProvide("lyxgreyedout"))
787                 macros << lyxgreyedout_def;
788
789         if (mustProvide("lyxdot"))
790                 macros << lyxdot_def << '\n';
791
792         // floats
793         getFloatDefinitions(macros);
794
795         // change tracking
796         if (mustProvide("ct-dvipost"))
797                 macros << changetracking_dvipost_def;
798
799         if (mustProvide("ct-xcolor-soul")) {
800                 int const prec = macros.precision(2);
801         
802                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
803                 macros << "\\providecolor{lyxadded}{rgb}{"
804                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
805
806                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
807                 macros << "\\providecolor{lyxdeleted}{rgb}{"
808                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
809
810                 macros.precision(prec);
811                 
812                 if (isRequired("hyperref"))
813                         macros << changetracking_xcolor_soul_hyperref_def;
814                 else
815                         macros << changetracking_xcolor_soul_def;
816         }
817
818         if (mustProvide("ct-none"))
819                 macros << changetracking_none_def;
820
821         return macros.str();
822 }
823
824
825 string const LaTeXFeatures::getBabelOptions() const
826 {
827         ostringstream tmp;
828
829         LanguageList::const_iterator it  = UsedLanguages_.begin();
830         LanguageList::const_iterator end =  UsedLanguages_.end();
831         for (; it != end; ++it)
832                 if (!(*it)->latex_options().empty())
833                         tmp << (*it)->latex_options() << '\n';
834         if (!params_.language->latex_options().empty())
835                 tmp << params_.language->latex_options() << '\n';
836
837         return tmp.str();
838 }
839
840
841 docstring const LaTeXFeatures::getTClassPreamble() const
842 {
843         // the text class specific preamble
844         DocumentClass const & tclass = params_.documentClass();
845         odocstringstream tcpreamble;
846
847         tcpreamble << tclass.preamble();
848
849         list<docstring>::const_iterator cit = usedLayouts_.begin();
850         list<docstring>::const_iterator end = usedLayouts_.end();
851         for (; cit != end; ++cit) {
852                 tcpreamble << tclass[*cit].preamble();
853         }
854
855         return tcpreamble.str();
856 }
857
858
859 docstring const LaTeXFeatures::getLyXSGMLEntities() const
860 {
861         // Definition of entities used in the document that are LyX related.
862         odocstringstream entities;
863
864         if (mustProvide("lyxarrow")) {
865                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
866         }
867
868         return entities.str();
869 }
870
871
872 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
873 {
874         odocstringstream sgmlpreamble;
875         // FIXME UNICODE
876         docstring const basename(from_utf8(onlyPath(fname)));
877
878         FileMap::const_iterator end = IncludedFiles_.end();
879         for (FileMap::const_iterator fi = IncludedFiles_.begin();
880              fi != end; ++fi)
881                 // FIXME UNICODE
882                 sgmlpreamble << "\n<!ENTITY " << fi->first
883                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
884                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
885
886         return sgmlpreamble.str();
887 }
888
889
890 void LaTeXFeatures::showStruct() const
891 {
892         lyxerr << "LyX needs the following commands when LaTeXing:"
893                << "\n***** Packages:" << getPackages()
894                << "\n***** Macros:" << getMacros()
895                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
896                << "\n***** done." << endl;
897 }
898
899
900 Buffer const & LaTeXFeatures::buffer() const
901 {
902         return *buffer_;
903 }
904
905
906 void LaTeXFeatures::setBuffer(Buffer const & buffer)
907 {
908         buffer_ = &buffer;
909 }
910
911
912 BufferParams const & LaTeXFeatures::bufferParams() const
913 {
914         return params_;
915 }
916
917
918 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
919 {
920         FloatList const & floats = params_.documentClass().floats();
921
922         // Here we will output the code to create the needed float styles.
923         // We will try to do this as minimal as possible.
924         // \floatstyle{ruled}
925         // \newfloat{algorithm}{htbp}{loa}
926         // \floatname{algorithm}{Algorithm}
927         UsedFloats::const_iterator cit = usedFloats_.begin();
928         UsedFloats::const_iterator end = usedFloats_.end();
929         // ostringstream floats;
930         for (; cit != end; ++cit) {
931                 Floating const & fl = floats.getType((cit->first));
932
933                 // For builtin floats we do nothing.
934                 if (fl.builtin()) continue;
935
936                 // We have to special case "table" and "figure"
937                 if (fl.type() == "tabular" || fl.type() == "figure") {
938                         // Output code to modify "table" or "figure"
939                         // but only if builtin == false
940                         // and that have to be true at this point in the
941                         // function.
942                         string const type = fl.type();
943                         string const placement = fl.placement();
944                         string const style = fl.style();
945                         if (!style.empty()) {
946                                 os << "\\floatstyle{" << style << "}\n"
947                                    << "\\restylefloat{" << type << "}\n";
948                         }
949                         if (!placement.empty()) {
950                                 os << "\\floatplacement{" << type << "}{"
951                                    << placement << "}\n";
952                         }
953                 } else {
954                         // The other non builtin floats.
955
956                         string const type = fl.type();
957                         string const placement = fl.placement();
958                         string const ext = fl.ext();
959                         string const within = fl.within();
960                         string const style = fl.style();
961                         string const name = fl.name();
962                         os << "\\floatstyle{" << style << "}\n"
963                            << "\\newfloat{" << type << "}{" << placement
964                            << "}{" << ext << '}';
965                         if (!within.empty())
966                                 os << '[' << within << ']';
967                         os << '\n'
968                            << "\\floatname{" << type << "}{"
969                            << name << "}\n";
970
971                         // What missing here is to code to minimalize the code
972                         // output so that the same floatstyle will not be
973                         // used several times, when the same style is still in
974                         // effect. (Lgb)
975                 }
976                 if (cit->second)
977                         os << "\n\\newsubfloat{" << fl.type() << "}\n";
978         }
979 }
980
981
982 } // namespace lyx