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