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