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