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