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