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