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