]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
e2fd3f1658af89b58a5c2dddb50ed5d35e6cd963
[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         "array",
392         "verbatim",
393         "longtable",
394         "rotating",
395         "latexsym",
396         "pifont",
397         "subfigure",
398         "floatflt",
399         "varioref",
400         "prettyref",
401         "float",
402         "booktabs",
403         "dvipost",
404         "fancybox",
405         "calc",
406         "nicefrac",
407         "tipa",
408         "framed",
409         "pdfcolmk",
410         "soul",
411         "textcomp",
412         "xcolor",
413 };
414
415 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
416
417 }
418
419
420 string const LaTeXFeatures::getPackages() const
421 {
422         ostringstream packages;
423         TextClass const & tclass = params_.getTextClass();
424
425         //
426         //  These are all the 'simple' includes.  i.e
427         //  packages which we just \usepackage{package}
428         //
429         for (int i = 0; i < nb_simplefeatures; ++i) {
430                 if (mustProvide(simplefeatures[i]))
431                         packages << "\\usepackage{"
432                                  << simplefeatures[i] << "}\n";
433         }
434
435         //
436         // The rest of these packages are somewhat more complicated
437         // than those above.
438         //
439
440         if (mustProvide("amsmath")
441             && params_.use_amsmath != BufferParams::package_off) {
442                 packages << "\\usepackage{amsmath}\n";
443         }
444
445         // wasysym is a simple feature, but it must be after amsmath if both
446         // are used
447         // wasysym redefines some integrals (e.g. iint) from amsmath. That
448         // leads to inconsistent integrals. We only load this package if
449         // esint is used, since esint redefines all relevant integral
450         // symbols from wasysym and amsmath.
451         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
452         if (mustProvide("wasysym") && isRequired("esint") &&
453             params_.use_esint != BufferParams::package_off)
454                 packages << "\\usepackage{wasysym}\n";
455
456         // color.sty
457         if (mustProvide("color")) {
458                 if (params_.graphicsDriver == "default")
459                         packages << "\\usepackage{color}\n";
460                 else
461                         packages << "\\usepackage["
462                                  << params_.graphicsDriver
463                                  << "]{color}\n";
464         }
465
466         // makeidx.sty
467         if (isRequired("makeidx")) {
468                 if (!tclass.provides("makeidx"))
469                         packages << "\\usepackage{makeidx}\n";
470                 packages << "\\makeindex\n";
471         }
472
473         // graphicx.sty
474         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
475                 if (params_.graphicsDriver == "default")
476                         packages << "\\usepackage{graphicx}\n";
477                 else
478                         packages << "\\usepackage["
479                                  << params_.graphicsDriver
480                                  << "]{graphicx}\n";
481         }
482         // shadecolor for shaded
483         if (mustProvide("framed") && mustProvide("color")) {
484                 RGBColor c = RGBColor(lcolor.getX11Name(Color::shadedbg));
485                 packages << "\\definecolor{shadecolor}{rgb}{" 
486                         << c.r/255 << ',' << c.g/255 << ',' << c.b/255 << "}\n";
487         }
488
489         // lyxskak.sty --- newer chess support based on skak.sty
490         if (mustProvide("chess")) {
491                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
492         }
493
494         // setspace.sty
495         if ((params_.spacing().getSpace() != Spacing::Single
496              && !params_.spacing().isDefault())
497             || isRequired("setspace")) {
498                 packages << "\\usepackage{setspace}\n";
499         }
500         switch (params_.spacing().getSpace()) {
501         case Spacing::Default:
502         case Spacing::Single:
503                 // we dont use setspace.sty so dont print anything
504                 //packages += "\\singlespacing\n";
505                 break;
506         case Spacing::Onehalf:
507                 packages << "\\onehalfspacing\n";
508                 break;
509         case Spacing::Double:
510                 packages << "\\doublespacing\n";
511                 break;
512         case Spacing::Other:
513                 packages << "\\setstretch{"
514                          << params_.spacing().getValue() << "}\n";
515                 break;
516         }
517
518         // amssymb.sty
519         if (mustProvide("amssymb") 
520             || params_.use_amsmath == BufferParams::package_on)
521                 packages << "\\usepackage{amssymb}\n";
522
523         // esint must be after amsmath and wasysym, since it will redeclare
524         // inconsistent integral symbols
525         if (mustProvide("esint") 
526             && params_.use_esint != BufferParams::package_off)
527                 packages << "\\usepackage{esint}\n";
528
529         // url.sty
530         if (mustProvide("url"))
531                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
532                             "                      {\\newcommand{\\url}{\\texttt}}\n";
533
534         // natbib.sty
535         if (mustProvide("natbib")) {
536                 packages << "\\usepackage[";
537                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
538                         packages << "numbers";
539                 } else {
540                         packages << "authoryear";
541                 }
542                 packages << "]{natbib}\n";
543         }
544
545         // jurabib -- we need version 0.6 at least.
546         if (mustProvide("jurabib")) {
547                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
548         }
549
550         // bibtopic -- the dot provides the aux file naming which
551         // LyX can detect.
552         if (mustProvide("bibtopic")) {
553                 packages << "\\usepackage[dot]{bibtopic}\n";
554         }
555
556         if (mustProvide("xy"))
557                 packages << "\\usepackage[all]{xy}\n";
558
559         if (mustProvide("nomencl")) {
560                 // Make it work with the new and old version of the package,
561                 // but don't use the compatibility option since it is
562                 // incompatible to other packages.
563                 packages << "\\usepackage{nomencl}\n"
564                             "% the following is useful when we have the old nomencl.sty package\n"
565                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
566                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
567                             "\\makenomenclature\n";
568         }
569
570         if (mustProvide("listings"))
571                 packages << "\\usepackage{listings}\n";
572  
573         return packages.str();
574 }
575
576
577 string const LaTeXFeatures::getMacros() const
578 {
579         ostringstream macros;
580
581         if (!preamble_snippets_.empty())
582                 macros << '\n';
583         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
584         FeaturesList::const_iterator pend = preamble_snippets_.end();
585         for (; pit != pend; ++pit) {
586                 macros << *pit << '\n';
587         }
588
589         if (mustProvide("LyX"))
590                 macros << lyx_def << '\n';
591
592         if (mustProvide("lyxline"))
593                 macros << lyxline_def << '\n';
594
595         if (mustProvide("noun"))
596                 macros << noun_def << '\n';
597
598         if (mustProvide("lyxarrow"))
599                 macros << lyxarrow_def << '\n';
600
601         // quotes.
602         if (mustProvide("quotesinglbase"))
603                 macros << quotesinglbase_def << '\n';
604         if (mustProvide("quotedblbase"))
605                 macros << quotedblbase_def << '\n';
606         if (mustProvide("guilsinglleft"))
607                 macros << guilsinglleft_def << '\n';
608         if (mustProvide("guilsinglright"))
609                 macros << guilsinglright_def << '\n';
610         if (mustProvide("guillemotleft"))
611                 macros << guillemotleft_def << '\n';
612         if (mustProvide("guillemotright"))
613                 macros << guillemotright_def << '\n';
614
615         // Math mode
616         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
617                 macros << boldsymbol_def << '\n';
618         if (mustProvide("binom") && !isRequired("amsmath"))
619                 macros << binom_def << '\n';
620         if (mustProvide("mathcircumflex"))
621                 macros << mathcircumflex_def << '\n';
622
623         // other
624         if (mustProvide("ParagraphLeftIndent"))
625                 macros << paragraphleftindent_def;
626         if (mustProvide("NeedLyXFootnoteCode"))
627                 macros << floatingfootnote_def;
628
629         // some problems with tex->html converters
630         if (mustProvide("NeedTabularnewline"))
631                 macros << tabularnewline_def;
632
633         // greyedout environment (note inset)
634         if (mustProvide("lyxgreyedout"))
635                 macros << lyxgreyedout_def;
636
637         if (mustProvide("lyxdot"))
638                 macros << lyxdot_def << '\n';
639
640         // floats
641         getFloatDefinitions(macros);
642
643         // change tracking
644         if (mustProvide("ct-dvipost")) {
645                 macros << changetracking_dvipost_def;
646         }
647         if (mustProvide("ct-xcolor-soul")) {
648                 RGBColor cadd = RGBColor(lcolor.getX11Name(Color::addedtext));
649                 macros << "\\providecolor{lyxadded}{rgb}{" 
650                        << cadd.r/255 << ',' << cadd.g/255 << ',' << cadd.b/255 << "}\n";
651
652                 RGBColor cdel = RGBColor(lcolor.getX11Name(Color::deletedtext));
653                 macros << "\\providecolor{lyxdeleted}{rgb}{" 
654                        << cdel.r/255 << ',' << cdel.g/255 << ',' << cdel.b/255 << "}\n";
655
656                 macros << "\\newcommand{\\lyxadded}[3]{\\color{lyxadded}{#3}}\n"
657                        << "\\newcommand{\\lyxdeleted}[3]{\\color{lyxdeleted}{\\st{#3}}}\n";
658         }
659         if (mustProvide("ct-none")) {
660                 macros << changetracking_none_def;
661         }
662
663         return macros.str();
664 }
665
666
667 string const LaTeXFeatures::getBabelOptions() const
668 {
669         ostringstream tmp;
670
671         LanguageList::const_iterator it  = UsedLanguages_.begin();
672         LanguageList::const_iterator end =  UsedLanguages_.end();
673         for (; it != end; ++it)
674                 if (!(*it)->latex_options().empty())
675                         tmp << (*it)->latex_options() << '\n';
676         if (!params_.language->latex_options().empty())
677                 tmp << params_.language->latex_options() << '\n';
678
679         return tmp.str();
680 }
681
682
683 docstring const LaTeXFeatures::getTClassPreamble() const
684 {
685         // the text class specific preamble
686         TextClass const & tclass = params_.getTextClass();
687         odocstringstream tcpreamble;
688
689         tcpreamble << tclass.preamble();
690
691         list<string>::const_iterator cit = usedLayouts_.begin();
692         list<string>::const_iterator end = usedLayouts_.end();
693         for (; cit != end; ++cit) {
694                 tcpreamble << tclass[*cit]->preamble();
695         }
696
697         CharStyles::iterator cs = tclass.charstyles().begin();
698         CharStyles::iterator csend = tclass.charstyles().end();
699         for (; cs != csend; ++cs) {
700                 if (isRequired(cs->name))
701                         tcpreamble << cs->preamble;
702         }
703
704         return tcpreamble.str();
705 }
706
707
708 docstring const LaTeXFeatures::getLyXSGMLEntities() const
709 {
710         // Definition of entities used in the document that are LyX related.
711         odocstringstream entities;
712
713         if (mustProvide("lyxarrow")) {
714                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
715         }
716
717         return entities.str();
718 }
719
720
721 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
722 {
723         odocstringstream sgmlpreamble;
724         // FIXME UNICODE
725         docstring const basename(from_utf8(onlyPath(fname)));
726
727         FileMap::const_iterator end = IncludedFiles_.end();
728         for (FileMap::const_iterator fi = IncludedFiles_.begin();
729              fi != end; ++fi)
730                 // FIXME UNICODE
731                 sgmlpreamble << "\n<!ENTITY " << fi->first
732                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
733                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
734
735         return sgmlpreamble.str();
736 }
737
738
739 void LaTeXFeatures::showStruct() const {
740         lyxerr << "LyX needs the following commands when LaTeXing:"
741                << "\n***** Packages:" << getPackages()
742                << "\n***** Macros:" << getMacros()
743                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
744                << "\n***** done." << endl;
745 }
746
747
748 Buffer const & LaTeXFeatures::buffer() const
749 {
750         return *buffer_;
751 }
752
753
754 void LaTeXFeatures::setBuffer(Buffer const & buffer)
755 {
756         buffer_ = &buffer;
757 }
758
759
760 BufferParams const & LaTeXFeatures::bufferParams() const
761 {
762         return params_;
763 }
764
765
766 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
767 {
768         FloatList const & floats = params_.getTextClass().floats();
769
770         // Here we will output the code to create the needed float styles.
771         // We will try to do this as minimal as possible.
772         // \floatstyle{ruled}
773         // \newfloat{algorithm}{htbp}{loa}
774         // \floatname{algorithm}{Algorithm}
775         UsedFloats::const_iterator cit = usedFloats_.begin();
776         UsedFloats::const_iterator end = usedFloats_.end();
777         // ostringstream floats;
778         for (; cit != end; ++cit) {
779                 Floating const & fl = floats.getType((*cit));
780
781                 // For builtin floats we do nothing.
782                 if (fl.builtin()) continue;
783
784                 // We have to special case "table" and "figure"
785                 if (fl.type() == "tabular" || fl.type() == "figure") {
786                         // Output code to modify "table" or "figure"
787                         // but only if builtin == false
788                         // and that have to be true at this point in the
789                         // function.
790                         string const type = fl.type();
791                         string const placement = fl.placement();
792                         string const style = fl.style();
793                         if (!style.empty()) {
794                                 os << "\\floatstyle{" << style << "}\n"
795                                    << "\\restylefloat{" << type << "}\n";
796                         }
797                         if (!placement.empty()) {
798                                 os << "\\floatplacement{" << type << "}{"
799                                    << placement << "}\n";
800                         }
801                 } else {
802                         // The other non builtin floats.
803
804                         string const type = fl.type();
805                         string const placement = fl.placement();
806                         string const ext = fl.ext();
807                         string const within = fl.within();
808                         string const style = fl.style();
809                         string const name = fl.name();
810                         os << "\\floatstyle{" << style << "}\n"
811                            << "\\newfloat{" << type << "}{" << placement
812                            << "}{" << ext << '}';
813                         if (!within.empty())
814                                 os << '[' << within << ']';
815                         os << '\n'
816                            << "\\floatname{" << type << "}{"
817                            << name << "}\n";
818
819                         // What missing here is to code to minimalize the code
820                         // output so that the same floatstyle will not be
821                         // used several times, when the same style is still in
822                         // effect. (Lgb)
823                 }
824         }
825 }
826
827
828 } // namespace lyx