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