]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
Allow boldface and font size changing commands for unicode symbols in math.
[features.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\n"
191         " \\def\\encodingdefault{LGR}}\n"
192         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
193         "\\DeclareFontEncoding{LGR}{}{}\n";
194
195 static string const textcyr_def =
196         "\\DeclareRobustCommand{\\cyrtext}{%\n"
197         " \\fontencoding{T2A}\\selectfont\n"
198         " \\def\\encodingdefault{T2A}}\n"
199         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
200         "\\DeclareFontEncoding{T2A}{}{}\n";
201
202 static string const mathsym_def =
203         "\\DeclareRobustCommand{\\mathsym}[1]{%\n"
204         " \\begingroup\n"
205         " \\edef\\b@ld{bold}%\n"
206         " \\def\\rmorbf##1{\\ifx\\math@version\\b@ld\\textbf{##1}\\else\\textrm{##1}\\fi}%\n"
207         " \\def\\szone{\\ifx\\@currsize\\large\\footnotesize%\n"
208         "  \\else\\ifx\\@currsize\\Large\\normalsize%\n"
209         "  \\else\\ifx\\@currsize\\LARGE\\large%\n"
210         "  \\else\\ifx\\@currsize\\huge\\Large%\n"
211         "  \\else\\ifx\\@currsize\\Huge\\huge%\n"
212         "  \\else\\scriptsize\\fi\\fi\\fi\\fi\\fi}%\n"
213         " \\def\\sztwo{\\ifx\\@currsize\\Large\\scriptsize%\n"
214         "  \\else\\ifx\\@currsize\\LARGE\\normalsize%\n"
215         "  \\else\\ifx\\@currsize\\huge\\large%\n"
216         "  \\else\\ifx\\@currsize\\Huge\\Large%\n"
217         "  \\else\\tiny\\fi\\fi\\fi\\fi}%\n"
218         " \\mathchoice{\\hbox{\\rmorbf{#1}}}{\\hbox{\\rmorbf{#1}}}%\n"
219         "  {\\hbox{\\szone\\rmorbf{#1}}}{\\hbox{\\sztwo\\rmorbf{#1}}}%\n"
220         " \\endgroup}\n";
221
222 /////////////////////////////////////////////////////////////////////
223 //
224 // LaTeXFeatures
225 //
226 /////////////////////////////////////////////////////////////////////
227
228 LaTeXFeatures::Packages LaTeXFeatures::packages_;
229
230
231 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
232                              OutputParams const & r)
233         : buffer_(&b), params_(p), runparams_(r)
234 {}
235
236
237 bool LaTeXFeatures::useBabel() const
238 {
239         return lyxrc.language_use_babel ||
240                 (bufferParams().language->lang() != lyxrc.default_language &&
241                  !bufferParams().language->babel().empty()) ||
242                 this->hasLanguages();
243 }
244
245
246 void LaTeXFeatures::require(string const & name)
247 {
248         features_.insert(name);
249 }
250
251
252 void LaTeXFeatures::require(set<string> const & names)
253 {
254         features_.insert(names.begin(), names.end());
255 }
256
257
258 void LaTeXFeatures::getAvailable()
259 {
260         Lexer lex;
261         support::FileName const real_file = libFileSearch("", "packages.lst");
262
263         if (real_file.empty())
264                 return;
265
266         lex.setFile(real_file);
267
268         if (!lex.isOK())
269                 return;
270
271         // Make sure that we are clean
272         packages_.clear();
273
274         bool finished = false;
275         // Parse config-file
276         while (lex.isOK() && !finished) {
277                 switch (lex.lex()) {
278                 case Lexer::LEX_FEOF:
279                         finished = true;
280                         break;
281                 default:
282                         packages_.insert(lex.getString());
283                 }
284         }
285 }
286
287
288 void LaTeXFeatures::useLayout(docstring const & layoutname)
289 {
290         // Some code to avoid loops in dependency definition
291         static int level = 0;
292         const int maxlevel = 30;
293         if (level > maxlevel) {
294                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
295                        << "recursion attained by layout "
296                        << to_utf8(layoutname) << endl;
297                 return;
298         }
299
300         DocumentClass const & tclass = params_.documentClass();
301         if (tclass.hasLayout(layoutname)) {
302                 // Is this layout already in usedLayouts?
303                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
304                     != usedLayouts_.end())
305                         return;
306
307                 Layout const & layout = tclass[layoutname];
308                 require(layout.requires());
309
310                 if (!layout.depends_on().empty()) {
311                         ++level;
312                         useLayout(layout.depends_on());
313                         --level;
314                 }
315                 usedLayouts_.push_back(layoutname);
316         } else {
317                 lyxerr << "LaTeXFeatures::useLayout: layout `"
318                        << to_utf8(layoutname) << "' does not exist in this class"
319                        << endl;
320         }
321
322         --level;
323 }
324
325
326 bool LaTeXFeatures::isRequired(string const & name) const
327 {
328         return features_.find(name) != features_.end();
329 }
330
331
332 bool LaTeXFeatures::mustProvide(string const & name) const
333 {
334         return isRequired(name) && !params_.documentClass().provides(name);
335 }
336
337
338 bool LaTeXFeatures::isAvailable(string const & name)
339 {
340         if (packages_.empty())
341                 getAvailable();
342         string n = name;
343         if (suffixIs(n, ".sty"))
344                 n.erase(name.length() - 4);
345         return packages_.find(n) != packages_.end();
346 }
347
348
349 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
350 {
351         SnippetList::const_iterator begin = preamble_snippets_.begin();
352         SnippetList::const_iterator end   = preamble_snippets_.end();
353         if (find(begin, end, preamble) == end)
354                 preamble_snippets_.push_back(preamble);
355 }
356
357
358 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
359 {
360         if (!usedFloats_[name])
361                 usedFloats_[name] = subfloat;
362         if (subfloat)
363                 require("subfig");
364         // We only need float.sty if we use non builtin floats, or if we
365         // use the "H" modifier. This includes modified table and
366         // figure floats. (Lgb)
367         Floating const & fl = params_.documentClass().floats().getType(name);
368         if (!fl.type().empty() && !fl.builtin()) {
369                 require("float");
370         }
371 }
372
373
374 void LaTeXFeatures::useLanguage(Language const * lang)
375 {
376         if (!lang->babel().empty())
377                 UsedLanguages_.insert(lang);
378         // CJK languages do not have a babel name.
379         // They use the CJK package
380         if (lang->encoding()->package() == Encoding::CJK)
381                 require("CJK");
382 }
383
384
385 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
386 {
387         IncludedFiles_[key] = name;
388 }
389
390
391 bool LaTeXFeatures::hasLanguages() const
392 {
393         return !UsedLanguages_.empty();
394 }
395
396
397 string LaTeXFeatures::getLanguages() const
398 {
399         ostringstream languages;
400
401         LanguageList::const_iterator const begin = UsedLanguages_.begin();
402         for (LanguageList::const_iterator cit = begin;
403              cit != UsedLanguages_.end();
404              ++cit) {
405                 if (cit != begin)
406                         languages << ',';
407                 languages << (*cit)->babel();
408         }
409         return languages.str();
410 }
411
412
413 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
414 {
415         // This does only find encodings of languages supported by babel, but
416         // that does not matter since we don't have a language with an
417         // encoding supported by inputenc but without babel support.
418         set<string> encodings;
419         LanguageList::const_iterator it  = UsedLanguages_.begin();
420         LanguageList::const_iterator end = UsedLanguages_.end();
421         for (; it != end; ++it)
422                 if ((*it)->encoding()->latexName() != doc_encoding &&
423                     (*it)->encoding()->package() == Encoding::inputenc)
424                         encodings.insert((*it)->encoding()->latexName());
425         return encodings;
426 }
427
428 namespace {
429
430 char const * simplefeatures[] = {
431 // note that the package order here will be the same in the LaTeX-output
432         "array",
433         "verbatim",
434         "longtable",
435         "rotating",
436         "latexsym",
437         "pifont",
438         // subfig is handled in BufferParams.cpp
439         "varioref",
440         "prettyref",
441         /*For a successful cooperation of the `wrapfig' package with the
442           `float' package you should load the `wrapfig' package *after*
443           the `float' package. See the caption package documentation
444           for explanation.*/
445         "float",
446         "rotfloat",
447         "wrapfig",
448         "booktabs",
449         "dvipost",
450         "fancybox",
451         "calc",
452         "units",
453         "tipa",
454         "tipx",
455         "framed",
456         "soul",
457         "textcomp",
458         "pmboxdraw",
459         "bbding",
460         "ifsym",
461         "marvosym",
462         "txfonts",
463         "mathrsfs",
464         "ascii",
465         "url",
466         "covington",
467         "csquotes",
468         "enumitem",
469         "endnotes",
470         "ifthen",
471         "amsthm",
472         "listings",
473         "bm",
474         "pdfpages"
475 };
476
477 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
478
479 }
480
481
482 string const LaTeXFeatures::getPackages() const
483 {
484         ostringstream packages;
485         DocumentClass const & tclass = params_.documentClass();
486
487         // FIXME: currently, we can only load packages and macros known
488         // to LyX.
489         // However, with the Require tag of layouts/custom insets,
490         // also inknown packages can be requested. They are silently
491         // swallowed now. We should change this eventually.
492
493         //
494         //  These are all the 'simple' includes.  i.e
495         //  packages which we just \usepackage{package}
496         //
497         for (int i = 0; i < nb_simplefeatures; ++i) {
498                 if (mustProvide(simplefeatures[i]))
499                         packages << "\\usepackage{"
500                                  << simplefeatures[i] << "}\n";
501         }
502
503         //
504         // The rest of these packages are somewhat more complicated
505         // than those above.
506         //
507
508         // esint is preferred for esintoramsmath
509         if ((mustProvide("amsmath") &&
510              params_.use_amsmath != BufferParams::package_off) ||
511             (mustProvide("esintoramsmath") &&
512              params_.use_esint == BufferParams::package_off)) {
513                 packages << "\\usepackage{amsmath}\n";
514         } else if (mustProvide("amsbsy")) {
515                 // amsbsy is already provided by amsmath
516                 packages << "\\usepackage{amsbsy}\n";
517         }
518         
519         // wasysym is a simple feature, but it must be after amsmath if both
520         // are used
521         // wasysym redefines some integrals (e.g. iint) from amsmath. That
522         // leads to inconsistent integrals. We only load this package if
523         // the document does not contain integrals (then isRequired("esint")
524         // is false) or if esint is used, since esint redefines all relevant
525         // integral symbols from wasysym and amsmath.
526         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
527         if (mustProvide("wasysym") &&
528             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
529                 packages << "\\usepackage{wasysym}\n";
530
531         // [x]color.sty
532         if (mustProvide("color") || mustProvide("xcolor")) {
533                 string const package =
534                         (mustProvide("xcolor") ? "xcolor" : "color");
535                 if (params_.graphicsDriver == "default")
536                         packages << "\\usepackage{" << package << "}\n";
537                 else
538                         packages << "\\usepackage["
539                                  << params_.graphicsDriver
540                                  << "]{" << package << "}\n";
541         }
542
543         // pdfcolmk must be loaded after color
544         if (mustProvide("pdfcolmk"))
545                 packages << "\\usepackage{pdfcolmk}\n";
546
547         // makeidx.sty
548         if (isRequired("makeidx")) {
549                 if (!tclass.provides("makeidx"))
550                         packages << "\\usepackage{makeidx}\n";
551                 packages << "\\makeindex\n";
552         }
553
554         // graphicx.sty
555         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
556                 if (params_.graphicsDriver == "default")
557                         packages << "\\usepackage{graphicx}\n";
558                 else
559                         packages << "\\usepackage["
560                                  << params_.graphicsDriver
561                                  << "]{graphicx}\n";
562         }
563         // shadecolor for shaded
564         if (isRequired("framed") && mustProvide("color")) {
565                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
566                 //255.0 to force conversion to double
567                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
568                 //to use the xcolor package instead, and then we can do
569                 // \define{shadcolor}{RGB}...
570                 //and not do any conversion. We'd then need to require xcolor
571                 //in InsetNote::validate().
572                 int const stmSize = packages.precision(2);
573                 packages << "\\definecolor{shadecolor}{rgb}{"
574                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
575                 packages.precision(stmSize);
576         }
577
578         // lyxskak.sty --- newer chess support based on skak.sty
579         if (mustProvide("chess"))
580                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
581
582         // setspace.sty
583         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
584     packages << "\\usepackage{setspace}\n";
585
586         // amssymb.sty
587         if (mustProvide("amssymb")
588             || params_.use_amsmath == BufferParams::package_on)
589                 packages << "\\usepackage{amssymb}\n";
590
591         // esint must be after amsmath and wasysym, since it will redeclare
592         // inconsistent integral symbols
593         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
594             params_.use_esint != BufferParams::package_off)
595                 packages << "\\usepackage{esint}\n";
596
597         // natbib.sty
598         if (mustProvide("natbib")) {
599                 packages << "\\usepackage[";
600                 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
601                         packages << "numbers";
602                 else
603                         packages << "authoryear";
604                 packages << "]{natbib}\n";
605         }
606
607         // jurabib -- we need version 0.6 at least.
608         if (mustProvide("jurabib"))
609                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
610         
611         // xargs -- we need version 1.09 at least
612         if (mustProvide("xargs"))
613                 packages << "\\usepackage{xargs}[2008/03/08]\n";
614
615         // bibtopic -- the dot provides the aux file naming which
616         // LyX can detect.
617         if (mustProvide("bibtopic"))
618                 packages << "\\usepackage[dot]{bibtopic}\n";
619
620         if (mustProvide("xy"))
621                 packages << "\\usepackage[all]{xy}\n";
622
623         if (mustProvide("nomencl")) {
624                 // Make it work with the new and old version of the package,
625                 // but don't use the compatibility option since it is
626                 // incompatible to other packages.
627                 packages << "\\usepackage{nomencl}\n"
628                             "% the following is useful when we have the old nomencl.sty package\n"
629                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
630                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
631                             "\\makenomenclature\n";
632         }
633
634         return packages.str();
635 }
636
637
638 string const LaTeXFeatures::getMacros() const
639 {
640         ostringstream macros;
641
642         if (!preamble_snippets_.empty())
643                 macros << '\n';
644         SnippetList::const_iterator pit  = preamble_snippets_.begin();
645         SnippetList::const_iterator pend = preamble_snippets_.end();
646         for (; pit != pend; ++pit)
647                 macros << *pit << '\n';
648
649         if (mustProvide("LyX"))
650                 macros << lyx_def << '\n';
651
652         if (mustProvide("lyxline"))
653                 macros << lyxline_def << '\n';
654
655         if (mustProvide("noun"))
656                 macros << noun_def << '\n';
657
658         if (mustProvide("lyxarrow"))
659                 macros << lyxarrow_def << '\n';
660
661         if (mustProvide("textgreek"))
662                 macros << textgreek_def << '\n';
663
664         if (mustProvide("textcyr"))
665                 macros << textcyr_def << '\n';
666
667         if (mustProvide("mathsym"))
668                 macros << mathsym_def << '\n';
669
670         // quotes.
671         if (mustProvide("quotesinglbase"))
672                 macros << quotesinglbase_def << '\n';
673         if (mustProvide("quotedblbase"))
674                 macros << quotedblbase_def << '\n';
675         if (mustProvide("guilsinglleft"))
676                 macros << guilsinglleft_def << '\n';
677         if (mustProvide("guilsinglright"))
678                 macros << guilsinglright_def << '\n';
679         if (mustProvide("guillemotleft"))
680                 macros << guillemotleft_def << '\n';
681         if (mustProvide("guillemotright"))
682                 macros << guillemotright_def << '\n';
683
684         // Math mode
685         if (mustProvide("binom") && !isRequired("amsmath"))
686                 macros << binom_def << '\n';
687         if (mustProvide("mathcircumflex"))
688                 macros << mathcircumflex_def << '\n';
689
690         // other
691         if (mustProvide("ParagraphLeftIndent"))
692                 macros << paragraphleftindent_def;
693         if (mustProvide("NeedLyXFootnoteCode"))
694                 macros << floatingfootnote_def;
695
696         // some problems with tex->html converters
697         if (mustProvide("NeedTabularnewline"))
698                 macros << tabularnewline_def;
699
700         // greyedout environment (note inset)
701         if (mustProvide("lyxgreyedout"))
702                 macros << lyxgreyedout_def;
703
704         if (mustProvide("lyxdot"))
705                 macros << lyxdot_def << '\n';
706
707         // floats
708         getFloatDefinitions(macros);
709
710         // change tracking
711         if (mustProvide("ct-dvipost"))
712                 macros << changetracking_dvipost_def;
713
714         if (mustProvide("ct-xcolor-soul")) {
715                 int const prec = macros.precision(2);
716         
717                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
718                 macros << "\\providecolor{lyxadded}{rgb}{"
719                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
720
721                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
722                 macros << "\\providecolor{lyxdeleted}{rgb}{"
723                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
724
725                 macros.precision(prec);
726                 
727                 if (isRequired("hyperref"))
728                         macros << changetracking_xcolor_soul_hyperref_def;
729                 else
730                         macros << changetracking_xcolor_soul_def;
731         }
732
733         if (mustProvide("ct-none"))
734                 macros << changetracking_none_def;
735
736         return macros.str();
737 }
738
739
740 string const LaTeXFeatures::getBabelOptions() const
741 {
742         ostringstream tmp;
743
744         LanguageList::const_iterator it  = UsedLanguages_.begin();
745         LanguageList::const_iterator end =  UsedLanguages_.end();
746         for (; it != end; ++it)
747                 if (!(*it)->latex_options().empty())
748                         tmp << (*it)->latex_options() << '\n';
749         if (!params_.language->latex_options().empty())
750                 tmp << params_.language->latex_options() << '\n';
751
752         return tmp.str();
753 }
754
755
756 docstring const LaTeXFeatures::getTClassPreamble() const
757 {
758         // the text class specific preamble
759         DocumentClass const & tclass = params_.documentClass();
760         odocstringstream tcpreamble;
761
762         tcpreamble << tclass.preamble();
763
764         list<docstring>::const_iterator cit = usedLayouts_.begin();
765         list<docstring>::const_iterator end = usedLayouts_.end();
766         for (; cit != end; ++cit) {
767                 tcpreamble << tclass[*cit].preamble();
768         }
769
770         return tcpreamble.str();
771 }
772
773
774 docstring const LaTeXFeatures::getLyXSGMLEntities() const
775 {
776         // Definition of entities used in the document that are LyX related.
777         odocstringstream entities;
778
779         if (mustProvide("lyxarrow")) {
780                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
781         }
782
783         return entities.str();
784 }
785
786
787 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
788 {
789         odocstringstream sgmlpreamble;
790         // FIXME UNICODE
791         docstring const basename(from_utf8(onlyPath(fname)));
792
793         FileMap::const_iterator end = IncludedFiles_.end();
794         for (FileMap::const_iterator fi = IncludedFiles_.begin();
795              fi != end; ++fi)
796                 // FIXME UNICODE
797                 sgmlpreamble << "\n<!ENTITY " << fi->first
798                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
799                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
800
801         return sgmlpreamble.str();
802 }
803
804
805 void LaTeXFeatures::showStruct() const
806 {
807         lyxerr << "LyX needs the following commands when LaTeXing:"
808                << "\n***** Packages:" << getPackages()
809                << "\n***** Macros:" << getMacros()
810                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
811                << "\n***** done." << endl;
812 }
813
814
815 Buffer const & LaTeXFeatures::buffer() const
816 {
817         return *buffer_;
818 }
819
820
821 void LaTeXFeatures::setBuffer(Buffer const & buffer)
822 {
823         buffer_ = &buffer;
824 }
825
826
827 BufferParams const & LaTeXFeatures::bufferParams() const
828 {
829         return params_;
830 }
831
832
833 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
834 {
835         FloatList const & floats = params_.documentClass().floats();
836
837         // Here we will output the code to create the needed float styles.
838         // We will try to do this as minimal as possible.
839         // \floatstyle{ruled}
840         // \newfloat{algorithm}{htbp}{loa}
841         // \floatname{algorithm}{Algorithm}
842         UsedFloats::const_iterator cit = usedFloats_.begin();
843         UsedFloats::const_iterator end = usedFloats_.end();
844         // ostringstream floats;
845         for (; cit != end; ++cit) {
846                 Floating const & fl = floats.getType((cit->first));
847
848                 // For builtin floats we do nothing.
849                 if (fl.builtin()) continue;
850
851                 // We have to special case "table" and "figure"
852                 if (fl.type() == "tabular" || fl.type() == "figure") {
853                         // Output code to modify "table" or "figure"
854                         // but only if builtin == false
855                         // and that have to be true at this point in the
856                         // function.
857                         string const type = fl.type();
858                         string const placement = fl.placement();
859                         string const style = fl.style();
860                         if (!style.empty()) {
861                                 os << "\\floatstyle{" << style << "}\n"
862                                    << "\\restylefloat{" << type << "}\n";
863                         }
864                         if (!placement.empty()) {
865                                 os << "\\floatplacement{" << type << "}{"
866                                    << placement << "}\n";
867                         }
868                 } else {
869                         // The other non builtin floats.
870
871                         string const type = fl.type();
872                         string const placement = fl.placement();
873                         string const ext = fl.ext();
874                         string const within = fl.within();
875                         string const style = fl.style();
876                         string const name = fl.name();
877                         os << "\\floatstyle{" << style << "}\n"
878                            << "\\newfloat{" << type << "}{" << placement
879                            << "}{" << ext << '}';
880                         if (!within.empty())
881                                 os << '[' << within << ']';
882                         os << '\n'
883                            << "\\floatname{" << type << "}{"
884                            << name << "}\n";
885
886                         // What missing here is to code to minimalize the code
887                         // output so that the same floatstyle will not be
888                         // used several times, when the same style is still in
889                         // effect. (Lgb)
890                 }
891                 if (cit->second)
892                         os << "\n\\newsubfloat{" << fl.type() << "}\n";
893         }
894 }
895
896
897 } // namespace lyx