]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
d5b8b2f26659a476907b333c759038c3ec2408f4
[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 "LaTeXFonts.h"
28 #include "LaTeXPackages.h"
29 #include "Layout.h"
30 #include "Lexer.h"
31 #include "LyXRC.h"
32 #include "TextClass.h"
33
34 #include "insets/InsetLayout.h"
35
36 #include "support/debug.h"
37 #include "support/docstream.h"
38 #include "support/FileName.h"
39 #include "support/filetools.h"
40 #include "support/gettext.h"
41 #include "support/lstrings.h"
42 #include "support/regex.h"
43
44 #include <algorithm>
45
46
47 using namespace std;
48 using namespace lyx::support;
49
50
51 namespace lyx {
52
53 /////////////////////////////////////////////////////////////////////
54 //
55 // Strings
56 //
57 /////////////////////////////////////////////////////////////////////
58
59 //\NeedsTeXFormat{LaTeX2e}
60 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
61 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
62
63 static docstring const lyx_def = from_ascii(
64         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
65
66 static docstring const lyx_hyperref_def = from_ascii(
67         "\\providecommand{\\LyX}{\\texorpdfstring%\n"
68         "  {L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}\n"
69         "  {LyX}}");
70
71 static docstring const noun_def = from_ascii(
72         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
73
74 static docstring const lyxarrow_def = from_ascii(
75         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
76         "\\@ifstar\n"
77         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
78         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
79
80 // for quotes without babel. This does not give perfect results, but
81 // anybody serious about non-english quotes should use babel (JMarc).
82
83 static docstring const quotedblbase_def = from_ascii(
84         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
85         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
86         "  \\penalty10000\\hskip0em\\relax%\n"
87         "}");
88
89 static docstring const quotesinglbase_def = from_ascii(
90         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
91         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
92         "  \\penalty10000\\hskip0em\\relax%\n"
93         "}");
94
95 static docstring const guillemotleft_def = from_ascii(
96         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
97         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
98         "\\penalty10000\\hskip0pt\\relax%\n"
99         "}");
100
101 static docstring const guillemotright_def = from_ascii(
102         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
103         "  \\penalty10000\\hskip0pt%\n"
104         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
105         "}");
106
107 static docstring const guilsinglleft_def = from_ascii(
108         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
109         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
110         "  \\penalty10000\\hskip0pt\\relax%\n"
111         "}");
112
113 static docstring const guilsinglright_def = from_ascii(
114         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
115         "  \\penalty10000\\hskip0pt%\n"
116         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
117         "}");
118
119 static docstring const paragraphleftindent_def = from_ascii(
120         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
121         "{\n"
122         "  \\begin{list}{}{%\n"
123         "    \\setlength{\\topsep}{0pt}%\n"
124         "    \\addtolength{\\leftmargin}{#1}\n"
125 // ho hum, yet more things commented out with no hint as to why they
126 // weren't just removed
127 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
128 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
129 //      "%%    \\setlength\\listparindent\\parindent%\n"
130 //      "%%    \\setlength\\itemindent\\parindent%\n"
131         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
132         "  }\n"
133         "  \\item[]\n"
134         "}\n"
135         "{\\end{list}}\n");
136
137 static docstring const binom_def = from_ascii(
138         "%% Binom macro for standard LaTeX users\n"
139         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
140
141 static docstring const mathcircumflex_def = from_ascii(
142         "%% For printing a cirumflex inside a formula\n"
143         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
144
145 static docstring const tabularnewline_def = from_ascii(
146         "%% Because html converters don't know tabularnewline\n"
147         "\\providecommand{\\tabularnewline}{\\\\}\n");
148
149 static docstring const lyxgreyedout_def = from_ascii(
150         "%% The greyedout annotation environment\n"
151         "\\newenvironment{lyxgreyedout}\n"
152         "  {\\textcolor{note_fontcolor}\\bgroup\\ignorespaces}\n"
153         "  {\\ignorespacesafterend\\egroup}\n");
154
155 // We want to omit the file extension for includegraphics, but this does not
156 // work when the filename contains other dots.
157 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
158 static docstring const lyxdot_def = from_ascii(
159         "%% A simple dot to overcome graphicx limitations\n"
160         "\\newcommand{\\lyxdot}{.}\n");
161
162 static docstring const changetracking_dvipost_def = from_ascii(
163         "%% Change tracking with dvipost\n"
164         "\\dvipostlayout\n"
165         "\\dvipost{osstart color push Red}\n"
166         "\\dvipost{osend color pop}\n"
167         "\\dvipost{cbstart color push Blue}\n"
168         "\\dvipost{cbend color pop}\n"
169         "\\DeclareRobustCommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
170         "\\DeclareRobustCommand{\\lyxdeleted}[3]{%\n"
171         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
172
173 static docstring const changetracking_xcolor_ulem_def = from_ascii(
174         "%% Change tracking with ulem\n"
175         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
176         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
177
178 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
179         "%% Change tracking with ulem\n"
180         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
181         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
182
183 static docstring const changetracking_none_def = from_ascii(
184         "\\newcommand{\\lyxadded}[3]{#3}\n"
185         "\\newcommand{\\lyxdeleted}[3]{}\n");
186
187 static docstring const textgreek_def = from_ascii(
188         "\\DeclareRobustCommand{\\greektext}{%\n"
189         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
190         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
191         "\\DeclareFontEncoding{LGR}{}{}\n"
192         "\\DeclareTextSymbol{\\~}{LGR}{126}");
193
194 static docstring const textcyr_def = from_ascii(
195         "\\DeclareRobustCommand{\\cyrtext}{%\n"
196         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
197         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
198         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
199
200 static docstring const lyxmathsym_def = from_ascii(
201         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
202         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
203
204 static docstring const papersizedvi_def = from_ascii(
205         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
206
207 static docstring const papersizepdf_def = from_ascii(
208         "\\pdfpageheight\\paperheight\n"
209         "\\pdfpagewidth\\paperwidth\n");
210
211 static docstring const cedilla_def = from_ascii(
212         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
213         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
214
215 static docstring const subring_def = from_ascii(
216         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
217         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
218
219 static docstring const subdot_def = from_ascii(
220         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
221         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
222
223 static docstring const subhat_def = from_ascii(
224         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
225         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
226
227 static docstring const subtilde_def = from_ascii(
228         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
229         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
230
231 static docstring const dacute_def = from_ascii(
232         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
233
234 static docstring const tipasymb_def = from_ascii(
235         "\\DeclareFontEncoding{T3}{}{}\n"
236         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
237
238 static docstring const dgrave_def = from_ascii(
239         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
240
241 static docstring const rcap_def = from_ascii(
242         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
243
244 static docstring const ogonek_def = from_ascii(
245         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
246         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
247         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
248         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
249         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
250
251 static docstring const lyxref_def = from_ascii(
252                 "\\RS@ifundefined{subsecref}\n"
253                 "  {\\newref{subsec}{name = \\RSsectxt}}\n"
254                 "  {}\n"
255                 "\\RS@ifundefined{thmref}\n"
256                 "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
257                 "  {}\n"
258                 "\\RS@ifundefined{lemref}\n"
259                 "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n"
260                 "  {}\n");
261
262 // Make sure the columns are also outputed as rtl
263 static docstring const rtloutputdblcol_def = from_ascii(
264         "\\def\\@outputdblcol{%\n"
265         "  \\if@firstcolumn\n"
266         "    \\global \\@firstcolumnfalse\n"
267         "    \\global \\setbox\\@leftcolumn \\box\\@outputbox\n"
268         "  \\else\n"
269         "    \\global \\@firstcolumntrue\n"
270         "    \\setbox\\@outputbox \\vbox {%\n"
271         "      \\hb@xt@\\textwidth {%\n"
272         "      \\kern\\textwidth \\kern-\\columnwidth %**\n"
273         "      \\hb@xt@\\columnwidth {%\n"
274         "         \\box\\@leftcolumn \\hss}%\n"
275         "      \\kern-\\textwidth %**\n"
276         "      \\hfil\n"
277         "      {\\normalcolor\\vrule \\@width\\columnseprule}%\n"
278         "      \\hfil\n"
279         "      \\kern-\\textwidth  %**\n"
280         "      \\hb@xt@\\columnwidth {%\n"
281         "         \\box\\@outputbox \\hss}%\n"
282         "      \\kern-\\columnwidth \\kern\\textwidth %**\n"
283         "    }%\n"
284         "  }%\n"
285         "  \\@combinedblfloats\n"
286         "  \\@outputpage\n"
287         "  \\begingroup\n"
288         "  \\@dblfloatplacement\n"
289         "  \\@startdblcolumn\n"
290         "  \\@whilesw\\if@fcolmade \\fi\n"
291         "  {\\@outputpage\n"
292         "    \\@startdblcolumn}%\n"
293         "  \\endgroup\n"
294         "  \\fi\n"
295         "}\n"
296         "\\@mparswitchtrue\n");
297
298
299 /////////////////////////////////////////////////////////////////////
300 //
301 // LyXHTML strings
302 //
303 /////////////////////////////////////////////////////////////////////
304
305 static docstring const lyxnoun_style = from_ascii(
306         "dfn.lyxnoun {\n"
307         "  font-variant: small-caps;\n"
308         "}\n");
309
310
311 // this is how it normally renders, but it might not always do so.
312 static docstring const lyxstrikeout_style = from_ascii(
313         "del.strikeout {\n"
314         "  text-decoration: line-through;\n"
315         "}\n");
316
317
318 /////////////////////////////////////////////////////////////////////
319 //
320 // LaTeXFeatures
321 //
322 /////////////////////////////////////////////////////////////////////
323
324
325 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
326                              OutputParams const & r)
327         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
328 {}
329
330
331 LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const
332 {
333         string const local_lp = bufferParams().lang_package;
334
335         // Locally, custom is just stored as a string
336         // in bufferParams().lang_package.
337         if (local_lp != "auto"
338             && local_lp != "babel"
339             && local_lp != "default"
340             && local_lp != "none")
341                  return LANG_PACK_CUSTOM;
342
343         if (local_lp == "none")
344                 return LANG_PACK_NONE;
345
346         /* If "auto" is selected, we load polyglossia if required,
347          * else we select babel.
348          * If babel is selected (either directly or via the "auto"
349          * mechanism), we really do only require it if we have
350          * a language that needs it.
351          */
352         bool const polyglossia_required =
353                 isRequired("polyglossia")
354                 && isAvailable("polyglossia")
355                 && !isProvided("babel")
356                 && this->hasOnlyPolyglossiaLanguages();
357         bool const babel_required =
358                 !bufferParams().language->babel().empty()
359                 || !this->getBabelLanguages().empty();
360
361         if (local_lp == "auto") {
362                 // polyglossia requirement has priority over babel
363                 if (polyglossia_required)
364                         return LANG_PACK_POLYGLOSSIA;
365                 else if (babel_required)
366                         return LANG_PACK_BABEL;
367         }
368
369         if (local_lp == "babel") {
370                 if (babel_required)
371                         return LANG_PACK_BABEL;
372         }
373
374         if (local_lp == "default") {
375                 switch (lyxrc.language_package_selection) {
376                 case LyXRC::LP_AUTO:
377                         // polyglossia requirement has priority over babel
378                         if (polyglossia_required)
379                                 return LANG_PACK_POLYGLOSSIA;
380                         else if (babel_required)
381                                 return LANG_PACK_BABEL;
382                         break;
383                 case LyXRC::LP_BABEL:
384                         if (babel_required)
385                                 return LANG_PACK_BABEL;
386                         break;
387                 case LyXRC::LP_CUSTOM:
388                         return LANG_PACK_CUSTOM;
389                 case LyXRC::LP_NONE:
390                         return LANG_PACK_NONE;
391                 }
392         }
393
394         return LANG_PACK_NONE;
395 }
396
397
398 void LaTeXFeatures::require(string const & name)
399 {
400         features_.insert(name);
401 }
402
403
404 void LaTeXFeatures::require(set<string> const & names)
405 {
406         features_.insert(names.begin(), names.end());
407 }
408
409
410 void LaTeXFeatures::useLayout(docstring const & layoutname)
411 {
412         useLayout(layoutname, 0);
413 }
414
415
416 void LaTeXFeatures::useLayout(docstring const & layoutname, int level)
417 {
418         // Some code to avoid loops in dependency definition
419         const int maxlevel = 30;
420         if (level > maxlevel) {
421                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
422                        << "recursion attained by layout "
423                        << to_utf8(layoutname) << endl;
424                 return;
425         }
426
427         DocumentClass const & tclass = params_.documentClass();
428         if (tclass.hasLayout(layoutname)) {
429                 // Is this layout already in usedLayouts?
430                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
431                     != usedLayouts_.end())
432                         return;
433
434                 Layout const & layout = tclass[layoutname];
435                 require(layout.requires());
436
437                 if (!layout.depends_on().empty()) {
438                         useLayout(layout.depends_on(), level + 1);
439                 }
440                 usedLayouts_.push_back(layoutname);
441         } else {
442                 lyxerr << "LaTeXFeatures::useLayout: layout `"
443                        << to_utf8(layoutname) << "' does not exist in this class"
444                        << endl;
445         }
446 }
447
448
449 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
450 {
451         docstring const & lname = lay.name();
452         DocumentClass const & tclass = params_.documentClass();
453
454         // this is a default inset layout, nothing useful here
455         if (!tclass.hasInsetLayout(lname))
456                 return;
457         // Is this layout already in usedInsetLayouts?
458         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
459                         != usedInsetLayouts_.end())
460                 return;
461
462         require(lay.requires());
463         usedInsetLayouts_.push_back(lname);
464 }
465
466
467 bool LaTeXFeatures::isRequired(string const & name) const
468 {
469         return features_.find(name) != features_.end();
470 }
471
472
473 bool LaTeXFeatures::isProvided(string const & name) const
474 {
475         if (params_.useNonTeXFonts)
476                 return params_.documentClass().provides(name);
477
478         bool const ot1 = (params_.font_encoding() == "default"
479                 || params_.font_encoding() == "OT1");
480         bool const complete = (params_.fonts_sans == "default")
481                 && (params_.fonts_typewriter == "default");
482         bool const nomath = (params_.fonts_math == "default");
483         return params_.documentClass().provides(name)
484                 || theLaTeXFonts().getLaTeXFont(
485                         from_ascii(params_.fonts_roman)).provides(name, ot1,
486                                                                   complete,
487                                                                   nomath)
488                 || theLaTeXFonts().getLaTeXFont(
489                         from_ascii(params_.fonts_sans)).provides(name, ot1,
490                                                                  complete,
491                                                                  nomath)
492                 || theLaTeXFonts().getLaTeXFont(
493                         from_ascii(params_.fonts_typewriter)).provides(name, ot1,
494                                                                        complete,
495                                                                        nomath)
496                 || theLaTeXFonts().getLaTeXFont(
497                         from_ascii(params_.fonts_math)).provides(name, ot1,
498                                                                        complete,
499                                                                        nomath);
500 }
501
502
503 bool LaTeXFeatures::mustProvide(string const & name) const
504 {
505         return isRequired(name) && !isProvided(name);
506 }
507
508
509 bool LaTeXFeatures::isAvailable(string const & name)
510 {
511         string::size_type const i = name.find("->");
512         if (i != string::npos) {
513                 string const from = name.substr(0,i);
514                 string const to = name.substr(i+2);
515                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
516                 return theConverters().isReachable(from, to);
517         }
518         return LaTeXPackages::isAvailable(name);
519 }
520
521
522 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
523 {
524         SnippetList::const_iterator begin = preamble_snippets_.begin();
525         SnippetList::const_iterator end   = preamble_snippets_.end();
526         if (find(begin, end, preamble) == end)
527                 preamble_snippets_.push_back(preamble);
528 }
529
530
531 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
532 {
533         SnippetList::const_iterator begin = css_snippets_.begin();
534         SnippetList::const_iterator end   = css_snippets_.end();
535         if (find(begin, end, snippet) == end)
536                 css_snippets_.push_back(snippet);
537 }
538
539
540 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
541 {
542         if (!usedFloats_[name])
543                 usedFloats_[name] = subfloat;
544         if (subfloat)
545                 require("subfig");
546         // We only need float.sty if we use non builtin floats, or if we
547         // use the "H" modifier. This includes modified table and
548         // figure floats. (Lgb)
549         Floating const & fl = params_.documentClass().floats().getType(name);
550         if (!fl.floattype().empty() && fl.usesFloatPkg()) {
551                 require("float");
552         }
553 }
554
555
556 void LaTeXFeatures::useLanguage(Language const * lang)
557 {
558         if (!lang->babel().empty() || !lang->polyglossia().empty())
559                 UsedLanguages_.insert(lang);
560         if (!lang->requires().empty())
561                 require(lang->requires());
562         // CJK languages do not have a babel name.
563         // They use the CJK package
564         if (lang->encoding()->package() == Encoding::CJK)
565                 require("CJK");
566         // japanese package is special
567         if (lang->encoding()->package() == Encoding::japanese)
568                 require("japanese");
569 }
570
571
572 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
573 {
574         IncludedFiles_[key] = name;
575 }
576
577
578 bool LaTeXFeatures::hasLanguages() const
579 {
580         return !UsedLanguages_.empty();
581 }
582
583
584 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
585 {
586         // first the main language
587         if (params_.language->polyglossia().empty())
588                 return false;
589         // now the secondary languages
590         LanguageList::const_iterator const begin = UsedLanguages_.begin();
591         for (LanguageList::const_iterator cit = begin;
592              cit != UsedLanguages_.end();
593              ++cit) {
594                 if ((*cit)->polyglossia().empty())
595                         return false;
596         }
597         return true;
598 }
599
600
601 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
602 {
603         // first the main language
604         if (params_.language->isPolyglossiaExclusive())
605                 return true;
606         // now the secondary languages
607         LanguageList::const_iterator const begin = UsedLanguages_.begin();
608         for (LanguageList::const_iterator cit = begin;
609              cit != UsedLanguages_.end();
610              ++cit) {
611                 if ((*cit)->isPolyglossiaExclusive())
612                         return true;
613         }
614         return false;
615 }
616
617
618 string LaTeXFeatures::getBabelLanguages() const
619 {
620         ostringstream languages;
621
622         bool first = true;
623         LanguageList::const_iterator const begin = UsedLanguages_.begin();
624         for (LanguageList::const_iterator cit = begin;
625              cit != UsedLanguages_.end();
626              ++cit) {
627                 if ((*cit)->babel().empty())
628                         continue;
629                 if (!first)
630                         languages << ',';
631                 else
632                         first = false;
633                 languages << (*cit)->babel();
634         }
635         return languages.str();
636 }
637
638
639 std::map<std::string, std::string> LaTeXFeatures::getPolyglossiaLanguages() const
640 {
641         std::map<std::string, std::string> languages;
642
643         LanguageList::const_iterator const begin = UsedLanguages_.begin();
644         for (LanguageList::const_iterator cit = begin;
645              cit != UsedLanguages_.end();
646              ++cit) {
647                 languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts();
648         }
649         return languages;
650 }
651
652
653 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
654 {
655         // This does only find encodings of languages supported by babel, but
656         // that does not matter since we don't have a language with an
657         // encoding supported by inputenc but without babel support.
658         set<string> encodings;
659         LanguageList::const_iterator it  = UsedLanguages_.begin();
660         LanguageList::const_iterator end = UsedLanguages_.end();
661         for (; it != end; ++it)
662                 if ((*it)->encoding()->latexName() != doc_encoding &&
663                     ((*it)->encoding()->package() == Encoding::inputenc
664                      || (*it)->encoding()->package() == Encoding::japanese))
665                         encodings.insert((*it)->encoding()->latexName());
666         return encodings;
667 }
668
669
670 void LaTeXFeatures::getFontEncodings(vector<string> & encodings) const
671 {
672         // these must be loaded if glyphs of this script
673         // are used (notwithstanding the language)
674         if (mustProvide("textgreek"))
675                 encodings.insert(encodings.begin(), "LGR");
676         if (mustProvide("textcyr"))
677                 encodings.insert(encodings.begin(), "T2A");
678
679         LanguageList::const_iterator it  = UsedLanguages_.begin();
680         LanguageList::const_iterator end = UsedLanguages_.end();
681         for (; it != end; ++it)
682                 if (!(*it)->fontenc().empty()
683                     && ascii_lowercase((*it)->fontenc()) != "none") {
684                         vector<string> extraencs = getVectorFromString((*it)->fontenc());
685                         vector<string>::const_iterator fit = extraencs.begin();
686                         for (; fit != extraencs.end(); ++fit) {
687                                 if (find(encodings.begin(), encodings.end(), *fit) == encodings.end())
688                                         encodings.insert(encodings.begin(), *fit);
689                         }
690                 }
691 }
692
693 namespace {
694
695 char const * simplefeatures[] = {
696 // note that the package order here will be the same in the LaTeX-output
697         "array",
698         "verbatim",
699         "longtable",
700         "rotating",
701         "latexsym",
702         "pifont",
703         // subfig is handled in BufferParams.cpp
704         "varioref",
705         "prettyref",
706         "refstyle",
707         /*For a successful cooperation of the `wrapfig' package with the
708           `float' package you should load the `wrapfig' package *after*
709           the `float' package. See the caption package documentation
710           for explanation.*/
711         "float",
712         "rotfloat",
713         "wrapfig",
714         "booktabs",
715         "dvipost",
716         "fancybox",
717         "calc",
718         "units",
719         "framed",
720         "soul",
721         "textcomp",
722         "pmboxdraw",
723         "bbding",
724         "ifsym",
725         "marvosym",
726         "txfonts",
727         "pxfonts",
728         "mathdesign",
729         "mathrsfs",
730         "mathabx",
731         "mathtools",
732         // "cancel",
733         "ascii",
734         "url",
735         "covington",
736         "csquotes",
737         "enumitem",
738         "endnotes",
739         "hhline",
740         "ifthen",
741         // listings is handled in BufferParams.cpp
742         "bm",
743         "pdfpages",
744         "amscd",
745         "slashed",
746         "multicol",
747         "multirow",
748         "tfrupee",
749         "shapepar",
750         "rsphrase",
751         "hpstatement",
752         "algorithm2e",
753         "sectionbox",
754         "tcolorbox",
755         "pdfcomment",
756         "fixme",
757         "todonotes",
758         "forest"
759 };
760
761 char const * bibliofeatures[] = {
762         // Known bibliography packages (will be loaded before natbib)
763         "achicago",
764         "apacite",
765         "apalike",
766         "astron",
767         "authordate1-4",
768         "babelbib",
769         "bibgerm",
770         "chicago",
771         "chscite",
772         "harvard",
773         "mslapa",
774         "named"
775 };
776
777 int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *);
778
779 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
780
781 }
782
783
784 string const LaTeXFeatures::getColorOptions() const
785 {
786         ostringstream colors;
787
788         // Handling the color packages separately is needed to be able to load them
789         // before babel when hyperref is loaded with the colorlinks option
790         // for more info see Bufferparams.cpp
791
792         // [x]color.sty
793         if (mustProvide("color") || mustProvide("xcolor")) {
794                 string const package =
795                         (mustProvide("xcolor") ? "xcolor" : "color");
796                 if (params_.graphics_driver == "default"
797                         || params_.graphics_driver == "none")
798                         colors << "\\usepackage{" << package << "}\n";
799                 else
800                         colors << "\\usepackage["
801                                  << params_.graphics_driver
802                                  << "]{" << package << "}\n";
803         }
804
805         // pdfcolmk must be loaded after color
806         if (mustProvide("pdfcolmk"))
807                 colors << "\\usepackage{pdfcolmk}\n";
808
809         // the following 3 color commands must be set after color
810         // is loaded and before pdfpages, therefore add the command
811         // here define the set color
812         if (mustProvide("pagecolor")) {
813                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
814                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
815                 // set the page color
816                 colors << "\\pagecolor{page_backgroundcolor}\n";
817         }
818
819         if (mustProvide("fontcolor")) {
820                 colors << "\\definecolor{document_fontcolor}{rgb}{";
821                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
822                 // set the color
823                 colors << "\\color{document_fontcolor}\n";
824         }
825
826         if (mustProvide("lyxgreyedout")) {
827                 colors << "\\definecolor{note_fontcolor}{rgb}{";
828                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
829                 // the color will be set together with the definition of
830                 // the lyxgreyedout environment (see lyxgreyedout_def)
831         }
832
833         // color for shaded boxes
834         if (isRequired("framed") && mustProvide("color")) {
835                 colors << "\\definecolor{shadecolor}{rgb}{";
836                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
837                 // this color is automatically used by the LaTeX-package "framed"
838         }
839
840         return colors.str();
841 }
842
843
844 string const LaTeXFeatures::getPackageOptions() const
845 {
846         ostringstream packageopts;
847         // Output all the package option stuff we have been asked to do.
848         map<string, string>::const_iterator it =
849                 params_.documentClass().packageOptions().begin();
850         map<string, string>::const_iterator en =
851                 params_.documentClass().packageOptions().end();
852         for (; it != en; ++it)
853                 if (mustProvide(it->first))
854                         packageopts << "\\PassOptionsToPackage{" << it->second << "}"
855                                  << "{" << it->first << "}\n";
856         return packageopts.str();
857 }
858
859
860 string const LaTeXFeatures::getPackages() const
861 {
862         ostringstream packages;
863
864         // FIXME: currently, we can only load packages and macros known
865         // to LyX.
866         // However, with the Require tag of layouts/custom insets,
867         // also unknown packages can be requested. They are silently
868         // swallowed now. We should change this eventually.
869
870         //  These are all the 'simple' includes.  i.e
871         //  packages which we just \usepackage{package}
872         for (int i = 0; i < nb_simplefeatures; ++i) {
873                 if (mustProvide(simplefeatures[i]))
874                         packages << "\\usepackage{" << simplefeatures[i] << "}\n";
875         }
876
877         // The rest of these packages are somewhat more complicated
878         // than those above.
879
880         // The tipa package and its extensions (tipx, tone) must not
881         // be loaded with non-TeX fonts, since fontspec includes the
882         // respective macros
883         if (mustProvide("tipa") && !params_.useNonTeXFonts)
884                 packages << "\\usepackage{tipa}\n";
885         if (mustProvide("tipx") && !params_.useNonTeXFonts)
886                 packages << "\\usepackage{tipx}\n";
887         if (mustProvide("tone") && !params_.useNonTeXFonts)
888                 packages << "\\usepackage{tone}\n";
889
890         // if fontspec or newtxmath is used, AMS packages have to be loaded
891         // before fontspec (in BufferParams)
892         string const amsPackages = loadAMSPackages();
893         bool const ot1 = (params_.font_encoding() == "default" || params_.font_encoding() == "OT1");
894         bool const use_newtxmath =
895                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fonts_math)).getUsedPackage(
896                         ot1, false, false) == "newtxmath";
897
898         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
899                 packages << amsPackages;
900
901         if (mustProvide("cancel") &&
902             params_.use_package("cancel") != BufferParams::package_off)
903                 packages << "\\usepackage{cancel}\n";
904
905         // accents must be loaded after amsmath
906         if (mustProvide("accents") &&
907             params_.use_package("accents") != BufferParams::package_off)
908                 packages << "\\usepackage{accents}\n";
909
910         // mathdots must be loaded after amsmath
911         if (mustProvide("mathdots") &&
912                 params_.use_package("mathdots") != BufferParams::package_off)
913                 packages << "\\usepackage{mathdots}\n";
914
915         // yhmath must be loaded after amsmath
916         if (mustProvide("yhmath") &&
917             params_.use_package("yhmath") != BufferParams::package_off)
918                 packages << "\\usepackage{yhmath}\n";
919
920         // stmaryrd must be loaded after amsmath
921         if (mustProvide("stmaryrd") &&
922             params_.use_package("stmaryrd") != BufferParams::package_off)
923                 packages << "\\usepackage{stmaryrd}\n";
924
925         if (mustProvide("stackrel") &&
926             params_.use_package("stackrel") != BufferParams::package_off)
927                 packages << "\\usepackage{stackrel}\n";
928
929         if (mustProvide("undertilde") &&
930                 params_.use_package("undertilde") != BufferParams::package_off)
931                 packages << "\\usepackage{undertilde}\n";
932
933         // [x]color and pdfcolmk are handled in getColorOptions() above
934
935         // makeidx.sty
936         if (isRequired("makeidx") || isRequired("splitidx")) {
937                 if (!isProvided("makeidx") && !isRequired("splitidx"))
938                         packages << "\\usepackage{makeidx}\n";
939                 if (mustProvide("splitidx"))
940                         packages << "\\usepackage{splitidx}\n";
941                 packages << "\\makeindex\n";
942         }
943
944         // graphicx.sty
945         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
946                 if (params_.graphics_driver == "default")
947                         packages << "\\usepackage{graphicx}\n";
948                 else
949                         packages << "\\usepackage["
950                                  << params_.graphics_driver
951                                  << "]{graphicx}\n";
952         }
953
954         // lyxskak.sty --- newer chess support based on skak.sty
955         if (mustProvide("chess"))
956                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
957
958         // setspace.sty
959         if (mustProvide("setspace") && !isProvided("SetSpace"))
960                 packages << "\\usepackage{setspace}\n";
961
962         // we need to assure that mhchem is loaded before esint and every other
963         // package that redefines command of amsmath because mhchem loads amlatex
964         // (this info is from the author of mhchem from June 2013)
965         if (mustProvide("mhchem") &&
966             params_.use_package("mhchem") != BufferParams::package_off)
967                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
968                             "\\usepackage{mhchem}\n";
969
970         // wasysym is a simple feature, but it must be after amsmath if both
971         // are used
972         // wasysym redefines some integrals (e.g. iint) from amsmath. That
973         // leads to inconsistent integrals. We only load this package if
974         // the document does not contain integrals (then isRequired("esint")
975         // is false) or if esint is used, since esint redefines all relevant
976         // integral symbols from wasysym and amsmath.
977         // See http://www.lyx.org/trac/ticket/1942
978         if (mustProvide("wasysym") &&
979             params_.use_package("wasysym") != BufferParams::package_off &&
980             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
981                 packages << "\\usepackage{wasysym}\n";
982
983         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
984         // and wasysym, since it will redeclare inconsistent integral symbols
985         if (mustProvide("esint") &&
986             params_.use_package("esint") != BufferParams::package_off)
987                 packages << "\\usepackage{esint}\n";
988
989         // Known bibliography packages (simple \usepackage{package})
990         for (int i = 0; i < nb_bibliofeatures; ++i) {
991                 if (mustProvide(bibliofeatures[i]))
992                         packages << "\\usepackage{"
993                                  << bibliofeatures[i] << "}\n";
994         }
995
996         // Compatibility between achicago and natbib
997         if (mustProvide("achicago") && mustProvide("natbib"))
998                 packages << "\\let\\achicagobib\\thebibliography\n";
999
1000         // natbib.sty
1001         // Some classes load natbib themselves, but still allow (or even require)
1002         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1003         // This special case is indicated by the "natbib-internal" key.
1004         if (mustProvide("natbib") && !isProvided("natbib-internal")) {
1005                 packages << "\\usepackage[";
1006                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1007                         packages << "numbers";
1008                 else
1009                         packages << "authoryear";
1010                 packages << "]{natbib}\n";
1011         }
1012
1013         // Compatibility between achicago and natbib
1014         if (mustProvide("achicago") && mustProvide("natbib")) {
1015                 packages << "\\let\\thebibliography\\achicagobib\n";
1016                 packages << "\\let\\SCcite\\astroncite\n";
1017                 packages << "\\let\\UnexpandableProtect\\protect\n";
1018         }
1019
1020         // jurabib -- we need version 0.6 at least.
1021         if (mustProvide("jurabib"))
1022                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
1023
1024         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1025         if (mustProvide("opcit")) {
1026                 if (isRequired("hyperref"))
1027                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1028                 else
1029                         packages << "\\usepackage[custombst]{opcit}\n";
1030         }
1031
1032         // xargs -- we need version 1.09 at least
1033         if (mustProvide("xargs"))
1034                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1035
1036         if (mustProvide("xy"))
1037                 packages << "\\usepackage[all]{xy}\n";
1038
1039         if (mustProvide("feyn"))
1040                 packages << "\\usepackage{feyn}\n"; //Diagram
1041
1042         if (mustProvide("ulem"))
1043                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1044                             "\\usepackage{ulem}\n";
1045
1046         if (mustProvide("nomencl")) {
1047                 // Make it work with the new and old version of the package,
1048                 // but don't use the compatibility option since it is
1049                 // incompatible to other packages.
1050                 packages << "\\usepackage{nomencl}\n"
1051                             "% the following is useful when we have the old nomencl.sty package\n"
1052                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1053                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1054                             "\\makenomenclature\n";
1055         }
1056
1057         // fixltx2e provides subscript
1058         if (mustProvide("subscript") && !isRequired("fixltx2e"))
1059                 packages << "\\usepackage{subscript}\n";
1060
1061         // footmisc must be loaded after setspace
1062         // Set options here, load the package after the user preamble to
1063         // avoid problems with manual loaded footmisc.
1064         if (mustProvide("footmisc"))
1065                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1066
1067         return packages.str();
1068 }
1069
1070
1071 string LaTeXFeatures::getPreambleSnippets() const
1072 {
1073         ostringstream snip;
1074         SnippetList::const_iterator pit  = preamble_snippets_.begin();
1075         SnippetList::const_iterator pend = preamble_snippets_.end();
1076         for (; pit != pend; ++pit)
1077                 snip << *pit << '\n';
1078         return snip.str();
1079 }
1080
1081
1082 std::string LaTeXFeatures::getCSSSnippets() const
1083 {
1084         ostringstream snip;
1085         SnippetList::const_iterator pit  = css_snippets_.begin();
1086         SnippetList::const_iterator pend = css_snippets_.end();
1087         for (; pit != pend; ++pit)
1088                 snip << *pit << '\n';
1089         return snip.str();
1090 }
1091
1092
1093 docstring const LaTeXFeatures::getMacros() const
1094 {
1095         odocstringstream macros;
1096
1097         if (!preamble_snippets_.empty()) {
1098                 macros << '\n';
1099                 macros << from_utf8(getPreambleSnippets());
1100         }
1101
1102         if (mustProvide("papersize")) {
1103                 if (runparams_.flavor == OutputParams::LATEX)
1104                         macros << papersizedvi_def << '\n';
1105                 else
1106                         macros << papersizepdf_def << '\n';
1107         }
1108
1109         if (mustProvide("LyX")) {
1110                 if (isRequired("hyperref"))
1111                         macros << lyx_hyperref_def << '\n';
1112                 else
1113                         macros << lyx_def << '\n';
1114         }
1115
1116         if (mustProvide("noun"))
1117                 macros << noun_def << '\n';
1118
1119         if (mustProvide("lyxarrow"))
1120                 macros << lyxarrow_def << '\n';
1121
1122         if (!usePolyglossia() && mustProvide("textgreek")) {
1123                 // Avoid a LaTeX error if times fonts are used and the grtimes
1124                 // package is installed but actual fonts are not (bug 6469).
1125                 if (params_.fonts_roman == "times")
1126                         macros << subst(textgreek_def,
1127                                         from_ascii("\\greektext #1"),
1128                                         from_ascii("%\n  \\IfFileExists"
1129                                                    "{grtm10.tfm}{}{\\fontfamily"
1130                                                    "{cmr}}\\greektext #1"))
1131                                << '\n';
1132                 else
1133                         macros << textgreek_def << '\n';
1134         }
1135
1136         if (!usePolyglossia() && mustProvide("textcyr"))
1137                 macros << textcyr_def << '\n';
1138
1139         if (mustProvide("lyxmathsym"))
1140                 macros << lyxmathsym_def << '\n';
1141
1142         if (mustProvide("cedilla"))
1143                 macros << cedilla_def << '\n';
1144
1145         if (mustProvide("subring"))
1146                 macros << subring_def << '\n';
1147
1148         if (mustProvide("subdot"))
1149                 macros << subdot_def << '\n';
1150
1151         if (mustProvide("subhat"))
1152                 macros << subhat_def << '\n';
1153
1154         if (mustProvide("subtilde"))
1155                 macros << subtilde_def << '\n';
1156
1157         if (mustProvide("dacute"))
1158                 macros << dacute_def << '\n';
1159
1160         if (mustProvide("tipasymb"))
1161                 macros << tipasymb_def << '\n';
1162
1163         if (mustProvide("dgrave"))
1164                 macros << dgrave_def << '\n';
1165
1166         if (mustProvide("rcap"))
1167                 macros << rcap_def << '\n';
1168
1169         if (mustProvide("ogonek"))
1170                 macros << ogonek_def << '\n';
1171
1172         // quotes.
1173         if (mustProvide("quotesinglbase"))
1174                 macros << quotesinglbase_def << '\n';
1175         if (mustProvide("quotedblbase"))
1176                 macros << quotedblbase_def << '\n';
1177         if (mustProvide("guilsinglleft"))
1178                 macros << guilsinglleft_def << '\n';
1179         if (mustProvide("guilsinglright"))
1180                 macros << guilsinglright_def << '\n';
1181         if (mustProvide("guillemotleft"))
1182                 macros << guillemotleft_def << '\n';
1183         if (mustProvide("guillemotright"))
1184                 macros << guillemotright_def << '\n';
1185
1186         // Math mode
1187         if (mustProvide("binom") && !isRequired("amsmath"))
1188                 macros << binom_def << '\n';
1189         if (mustProvide("mathcircumflex"))
1190                 macros << mathcircumflex_def << '\n';
1191
1192         // other
1193         if (mustProvide("ParagraphLeftIndent"))
1194                 macros << paragraphleftindent_def;
1195
1196         // some problems with tex->html converters
1197         if (mustProvide("NeedTabularnewline"))
1198                 macros << tabularnewline_def;
1199
1200         // greyed-out environment (note inset)
1201         // the color is specified in the routine
1202         // getColorOptions() to avoid LaTeX-package clashes
1203         if (mustProvide("lyxgreyedout"))
1204                 macros << lyxgreyedout_def;
1205
1206         if (mustProvide("lyxdot"))
1207                 macros << lyxdot_def << '\n';
1208
1209         // floats
1210         getFloatDefinitions(macros);
1211
1212         if (mustProvide("refstyle"))
1213                 macros << lyxref_def << '\n';
1214
1215         // change tracking
1216         if (mustProvide("ct-dvipost"))
1217                 macros << changetracking_dvipost_def;
1218
1219         if (mustProvide("ct-xcolor-ulem")) {
1220                 streamsize const prec = macros.precision(2);
1221
1222                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1223                 macros << "\\providecolor{lyxadded}{rgb}{"
1224                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1225
1226                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1227                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1228                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1229
1230                 macros.precision(prec);
1231
1232                 if (isRequired("hyperref"))
1233                         macros << changetracking_xcolor_ulem_hyperref_def;
1234                 else
1235                         macros << changetracking_xcolor_ulem_def;
1236         }
1237
1238         if (mustProvide("ct-none"))
1239                 macros << changetracking_none_def;
1240
1241         if (mustProvide("rtloutputdblcol"))
1242                 macros << rtloutputdblcol_def;
1243
1244         return macros.str();
1245 }
1246
1247
1248 string const LaTeXFeatures::getBabelPresettings() const
1249 {
1250         ostringstream tmp;
1251
1252         LanguageList::const_iterator it  = UsedLanguages_.begin();
1253         LanguageList::const_iterator end = UsedLanguages_.end();
1254         for (; it != end; ++it)
1255                 if (!(*it)->babel_presettings().empty())
1256                         tmp << (*it)->babel_presettings() << '\n';
1257         if (!params_.language->babel_presettings().empty())
1258                 tmp << params_.language->babel_presettings() << '\n';
1259
1260         if (!contains(tmp.str(), '@'))
1261                 return tmp.str();
1262
1263         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1264 }
1265
1266
1267 string const LaTeXFeatures::getBabelPostsettings() const
1268 {
1269         ostringstream tmp;
1270
1271         LanguageList::const_iterator it  = UsedLanguages_.begin();
1272         LanguageList::const_iterator end = UsedLanguages_.end();
1273         for (; it != end; ++it)
1274                 if (!(*it)->babel_postsettings().empty())
1275                         tmp << (*it)->babel_postsettings() << '\n';
1276         if (!params_.language->babel_postsettings().empty())
1277                 tmp << params_.language->babel_postsettings() << '\n';
1278
1279         if (!contains(tmp.str(), '@'))
1280                 return tmp.str();
1281
1282         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1283 }
1284
1285
1286 bool LaTeXFeatures::needBabelLangOptions() const
1287 {
1288         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1289                 return true;
1290
1291         LanguageList::const_iterator it  = UsedLanguages_.begin();
1292         LanguageList::const_iterator end = UsedLanguages_.end();
1293         for (; it != end; ++it)
1294                 if ((*it)->asBabelOptions())
1295                         return true;
1296
1297         return false;
1298 }
1299
1300
1301 string const LaTeXFeatures::loadAMSPackages() const
1302 {
1303         ostringstream tmp;
1304
1305         if (mustProvide("amsmath")
1306             && params_.use_package("amsmath") != BufferParams::package_off) {
1307                 tmp << "\\usepackage{amsmath}\n";
1308         } else {
1309                 // amsbsy and amstext are already provided by amsmath
1310                 if (mustProvide("amsbsy"))
1311                         tmp << "\\usepackage{amsbsy}\n";
1312                 if (mustProvide("amstext"))
1313                         tmp << "\\usepackage{amstext}\n";
1314         }
1315
1316         if (mustProvide("amsthm"))
1317                 tmp << "\\usepackage{amsthm}\n";
1318
1319         if (mustProvide("amssymb")
1320             && params_.use_package("amssymb") != BufferParams::package_off)
1321                 tmp << "\\usepackage{amssymb}\n";
1322
1323         return tmp.str();
1324 }
1325
1326
1327 docstring const LaTeXFeatures::getTClassPreamble() const
1328 {
1329         // the text class specific preamble
1330         DocumentClass const & tclass = params_.documentClass();
1331         odocstringstream tcpreamble;
1332
1333         tcpreamble << tclass.preamble();
1334
1335         list<docstring>::const_iterator cit = usedLayouts_.begin();
1336         list<docstring>::const_iterator end = usedLayouts_.end();
1337         for (; cit != end; ++cit)
1338                 tcpreamble << tclass[*cit].preamble();
1339
1340         cit = usedInsetLayouts_.begin();
1341         end = usedInsetLayouts_.end();
1342         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1343         for (; cit != end; ++cit) {
1344                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1345                 if (it == ils.end())
1346                         continue;
1347                 tcpreamble << it->second.preamble();
1348         }
1349
1350         return tcpreamble.str();
1351 }
1352
1353
1354 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1355 {
1356         DocumentClass const & tclass = params_.documentClass();
1357         odocstringstream tcpreamble;
1358
1359         tcpreamble << tclass.htmlpreamble();
1360
1361         list<docstring>::const_iterator cit = usedLayouts_.begin();
1362         list<docstring>::const_iterator end = usedLayouts_.end();
1363         for (; cit != end; ++cit)
1364                 tcpreamble << tclass[*cit].htmlpreamble();
1365
1366         cit = usedInsetLayouts_.begin();
1367         end = usedInsetLayouts_.end();
1368         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1369         for (; cit != end; ++cit) {
1370                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1371                 if (it == ils.end())
1372                         continue;
1373                 tcpreamble << it->second.htmlpreamble();
1374         }
1375
1376         return tcpreamble.str();
1377 }
1378
1379
1380 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1381 {
1382         DocumentClass const & tclass = params_.documentClass();
1383         odocstringstream tcpreamble;
1384
1385         if (mustProvide("noun"))
1386                 tcpreamble << lyxnoun_style;
1387         // this isn't exact, but it won't hurt that much if it
1388         // wasn't for this.
1389         if (mustProvide("ulem"))
1390                 tcpreamble << lyxstrikeout_style;
1391
1392         tcpreamble << tclass.htmlstyles();
1393
1394         list<docstring>::const_iterator cit = usedLayouts_.begin();
1395         list<docstring>::const_iterator end = usedLayouts_.end();
1396         for (; cit != end; ++cit)
1397                 tcpreamble << tclass[*cit].htmlstyle();
1398
1399         cit = usedInsetLayouts_.begin();
1400         end = usedInsetLayouts_.end();
1401         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1402         for (; cit != end; ++cit) {
1403                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1404                 if (it == ils.end())
1405                         continue;
1406                 tcpreamble << it->second.htmlstyle();
1407         }
1408
1409         return tcpreamble.str();
1410 }
1411
1412
1413 namespace {
1414
1415 docstring const getFloatI18nPreamble(docstring const & type,
1416                         docstring const & name, Language const * lang,
1417                         Encoding const & enc, bool const polyglossia)
1418 {
1419         // Check whether name can be encoded in the buffer encoding
1420         bool encodable = true;
1421         for (size_t i = 0; i < name.size(); ++i) {
1422                 if (!enc.encodable(name[i])) {
1423                         encodable = false;
1424                         break;
1425                 }
1426         }
1427
1428         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1429                                                : from_ascii(lang->babel());
1430         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1431         docstring const texenc = from_ascii(lang->encoding()->latexName());
1432         docstring const bufenc = from_ascii(enc.iconvName());
1433         docstring const s1 = docstring(1, 0xF0000);
1434         docstring const s2 = docstring(1, 0xF0001);
1435         docstring const translated = encodable ? name
1436                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1437                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1438
1439         odocstringstream os;
1440         os << "\\addto\\captions" << language
1441            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1442         return os.str();
1443 }
1444
1445
1446 docstring const i18npreamble(docstring const & templ, Language const * lang,
1447                              Encoding const & enc, bool const polyglossia,
1448                              bool const need_fixedwidth)
1449 {
1450         if (templ.empty())
1451                 return templ;
1452
1453         string preamble = polyglossia ?
1454                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1455                 subst(to_utf8(templ), "$$lang", lang->babel());
1456
1457         string const langenc = lang->encoding()->iconvName();
1458         string const texenc = lang->encoding()->latexName();
1459         string const bufenc = enc.iconvName();
1460         Encoding const * testenc(&enc);
1461         bool lang_fallback = false;
1462         bool ascii_fallback = false;
1463         if (need_fixedwidth && !enc.hasFixedWidth()) {
1464                 if (lang->encoding()->hasFixedWidth()) {
1465                         testenc = lang->encoding();
1466                         lang_fallback = true;
1467                 } else {
1468                         // We need a fixed width encoding, but both the buffer
1469                         // encoding and the language encoding are variable
1470                         // width. As a last fallback, try to convert to pure
1471                         // ASCII using the LaTeX commands defined in unicodesymbols.
1472                         testenc = encodings.fromLyXName("ascii");
1473                         if (!testenc)
1474                                 return docstring();
1475                         ascii_fallback = true;
1476                 }
1477         }
1478         // First and second character of plane 15 (Private Use Area)
1479         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1480         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1481         // FIXME UNICODE
1482         // lyx::regex is not unicode-safe.
1483         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1484         static regex const reg("_\\(([^\\)]+)\\)");
1485         smatch sub;
1486         while (regex_search(preamble, sub, reg)) {
1487                 string const key = sub.str(1);
1488                 docstring const name = lang->translateLayout(key);
1489                 // Check whether name can be encoded in the buffer encoding
1490                 bool encodable = true;
1491                 for (size_t i = 0; i < name.size() && encodable; ++i)
1492                         if (!testenc->encodable(name[i]))
1493                                 encodable = false;
1494                 string translated;
1495                 if (encodable && !lang_fallback)
1496                         translated = to_utf8(name);
1497                 else if (ascii_fallback)
1498                         translated = to_ascii(testenc->latexString(name).first);
1499                 else
1500                         translated = "\\inputencoding{" + texenc + "}"
1501                                 + s1 + langenc + s2 + to_utf8(name)
1502                                 + s1 + bufenc + s2;
1503                 preamble = subst(preamble, sub.str(), translated);
1504         }
1505         return from_utf8(preamble);
1506 }
1507
1508 }
1509
1510
1511 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1512 {
1513         DocumentClass const & tclass = params_.documentClass();
1514         // collect preamble snippets in a set to prevent multiple identical
1515         // commands (would happen if e.g. both theorem and theorem* are used)
1516         set<docstring> snippets;
1517         typedef LanguageList::const_iterator lang_it;
1518         lang_it const lbeg = UsedLanguages_.begin();
1519         lang_it const lend =  UsedLanguages_.end();
1520         list<docstring>::const_iterator cit = usedLayouts_.begin();
1521         list<docstring>::const_iterator end = usedLayouts_.end();
1522         for (; cit != end; ++cit) {
1523                 // language dependent commands (once per document)
1524                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1525                                                 buffer().language(),
1526                                                 buffer().params().encoding(),
1527                                                 use_polyglossia, false));
1528                 // commands for language changing (for multilanguage documents)
1529                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1530                         snippets.insert(i18npreamble(
1531                                                 tclass[*cit].babelpreamble(),
1532                                                 buffer().language(),
1533                                                 buffer().params().encoding(),
1534                                                 use_polyglossia, false));
1535                         for (lang_it lit = lbeg; lit != lend; ++lit)
1536                                 snippets.insert(i18npreamble(
1537                                                 tclass[*cit].babelpreamble(),
1538                                                 *lit,
1539                                                 buffer().params().encoding(),
1540                                                 use_polyglossia, false));
1541                 }
1542         }
1543         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1544                 FloatList const & floats = params_.documentClass().floats();
1545                 UsedFloats::const_iterator fit = usedFloats_.begin();
1546                 UsedFloats::const_iterator fend = usedFloats_.end();
1547                 for (; fit != fend; ++fit) {
1548                         Floating const & fl = floats.getType(fit->first);
1549                         // we assume builtin floats are translated
1550                         if (fl.isPredefined())
1551                                 continue;
1552                         docstring const type = from_ascii(fl.floattype());
1553                         docstring const flname = from_utf8(fl.name());
1554                         docstring name = buffer().language()->translateLayout(fl.name());
1555                         // only request translation if we have a real translation
1556                         // (that differs from the source)
1557                         if (flname != name)
1558                                 snippets.insert(getFloatI18nPreamble(
1559                                                 type, name, buffer().language(),
1560                                                 buffer().params().encoding(),
1561                                                 use_polyglossia));
1562                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1563                                 string const code = (*lit)->code();
1564                                 name = (*lit)->translateLayout(fl.name());
1565                                 // we assume we have a suitable translation if
1566                                 // either the language is English (we need to
1567                                 // translate into English if English is a secondary
1568                                 // language) or if translateIfPossible returns
1569                                 // something different to the English source.
1570                                 bool const have_translation =
1571                                         (flname != name || contains(code, "en"));
1572                                 if (have_translation)
1573                                         snippets.insert(getFloatI18nPreamble(
1574                                                 type, name, *lit,
1575                                                 buffer().params().encoding(),
1576                                                 use_polyglossia));
1577                         }
1578                 }
1579         }
1580
1581         cit = usedInsetLayouts_.begin();
1582         end = usedInsetLayouts_.end();
1583         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1584         for (; cit != end; ++cit) {
1585                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1586                 if (it == ils.end())
1587                         continue;
1588                 // The listings package does not work with variable width
1589                 // encodings, only with fixed width encodings. Therefore we
1590                 // need to force a fixed width encoding for
1591                 // \lstlistlistingname and \lstlistingname (bug 9382).
1592                 // This needs to be consistent with InsetListings::latex().
1593                 bool const need_fixedwidth = !runparams_.isFullUnicode() &&
1594                                 it->second.fixedwidthpreambleencoding();
1595                 // language dependent commands (once per document)
1596                 snippets.insert(i18npreamble(it->second.langpreamble(),
1597                                                 buffer().language(),
1598                                                 buffer().params().encoding(),
1599                                                 use_polyglossia, need_fixedwidth));
1600                 // commands for language changing (for multilanguage documents)
1601                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1602                         snippets.insert(i18npreamble(
1603                                                 it->second.babelpreamble(),
1604                                                 buffer().language(),
1605                                                 buffer().params().encoding(),
1606                                                 use_polyglossia, need_fixedwidth));
1607                         for (lang_it lit = lbeg; lit != lend; ++lit)
1608                                 snippets.insert(i18npreamble(
1609                                                 it->second.babelpreamble(),
1610                                                 *lit,
1611                                                 buffer().params().encoding(),
1612                                                 use_polyglossia, need_fixedwidth));
1613                 }
1614         }
1615
1616         odocstringstream tcpreamble;
1617         set<docstring>::const_iterator const send = snippets.end();
1618         set<docstring>::const_iterator it = snippets.begin();
1619         for (; it != send; ++it)
1620                 tcpreamble << *it;
1621         return tcpreamble.str();
1622 }
1623
1624
1625 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1626 {
1627         // Definition of entities used in the document that are LyX related.
1628         odocstringstream entities;
1629
1630         if (mustProvide("lyxarrow")) {
1631                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1632         }
1633
1634         return entities.str();
1635 }
1636
1637
1638 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1639 {
1640         odocstringstream sgmlpreamble;
1641         // FIXME UNICODE
1642         docstring const basename(from_utf8(onlyPath(fname)));
1643
1644         FileMap::const_iterator end = IncludedFiles_.end();
1645         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1646              fi != end; ++fi)
1647                 // FIXME UNICODE
1648                 sgmlpreamble << "\n<!ENTITY " << fi->first
1649                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1650                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1651
1652         return sgmlpreamble.str();
1653 }
1654
1655
1656 void LaTeXFeatures::showStruct() const
1657 {
1658         lyxerr << "LyX needs the following commands when LaTeXing:"
1659                << "\n***** Packages:" << getPackages()
1660                << "\n***** Macros:" << to_utf8(getMacros())
1661                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1662                << "\n***** done." << endl;
1663 }
1664
1665
1666 Buffer const & LaTeXFeatures::buffer() const
1667 {
1668         return *buffer_;
1669 }
1670
1671
1672 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1673 {
1674         buffer_ = &buffer;
1675 }
1676
1677
1678 BufferParams const & LaTeXFeatures::bufferParams() const
1679 {
1680         return params_;
1681 }
1682
1683
1684 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1685 {
1686         FloatList const & floats = params_.documentClass().floats();
1687
1688         // Here we will output the code to create the needed float styles.
1689         // We will try to do this as minimal as possible.
1690         // \floatstyle{ruled}
1691         // \newfloat{algorithm}{htbp}{loa}
1692         // \providecommand{\algorithmname}{Algorithm}
1693         // \floatname{algorithm}{\protect\algorithmname}
1694         UsedFloats::const_iterator cit = usedFloats_.begin();
1695         UsedFloats::const_iterator end = usedFloats_.end();
1696         for (; cit != end; ++cit) {
1697                 Floating const & fl = floats.getType(cit->first);
1698
1699                 // For builtin floats we do nothing.
1700                 if (fl.isPredefined())
1701                         continue;
1702
1703                 // We have to special case "table" and "figure"
1704                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1705                         // Output code to modify "table" or "figure"
1706                         // but only if builtin == false
1707                         // and that have to be true at this point in the
1708                         // function.
1709                         docstring const type = from_ascii(fl.floattype());
1710                         docstring const placement = from_ascii(fl.placement());
1711                         docstring const style = from_ascii(fl.style());
1712                         if (!style.empty()) {
1713                                 os << "\\floatstyle{" << style << "}\n"
1714                                    << "\\restylefloat{" << type << "}\n";
1715                         }
1716                         if (!placement.empty()) {
1717                                 os << "\\floatplacement{" << type << "}{"
1718                                    << placement << "}\n";
1719                         }
1720                 } else {
1721                         // The other non builtin floats.
1722
1723                         docstring const type = from_ascii(fl.floattype());
1724                         docstring const placement = from_ascii(fl.placement());
1725                         docstring const ext = from_ascii(fl.ext());
1726                         docstring const within = from_ascii(fl.within());
1727                         docstring const style = from_ascii(fl.style());
1728                         docstring const name =
1729                                 buffer().language()->translateLayout(fl.name());
1730                         os << "\\floatstyle{" << style << "}\n"
1731                            << "\\newfloat{" << type << "}{" << placement
1732                            << "}{" << ext << '}';
1733                         if (!within.empty())
1734                                 os << '[' << within << ']';
1735                         os << '\n'
1736                            << "\\providecommand{\\" << type << "name}{"
1737                            << name << "}\n"
1738                            << "\\floatname{" << type << "}{\\protect\\"
1739                            << type << "name}\n";
1740
1741                         // What missing here is to code to minimalize the code
1742                         // output so that the same floatstyle will not be
1743                         // used several times, when the same style is still in
1744                         // effect. (Lgb)
1745                 }
1746                 if (cit->second)
1747                         // The subfig package is loaded later
1748                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
1749         }
1750 }
1751
1752
1753 void LaTeXFeatures::resolveAlternatives()
1754 {
1755         for (Features::iterator it = features_.begin(); it != features_.end();) {
1756                 if (contains(*it, '|')) {
1757                         vector<string> const alternatives = getVectorFromString(*it, "|");
1758                         vector<string>::const_iterator const end = alternatives.end();
1759                         vector<string>::const_iterator ita = alternatives.begin();
1760                         // Is any alternative already required? => use that
1761                         for (; ita != end; ++ita) {
1762                                 if (isRequired(*ita))
1763                                         break;
1764                         }
1765                         // Is any alternative available? => use the first one
1766                         // (bug 9498)
1767                         if (ita == end) {
1768                                 for (ita = alternatives.begin(); ita != end; ++ita) {
1769                                         if (isAvailable(*ita)) {
1770                                                 require(*ita);
1771                                                 break;
1772                                         }
1773                                 }
1774                         }
1775                         // This will not work, but not requiring something
1776                         // would be more confusing
1777                         if (ita == end)
1778                                 require(alternatives.front());
1779                         features_.erase(it);
1780                         it = features_.begin();
1781                 } else
1782                         ++it;
1783         }
1784 }
1785
1786
1787 } // namespace lyx