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