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