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