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