]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
HTML for math fonts.
[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 "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "Layout.h"
28 #include "Lexer.h"
29 #include "LyXRC.h"
30 #include "TextClass.h"
31
32 #include "insets/InsetLayout.h"
33
34 #include "support/debug.h"
35 #include "support/docstream.h"
36 #include "support/FileName.h"
37 #include "support/filetools.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
40
41 using namespace std;
42 using namespace lyx::support;
43
44
45 namespace lyx {
46
47 /////////////////////////////////////////////////////////////////////
48 //
49 // Strings
50 //
51 /////////////////////////////////////////////////////////////////////
52
53 //\NeedsTeXFormat{LaTeX2e}
54 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
55 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
56
57 static docstring const lyx_def = from_ascii(
58         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
59
60 static docstring const lyxline_def = from_ascii(
61         "\\newcommand{\\lyxline}[1][1pt]{%\n"
62         "  \\par\\noindent%\n"
63         "  \\rule[.5ex]{\\linewidth}{#1}\\par}");
64
65 static docstring const noun_def = from_ascii(
66         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
67
68 static docstring const lyxarrow_def = from_ascii(
69         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
70         "\\@ifstar\n"
71         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
72         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
73
74 // for quotes without babel. This does not give perfect results, but
75 // anybody serious about non-english quotes should use babel (JMarc).
76
77 static docstring const quotedblbase_def = from_ascii(
78         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
79         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
80         "  \\penalty10000\\hskip0em\\relax%\n"
81         "}");
82
83 static docstring const quotesinglbase_def = from_ascii(
84         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
85         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
86         "  \\penalty10000\\hskip0em\\relax%\n"
87         "}");
88
89 static docstring const guillemotleft_def = from_ascii(
90         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
91         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
92         "\\penalty10000\\hskip0pt\\relax%\n"
93         "}");
94
95 static docstring const guillemotright_def = from_ascii(
96         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
97         "  \\penalty10000\\hskip0pt%\n"
98         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
99         "}");
100
101 static docstring const guilsinglleft_def = from_ascii(
102         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
103         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
104         "  \\penalty10000\\hskip0pt\\relax%\n"
105         "}");
106
107 static docstring const guilsinglright_def = from_ascii(
108         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
109         "  \\penalty10000\\hskip0pt%\n"
110         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
111         "}");
112
113 static docstring const paragraphleftindent_def = from_ascii(
114         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
115         "{\n"
116         "  \\begin{list}{}{%\n"
117         "    \\setlength{\\topsep}{0pt}%\n"
118         "    \\addtolength{\\leftmargin}{#1}\n"
119 // ho hum, yet more things commented out with no hint as to why they
120 // weren't just removed
121 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
122 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
123 //      "%%    \\setlength\\listparindent\\parindent%\n"
124 //      "%%    \\setlength\\itemindent\\parindent%\n"
125         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
126         "  }\n"
127         "  \\item[]\n"
128         "}\n"
129         "{\\end{list}}\n");
130
131 static docstring const floatingfootnote_def = from_ascii(
132         "%% Special footnote code from the package 'stblftnt.sty'\n"
133         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
134         "\\let\\SF@@footnote\\footnote\n"
135         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
136         "    \\expandafter\\SF@@footnote\n"
137         "  \\else\n"
138         "    \\expandafter\\SF@gobble@opt\n"
139         "  \\fi\n"
140         "}\n"
141         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
142         "  \\SF@gobble@twobracket\n"
143         "  \\@gobble\n"
144         "}\n"
145         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
146         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
147         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
148
149 static docstring const binom_def = from_ascii(
150         "%% Binom macro for standard LaTeX users\n"
151         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
152
153 static docstring const mathcircumflex_def = from_ascii(
154         "%% For printing a cirumflex inside a formula\n"
155         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
156
157 static docstring const tabularnewline_def = from_ascii(
158         "%% Because html converters don't know tabularnewline\n"
159         "\\providecommand{\\tabularnewline}{\\\\}\n");
160         
161 static docstring const lyxgreyedout_def = from_ascii(
162         "%% The greyedout annotation environment\n"
163         "\\newenvironment{lyxgreyedout}{\\textcolor{note_fontcolor}\\bgroup}{\\egroup}\n");
164
165 // We want to omit the file extension for includegraphics, but this does not
166 // work when the filename contains other dots.
167 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
168 static docstring const lyxdot_def = from_ascii(
169         "%% A simple dot to overcome graphicx limitations\n"
170         "\\newcommand{\\lyxdot}{.}\n");
171
172 static docstring const changetracking_dvipost_def = from_ascii(
173         "%% Change tracking with dvipost\n"
174         "\\dvipostlayout\n"
175         "\\dvipost{osstart color push Red}\n"
176         "\\dvipost{osend color pop}\n"
177         "\\dvipost{cbstart color push Blue}\n"
178         "\\dvipost{cbend color pop}\n"
179         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
180         "\\newcommand{\\lyxdeleted}[3]{%\n"
181         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
182
183 static docstring const changetracking_xcolor_ulem_def = from_ascii(
184         "%% Change tracking with ulem\n"
185         "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
186         "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
187
188 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
189         "%% Change tracking with ulem\n"
190         "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
191         "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
192
193 static docstring const changetracking_none_def = from_ascii(
194         "\\newcommand{\\lyxadded}[3]{#3}\n"
195         "\\newcommand{\\lyxdeleted}[3]{}\n");
196
197 static docstring const textgreek_def = from_ascii(
198         "\\providecommand*{\\perispomeni}{\\char126}\n"
199         "\\AtBeginDocument{\\DeclareRobustCommand{\\greektext}{%\n"
200         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}%\n"
201         "  \\renewcommand{\\~}{\\perispomeni}%\n"
202         "}}\n"
203         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
204         "\\DeclareFontEncoding{LGR}{}{}\n");
205
206 static docstring const textcyr_def = from_ascii(
207         "\\DeclareRobustCommand{\\cyrtext}{%\n"
208         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
209         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
210         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
211
212 static docstring const lyxmathsym_def = from_ascii(
213         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
214         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
215
216 static docstring const papersizedvi_def = from_ascii(
217         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
218
219 static docstring const papersizepdf_def = from_ascii(
220         "\\pdfpageheight\\paperheight\n"
221         "\\pdfpagewidth\\paperwidth\n");
222
223 static docstring const cedilla_def = from_ascii(
224         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
225         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
226
227 static docstring const subring_def = from_ascii(
228         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
229         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
230
231 static docstring const subdot_def = from_ascii(
232         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
233         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
234
235 static docstring const subhat_def = from_ascii(
236         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
237         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
238
239 static docstring const subtilde_def = from_ascii(
240         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
241         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
242
243 static docstring const dacute_def = from_ascii(
244         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
245
246 static docstring const tipasymb_def = from_ascii(
247         "\\DeclareFontEncoding{T3}{}{}\n"
248         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
249
250 static docstring const dgrave_def = from_ascii(
251         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
252
253 static docstring const rcap_def = from_ascii(
254         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
255
256 static docstring const ogonek_def = from_ascii(
257         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
258         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
259         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
260         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
261         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
262
263 /////////////////////////////////////////////////////////////////////
264 //
265 // LaTeXFeatures
266 //
267 /////////////////////////////////////////////////////////////////////
268
269 LaTeXFeatures::Packages LaTeXFeatures::packages_;
270
271
272 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
273                              OutputParams const & r)
274         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
275 {}
276
277
278 bool LaTeXFeatures::useBabel() const
279 {
280         return lyxrc.language_use_babel ||
281                 (bufferParams().language->lang() != lyxrc.default_language &&
282                  !bufferParams().language->babel().empty()) ||
283                 this->hasLanguages();
284 }
285
286
287 void LaTeXFeatures::require(string const & name)
288 {
289         features_.insert(name);
290 }
291
292
293 void LaTeXFeatures::require(set<string> const & names)
294 {
295         features_.insert(names.begin(), names.end());
296 }
297
298
299 void LaTeXFeatures::getAvailable()
300 {
301         Lexer lex;
302         support::FileName const real_file = libFileSearch("", "packages.lst");
303
304         if (real_file.empty())
305                 return;
306
307         lex.setFile(real_file);
308
309         if (!lex.isOK())
310                 return;
311
312         // Make sure that we are clean
313         packages_.clear();
314
315         bool finished = false;
316         // Parse config-file
317         while (lex.isOK() && !finished) {
318                 switch (lex.lex()) {
319                 case Lexer::LEX_FEOF:
320                         finished = true;
321                         break;
322                 default:
323                         packages_.insert(lex.getString());
324                 }
325         }
326 }
327
328
329 void LaTeXFeatures::useLayout(docstring const & layoutname)
330 {
331         // Some code to avoid loops in dependency definition
332         static int level = 0;
333         const int maxlevel = 30;
334         if (level > maxlevel) {
335                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
336                        << "recursion attained by layout "
337                        << to_utf8(layoutname) << endl;
338                 return;
339         }
340
341         DocumentClass const & tclass = params_.documentClass();
342         if (tclass.hasLayout(layoutname)) {
343                 // Is this layout already in usedLayouts?
344                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
345                     != usedLayouts_.end())
346                         return;
347
348                 Layout const & layout = tclass[layoutname];
349                 require(layout.requires());
350
351                 if (!layout.depends_on().empty()) {
352                         ++level;
353                         useLayout(layout.depends_on());
354                         --level;
355                 }
356                 usedLayouts_.push_back(layoutname);
357         } else {
358                 lyxerr << "LaTeXFeatures::useLayout: layout `"
359                        << to_utf8(layoutname) << "' does not exist in this class"
360                        << endl;
361         }
362
363         --level;
364 }
365
366
367 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
368 {
369         docstring const & lname = lay.name();
370         DocumentClass const & tclass = params_.documentClass();
371
372         // this is a default inset layout, nothing useful here
373         if (!tclass.hasInsetLayout(lname))
374                 return;
375         // Is this layout already in usedInsetLayouts?
376         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname) 
377                         != usedInsetLayouts_.end())
378                 return;
379
380         require(lay.requires());
381         usedInsetLayouts_.push_back(lname);
382 }
383
384
385 bool LaTeXFeatures::isRequired(string const & name) const
386 {
387         return features_.find(name) != features_.end();
388 }
389
390
391 bool LaTeXFeatures::mustProvide(string const & name) const
392 {
393         return isRequired(name) && !params_.documentClass().provides(name);
394 }
395
396
397 bool LaTeXFeatures::isAvailable(string const & name)
398 {
399         string::size_type const i = name.find("->");
400         if (i != string::npos) {
401                 string const from = name.substr(0,i);
402                 string const to = name.substr(i+2);
403                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
404                 return theConverters().isReachable(from, to);
405         }
406
407         if (packages_.empty())
408                 getAvailable();
409         string n = name;
410         if (suffixIs(n, ".sty"))
411                 n.erase(name.length() - 4);
412         return packages_.find(n) != packages_.end();
413 }
414
415
416 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
417 {
418         SnippetList::const_iterator begin = preamble_snippets_.begin();
419         SnippetList::const_iterator end   = preamble_snippets_.end();
420         if (find(begin, end, preamble) == end)
421                 preamble_snippets_.push_back(preamble);
422 }
423
424
425 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
426 {
427         if (!usedFloats_[name])
428                 usedFloats_[name] = subfloat;
429         if (subfloat)
430                 require("subfig");
431         // We only need float.sty if we use non builtin floats, or if we
432         // use the "H" modifier. This includes modified table and
433         // figure floats. (Lgb)
434         Floating const & fl = params_.documentClass().floats().getType(name);
435         if (!fl.floattype().empty() && fl.needsFloatPkg()) {
436                 require("float");
437         }
438 }
439
440
441 void LaTeXFeatures::useLanguage(Language const * lang)
442 {
443         if (!lang->babel().empty())
444                 UsedLanguages_.insert(lang);
445         if (lang->lang() == "vietnamese")
446                 require("vietnamese");
447         // CJK languages do not have a babel name.
448         // They use the CJK package
449         if (lang->encoding()->package() == Encoding::CJK)
450                 require("CJK");
451         // japanese package is special
452         if (lang->encoding()->package() == Encoding::japanese)
453                 require("japanese");
454 }
455
456
457 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
458 {
459         IncludedFiles_[key] = name;
460 }
461
462
463 bool LaTeXFeatures::hasLanguages() const
464 {
465         return !UsedLanguages_.empty();
466 }
467
468
469 string LaTeXFeatures::getLanguages() const
470 {
471         ostringstream languages;
472
473         LanguageList::const_iterator const begin = UsedLanguages_.begin();
474         for (LanguageList::const_iterator cit = begin;
475              cit != UsedLanguages_.end();
476              ++cit) {
477                 if (cit != begin)
478                         languages << ',';
479                 languages << (*cit)->babel();
480         }
481         return languages.str();
482 }
483
484
485 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
486 {
487         // This does only find encodings of languages supported by babel, but
488         // that does not matter since we don't have a language with an
489         // encoding supported by inputenc but without babel support.
490         set<string> encodings;
491         LanguageList::const_iterator it  = UsedLanguages_.begin();
492         LanguageList::const_iterator end = UsedLanguages_.end();
493         for (; it != end; ++it)
494                 if ((*it)->encoding()->latexName() != doc_encoding &&
495                     ((*it)->encoding()->package() == Encoding::inputenc
496                      || (*it)->encoding()->package() == Encoding::japanese))
497                         encodings.insert((*it)->encoding()->latexName());
498         return encodings;
499 }
500
501 namespace {
502
503 char const * simplefeatures[] = {
504 // note that the package order here will be the same in the LaTeX-output
505         "array",
506         "verbatim",
507         "longtable",
508         "rotating",
509         "latexsym",
510         "pifont",
511         // subfig is handled in BufferParams.cpp
512         "varioref",
513         "prettyref",
514         /*For a successful cooperation of the `wrapfig' package with the
515           `float' package you should load the `wrapfig' package *after*
516           the `float' package. See the caption package documentation
517           for explanation.*/
518         "float",
519         "rotfloat",
520         "wrapfig",
521         "booktabs",
522         "dvipost",
523         "fancybox",
524         "calc",
525         "units",
526         "tipa",
527         "tipx",
528         "framed",
529         "soul",
530         "textcomp",
531         "pmboxdraw",
532         "bbding",
533         "ifsym",
534         "marvosym",
535         "txfonts",
536         "mathrsfs",
537         "ascii",
538         "url",
539         "covington",
540         "csquotes",
541         "enumitem",
542         "endnotes",
543         "ifthen",
544         "amsthm",
545         // listings is handled in BufferParams.cpp
546         "bm",
547         "pdfpages",
548         "amscd",
549         "slashed",
550         "multirow"
551 };
552
553 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
554
555 }
556
557
558 string const LaTeXFeatures::getColorOptions() const
559 {
560         ostringstream colors;
561
562         // Handling the color packages separately is needed to be able to load them
563         // before babel when hyperref is loaded with the colorlinks option
564         // for more info see Bufferparams.cpp
565
566         // [x]color.sty
567         if (mustProvide("color") || mustProvide("xcolor")) {
568                 string const package =
569                         (mustProvide("xcolor") ? "xcolor" : "color");
570                 if (params_.graphicsDriver == "default"
571                         || params_.graphicsDriver == "none")
572                         colors << "\\usepackage{" << package << "}\n";
573                 else
574                         colors << "\\usepackage["
575                                  << params_.graphicsDriver
576                                  << "]{" << package << "}\n";
577         }
578
579         // pdfcolmk must be loaded after color
580         if (mustProvide("pdfcolmk"))
581                 colors << "\\usepackage{pdfcolmk}\n";
582
583         // the following 3 color commands must be set after color
584         // is loaded and before pdfpages, therefore add the command
585         // here define the set color
586         if (mustProvide("pagecolor")) {
587                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
588                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
589                 // set the page color
590                 colors << "\\pagecolor{page_backgroundcolor}\n";
591         }
592
593         if (mustProvide("lyxgreyedout")) {
594                 colors << "\\definecolor{note_fontcolor}{rgb}{";
595                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
596                 // the color will be set together with the definition of
597                 // the lyxgreyedout environment (lyxgreyedout_def)
598         }
599
600         return colors.str();
601 }
602
603
604 string const LaTeXFeatures::getPackages() const
605 {
606         ostringstream packages;
607         DocumentClass const & tclass = params_.documentClass();
608
609         // FIXME: currently, we can only load packages and macros known
610         // to LyX.
611         // However, with the Require tag of layouts/custom insets,
612         // also inknown packages can be requested. They are silently
613         // swallowed now. We should change this eventually.
614
615         //
616         //  These are all the 'simple' includes.  i.e
617         //  packages which we just \usepackage{package}
618         //
619         for (int i = 0; i < nb_simplefeatures; ++i) {
620                 if (mustProvide(simplefeatures[i]))
621                         packages << "\\usepackage{"
622                                  << simplefeatures[i] << "}\n";
623         }
624
625         //
626         // The rest of these packages are somewhat more complicated
627         // than those above.
628         //
629
630         // esint is preferred for esintoramsmath
631         if ((mustProvide("amsmath")
632              && params_.use_amsmath != BufferParams::package_off)
633             || (mustProvide("esintoramsmath")
634                 && params_.use_esint == BufferParams::package_off
635                 && params_.use_amsmath != BufferParams::package_off)) {
636                 packages << "\\usepackage{amsmath}\n";
637         } else {
638                 // amsbsy and amstext are already provided by amsmath
639                 if (mustProvide("amsbsy"))
640                         packages << "\\usepackage{amsbsy}\n";
641                 if (mustProvide("amstext"))
642                         packages << "\\usepackage{amstext}\n";
643         }
644         
645         // wasysym is a simple feature, but it must be after amsmath if both
646         // are used
647         // wasysym redefines some integrals (e.g. iint) from amsmath. That
648         // leads to inconsistent integrals. We only load this package if
649         // the document does not contain integrals (then isRequired("esint")
650         // is false) or if esint is used, since esint redefines all relevant
651         // integral symbols from wasysym and amsmath.
652         // See http://www.lyx.org/trac/ticket/1942
653         if (mustProvide("wasysym") &&
654             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
655                 packages << "\\usepackage{wasysym}\n";
656
657         // accents must be loaded after amsmath
658         if (mustProvide("accents"))
659                 packages << "\\usepackage{accents}\n";
660
661         // mathdots must be loaded after amsmath
662         if (mustProvide("mathdots"))
663                 packages << "\\usepackage{mathdots}\n";
664
665         // yhmath must be loaded after amsmath
666         if (mustProvide("yhmath"))
667                 packages << "\\usepackage{yhmath}\n";
668
669         // [x]color and pdfcolmk are handled in getColorOptions() above
670         
671         // makeidx.sty
672         if (isRequired("makeidx") || isRequired("splitidx")) {
673                 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
674                         packages << "\\usepackage{makeidx}\n";
675                 if (!tclass.provides("splitidx") && isRequired("splitidx"))
676                         packages << "\\usepackage{splitidx}\n";
677                 packages << "\\makeindex\n";
678         }
679
680         // graphicx.sty
681         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
682                 if (params_.graphicsDriver == "default")
683                         packages << "\\usepackage{graphicx}\n";
684                 else
685                         packages << "\\usepackage["
686                                  << params_.graphicsDriver
687                                  << "]{graphicx}\n";
688         }
689         // shadecolor for shaded
690         if (isRequired("framed") && mustProvide("color")) {
691                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
692                 //255.0 to force conversion to double
693                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
694                 //to use the xcolor package instead, and then we can do
695                 // \define{shadcolor}{RGB}...
696                 //and not do any conversion. We'd then need to require xcolor
697                 //in InsetNote::validate().
698                 int const stmSize = packages.precision(2);
699                 packages << "\\definecolor{shadecolor}{rgb}{"
700                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
701                 packages.precision(stmSize);
702         }
703
704         // lyxskak.sty --- newer chess support based on skak.sty
705         if (mustProvide("chess"))
706                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
707
708         // setspace.sty
709         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
710                 packages << "\\usepackage{setspace}\n";
711
712         // amssymb.sty
713         if (mustProvide("amssymb")
714             || params_.use_amsmath == BufferParams::package_on)
715                 packages << "\\usepackage{amssymb}\n";
716
717         // esint must be after amsmath and wasysym, since it will redeclare
718         // inconsistent integral symbols
719         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
720             params_.use_esint != BufferParams::package_off)
721                 packages << "\\usepackage{esint}\n";
722
723         // natbib.sty
724         // Some classes load natbib themselves, but still allow (or even require)
725         // plain numeric citations (ReVTeX is such a case, see bug 5182).
726         // This special case is indicated by the "natbib-internal" key.
727         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
728                 packages << "\\usepackage[";
729                 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
730                         packages << "numbers";
731                 else
732                         packages << "authoryear";
733                 packages << "]{natbib}\n";
734         }
735
736         // jurabib -- we need version 0.6 at least.
737         if (mustProvide("jurabib"))
738                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
739         
740         // xargs -- we need version 1.09 at least
741         if (mustProvide("xargs"))
742                 packages << "\\usepackage{xargs}[2008/03/08]\n";
743
744         // bibtopic -- the dot provides the aux file naming which
745         // LyX can detect.
746         if (mustProvide("bibtopic"))
747                 packages << "\\usepackage[dot]{bibtopic}\n";
748
749         if (mustProvide("xy"))
750                 packages << "\\usepackage[all]{xy}\n";
751
752         if (mustProvide("ulem"))
753                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
754                             "\\usepackage{ulem}\n";
755
756         if (mustProvide("mhchem") &&
757                 params_.use_mhchem != BufferParams::package_off)
758                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
759                             "\\usepackage{mhchem}\n";
760
761         if (mustProvide("nomencl")) {
762                 // Make it work with the new and old version of the package,
763                 // but don't use the compatibility option since it is
764                 // incompatible to other packages.
765                 packages << "\\usepackage{nomencl}\n"
766                             "% the following is useful when we have the old nomencl.sty package\n"
767                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
768                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
769                             "\\makenomenclature\n";
770         }
771
772         return packages.str();
773 }
774
775
776 string LaTeXFeatures::getPreambleSnippets() const 
777 {
778         ostringstream snip;
779         SnippetList::const_iterator pit  = preamble_snippets_.begin();
780         SnippetList::const_iterator pend = preamble_snippets_.end();
781         for (; pit != pend; ++pit)
782                 snip << *pit << '\n';
783         return snip.str();
784 }
785
786
787 docstring const LaTeXFeatures::getMacros() const
788 {
789         odocstringstream macros;
790
791         if (!preamble_snippets_.empty()) {
792                 macros << '\n';
793                 macros << from_utf8(getPreambleSnippets());
794         }
795
796         if (mustProvide("papersize")) {
797                 if (runparams_.flavor == OutputParams::LATEX)
798                         macros << papersizedvi_def << '\n';
799                 else
800                         macros << papersizepdf_def << '\n';
801         }
802
803         if (mustProvide("LyX"))
804                 macros << lyx_def << '\n';
805
806         if (mustProvide("lyxline"))
807                 macros << lyxline_def << '\n';
808
809         if (mustProvide("noun"))
810                 macros << noun_def << '\n';
811
812         if (mustProvide("lyxarrow"))
813                 macros << lyxarrow_def << '\n';
814
815         if (mustProvide("textgreek")) {
816                 // Avoid a LaTeX error if times fonts are used and the grtimes
817                 // package is installed but actual fonts are not (bug 6469).
818                 if (params_.fontsRoman == "times")
819                         macros << subst(textgreek_def,
820                                         from_ascii("\\greektext #1"),
821                                         from_ascii("%\n  \\IfFileExists"
822                                                    "{grtm10.tfm}{}{\\fontfamily"
823                                                    "{cmr}}\\greektext #1"))
824                                << '\n';
825                 else
826                         macros << textgreek_def << '\n';
827         }
828
829         if (mustProvide("textcyr"))
830                 macros << textcyr_def << '\n';
831
832         if (mustProvide("lyxmathsym"))
833                 macros << lyxmathsym_def << '\n';
834
835         if (mustProvide("cedilla"))
836                 macros << cedilla_def << '\n';
837
838         if (mustProvide("subring"))
839                 macros << subring_def << '\n';
840
841         if (mustProvide("subdot"))
842                 macros << subdot_def << '\n';
843
844         if (mustProvide("subhat"))
845                 macros << subhat_def << '\n';
846
847         if (mustProvide("subtilde"))
848                 macros << subtilde_def << '\n';
849
850         if (mustProvide("dacute"))
851                 macros << dacute_def << '\n';
852
853         if (mustProvide("tipasymb"))
854                 macros << tipasymb_def << '\n';
855
856         if (mustProvide("dgrave"))
857                 macros << dgrave_def << '\n';
858
859         if (mustProvide("rcap"))
860                 macros << rcap_def << '\n';
861
862         if (mustProvide("ogonek"))
863                 macros << ogonek_def << '\n';
864
865         // quotes.
866         if (mustProvide("quotesinglbase"))
867                 macros << quotesinglbase_def << '\n';
868         if (mustProvide("quotedblbase"))
869                 macros << quotedblbase_def << '\n';
870         if (mustProvide("guilsinglleft"))
871                 macros << guilsinglleft_def << '\n';
872         if (mustProvide("guilsinglright"))
873                 macros << guilsinglright_def << '\n';
874         if (mustProvide("guillemotleft"))
875                 macros << guillemotleft_def << '\n';
876         if (mustProvide("guillemotright"))
877                 macros << guillemotright_def << '\n';
878
879         // Math mode
880         if (mustProvide("binom") && !isRequired("amsmath"))
881                 macros << binom_def << '\n';
882         if (mustProvide("mathcircumflex"))
883                 macros << mathcircumflex_def << '\n';
884
885         // other
886         if (mustProvide("ParagraphLeftIndent"))
887                 macros << paragraphleftindent_def;
888         if (mustProvide("NeedLyXFootnoteCode"))
889                 macros << floatingfootnote_def;
890
891         // some problems with tex->html converters
892         if (mustProvide("NeedTabularnewline"))
893                 macros << tabularnewline_def;
894
895         // greyed-out environment (note inset)
896         // the color is specified in the routine
897         // getColorOptions() to avoid LaTeX-package clashes
898         if (mustProvide("lyxgreyedout"))
899                 macros << lyxgreyedout_def;
900
901         if (mustProvide("lyxdot"))
902                 macros << lyxdot_def << '\n';
903
904         // floats
905         getFloatDefinitions(macros);
906
907         // change tracking
908         if (mustProvide("ct-dvipost"))
909                 macros << changetracking_dvipost_def;
910
911         if (mustProvide("ct-xcolor-ulem")) {
912                 int const prec = macros.precision(2);
913         
914                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
915                 macros << "\\providecolor{lyxadded}{rgb}{"
916                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
917
918                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
919                 macros << "\\providecolor{lyxdeleted}{rgb}{"
920                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
921
922                 macros.precision(prec);
923                 
924                 if (isRequired("hyperref"))
925                         macros << changetracking_xcolor_ulem_hyperref_def;
926                 else
927                         macros << changetracking_xcolor_ulem_def;
928         }
929
930         if (mustProvide("ct-none"))
931                 macros << changetracking_none_def;
932
933         return macros.str();
934 }
935
936
937 string const LaTeXFeatures::getBabelOptions() const
938 {
939         ostringstream tmp;
940
941         LanguageList::const_iterator it  = UsedLanguages_.begin();
942         LanguageList::const_iterator end =  UsedLanguages_.end();
943         for (; it != end; ++it)
944                 if (!(*it)->latex_options().empty())
945                         tmp << (*it)->latex_options() << '\n';
946         if (!params_.language->latex_options().empty())
947                 tmp << params_.language->latex_options() << '\n';
948
949         return tmp.str();
950 }
951
952
953 docstring const LaTeXFeatures::getTClassPreamble() const
954 {
955         // the text class specific preamble
956         DocumentClass const & tclass = params_.documentClass();
957         odocstringstream tcpreamble;
958
959         tcpreamble << tclass.preamble();
960
961         list<docstring>::const_iterator cit = usedLayouts_.begin();
962         list<docstring>::const_iterator end = usedLayouts_.end();
963         for (; cit != end; ++cit)
964                 tcpreamble << tclass[*cit].preamble();
965
966         cit = usedInsetLayouts_.begin();
967         end = usedInsetLayouts_.end();
968         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
969         for (; cit != end; ++cit) {
970                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
971                 if (it == ils.end())
972                         continue;
973                 tcpreamble << it->second.preamble();
974         }
975
976         return tcpreamble.str();
977 }
978
979
980 docstring const LaTeXFeatures::getTClassHTMLPreamble() const 
981 {
982         DocumentClass const & tclass = params_.documentClass();
983         odocstringstream tcpreamble;
984
985         tcpreamble << tclass.htmlpreamble();
986
987         list<docstring>::const_iterator cit = usedLayouts_.begin();
988         list<docstring>::const_iterator end = usedLayouts_.end();
989         for (; cit != end; ++cit)
990                 tcpreamble << tclass[*cit].htmlpreamble();
991
992         cit = usedInsetLayouts_.begin();
993         end = usedInsetLayouts_.end();
994         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
995         for (; cit != end; ++cit) {
996                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
997                 if (it == ils.end())
998                         continue;
999                 tcpreamble << it->second.htmlpreamble();
1000         }
1001
1002         return tcpreamble.str();
1003 }
1004
1005
1006 docstring const LaTeXFeatures::getTClassHTMLStyles() const {
1007         DocumentClass const & tclass = params_.documentClass();
1008         odocstringstream tcpreamble;
1009
1010         list<docstring>::const_iterator cit = usedLayouts_.begin();
1011         list<docstring>::const_iterator end = usedLayouts_.end();
1012         for (; cit != end; ++cit)
1013                 tcpreamble << tclass[*cit].htmlstyle();
1014
1015         cit = usedInsetLayouts_.begin();
1016         end = usedInsetLayouts_.end();
1017         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1018         for (; cit != end; ++cit) {
1019                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1020                 if (it == ils.end())
1021                         continue;
1022                 tcpreamble << it->second.htmlstyle();
1023         }
1024
1025         return tcpreamble.str();
1026 }
1027
1028
1029 namespace {
1030 docstring const getFloatI18nPreamble(docstring const & type, docstring const & name, docstring const & lang)
1031 {
1032         odocstringstream os;
1033         os << "\\addto\\captions" << lang
1034            << "{\\renewcommand{\\" << type << "name}{" << name << "}}\n";
1035         return os.str();
1036 }
1037 }
1038
1039
1040 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel) const
1041 {
1042         DocumentClass const & tclass = params_.documentClass();
1043         // collect preamble snippets in a set to prevent multiple identical
1044         // commands (would happen if e.g. both theorem and theorem* are used)
1045         set<docstring> snippets;
1046         typedef LanguageList::const_iterator lang_it;
1047         lang_it const lbeg = UsedLanguages_.begin();
1048         lang_it const lend =  UsedLanguages_.end();
1049         list<docstring>::const_iterator cit = usedLayouts_.begin();
1050         list<docstring>::const_iterator end = usedLayouts_.end();
1051         for (; cit != end; ++cit) {
1052                 // language dependent commands (once per document)
1053                 snippets.insert(tclass[*cit].langpreamble(buffer().language()));
1054                 // commands for language changing (for multilanguage documents)
1055                 if (use_babel && !UsedLanguages_.empty()) {
1056                         snippets.insert(tclass[*cit].babelpreamble(buffer().language()));
1057                         for (lang_it lit = lbeg; lit != lend; ++lit)
1058                                 snippets.insert(tclass[*cit].babelpreamble(*lit));
1059                 }
1060         }
1061         if (use_babel && !UsedLanguages_.empty()) {
1062                 FloatList const & floats = params_.documentClass().floats();
1063                 UsedFloats::const_iterator fit = usedFloats_.begin();
1064                 UsedFloats::const_iterator fend = usedFloats_.end();
1065                 for (; fit != fend; ++fit) {
1066                         Floating const & fl = floats.getType(fit->first);
1067                         docstring const type = from_ascii(fl.floattype());
1068                         docstring const flname = from_utf8(fl.name());
1069                         docstring name = translateIfPossible(flname,
1070                                 buffer().language()->code());
1071                         snippets.insert(getFloatI18nPreamble(
1072                                 type, name,
1073                                 from_ascii(buffer().language()->babel())));
1074                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1075                                 name = translateIfPossible(flname,
1076                                         (*lit)->code());
1077                                 snippets.insert(getFloatI18nPreamble(
1078                                         type, name,
1079                                         from_ascii((*lit)->babel())));
1080                         }
1081                 }
1082         }
1083
1084         odocstringstream tcpreamble;
1085         set<docstring>::const_iterator const send = snippets.end();
1086         set<docstring>::const_iterator it = snippets.begin();
1087         for (; it != send; ++it)
1088                 tcpreamble << *it;
1089         return tcpreamble.str();
1090 }
1091
1092
1093 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1094 {
1095         // Definition of entities used in the document that are LyX related.
1096         odocstringstream entities;
1097
1098         if (mustProvide("lyxarrow")) {
1099                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1100         }
1101
1102         return entities.str();
1103 }
1104
1105
1106 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1107 {
1108         odocstringstream sgmlpreamble;
1109         // FIXME UNICODE
1110         docstring const basename(from_utf8(onlyPath(fname)));
1111
1112         FileMap::const_iterator end = IncludedFiles_.end();
1113         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1114              fi != end; ++fi)
1115                 // FIXME UNICODE
1116                 sgmlpreamble << "\n<!ENTITY " << fi->first
1117                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
1118                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1119
1120         return sgmlpreamble.str();
1121 }
1122
1123
1124 void LaTeXFeatures::showStruct() const
1125 {
1126         lyxerr << "LyX needs the following commands when LaTeXing:"
1127                << "\n***** Packages:" << getPackages()
1128                << "\n***** Macros:" << to_utf8(getMacros())
1129                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1130                << "\n***** done." << endl;
1131 }
1132
1133
1134 Buffer const & LaTeXFeatures::buffer() const
1135 {
1136         return *buffer_;
1137 }
1138
1139
1140 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1141 {
1142         buffer_ = &buffer;
1143 }
1144
1145
1146 BufferParams const & LaTeXFeatures::bufferParams() const
1147 {
1148         return params_;
1149 }
1150
1151
1152 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1153 {
1154         FloatList const & floats = params_.documentClass().floats();
1155
1156         // Here we will output the code to create the needed float styles.
1157         // We will try to do this as minimal as possible.
1158         // \floatstyle{ruled}
1159         // \newfloat{algorithm}{htbp}{loa}
1160         // \providecommand{\algorithmname}{Algorithm}
1161         // \floatname{algorithm}{\protect\algorithmname}
1162         UsedFloats::const_iterator cit = usedFloats_.begin();
1163         UsedFloats::const_iterator end = usedFloats_.end();
1164         for (; cit != end; ++cit) {
1165                 Floating const & fl = floats.getType(cit->first);
1166
1167                 // For builtin floats we do nothing.
1168                 if (!fl.needsFloatPkg()) 
1169                         continue;
1170
1171                 // We have to special case "table" and "figure"
1172                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1173                         // Output code to modify "table" or "figure"
1174                         // but only if builtin == false
1175                         // and that have to be true at this point in the
1176                         // function.
1177                         docstring const type = from_ascii(fl.floattype());
1178                         docstring const placement = from_ascii(fl.placement());
1179                         docstring const style = from_ascii(fl.style());
1180                         if (!style.empty()) {
1181                                 os << "\\floatstyle{" << style << "}\n"
1182                                    << "\\restylefloat{" << type << "}\n";
1183                         }
1184                         if (!placement.empty()) {
1185                                 os << "\\floatplacement{" << type << "}{"
1186                                    << placement << "}\n";
1187                         }
1188                 } else {
1189                         // The other non builtin floats.
1190
1191                         docstring const type = from_ascii(fl.floattype());
1192                         docstring const placement = from_ascii(fl.placement());
1193                         docstring const ext = from_ascii(fl.ext());
1194                         docstring const within = from_ascii(fl.within());
1195                         docstring const style = from_ascii(fl.style());
1196                         docstring const name = translateIfPossible(
1197                                         from_utf8(fl.name()),
1198                                         buffer().language()->code());
1199                         os << "\\floatstyle{" << style << "}\n"
1200                            << "\\newfloat{" << type << "}{" << placement
1201                            << "}{" << ext << '}';
1202                         if (!within.empty())
1203                                 os << '[' << within << ']';
1204                         os << '\n'
1205                            << "\\providecommand{\\" << type << "name}{"
1206                            << name << "}\n"
1207                            << "\\floatname{" << type << "}{\\protect\\"
1208                            << type << "name}\n";
1209
1210                         // What missing here is to code to minimalize the code
1211                         // output so that the same floatstyle will not be
1212                         // used several times, when the same style is still in
1213                         // effect. (Lgb)
1214                 }
1215                 if (cit->second)
1216                         os << "\n\\newsubfloat{" << from_ascii(fl.floattype()) << "}\n";
1217         }
1218 }
1219
1220
1221 } // namespace lyx