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