]> git.lyx.org Git - features.git/blob - src/BufferParams.cpp
* Add possibility to append active branch names to the output file name (#3105).
[features.git] / src / BufferParams.cpp
1 /**
2  * \file BufferParams.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  * \author André Pönitz
11  * \author Martin Vermeer
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "BufferParams.h"
19
20 #include "Author.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
23 #include "buffer_funcs.h"
24 #include "Bullet.h"
25 #include "Color.h"
26 #include "ColorSet.h"
27 #include "Encoding.h"
28 #include "IndicesList.h"
29 #include "Language.h"
30 #include "LaTeXFeatures.h"
31 #include "ModuleList.h"
32 #include "Font.h"
33 #include "Lexer.h"
34 #include "LyXRC.h"
35 #include "OutputParams.h"
36 #include "Spacing.h"
37 #include "TexRow.h"
38 #include "VSpace.h"
39 #include "PDFOptions.h"
40
41 #include "frontends/alert.h"
42
43 #include "insets/InsetListingsParams.h"
44
45 #include "support/convert.h"
46 #include "support/debug.h"
47 #include "support/docstream.h"
48 #include "support/FileName.h"
49 #include "support/filetools.h"
50 #include "support/gettext.h"
51 #include "support/Messages.h"
52 #include "support/Translator.h"
53 #include "support/lstrings.h"
54
55 #include <algorithm>
56 #include <sstream>
57
58 using namespace std;
59 using namespace lyx::support;
60
61
62 static char const * const string_paragraph_separation[] = {
63         "indent", "skip", ""
64 };
65
66
67 static char const * const string_quotes_language[] = {
68         "english", "swedish", "german", "polish", "french", "danish", ""
69 };
70
71
72 static char const * const string_papersize[] = {
73         "default", "custom", "letterpaper", "legalpaper", "executivepaper",
74         "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
75 };
76
77
78 static char const * const string_orientation[] = {
79         "portrait", "landscape", ""
80 };
81
82
83 static char const * const string_footnotekinds[] = {
84         "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
85 };
86
87
88 static char const * const tex_graphics[] = {
89         "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
90         "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
91         "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
92         "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
93         "xetex", "none", ""
94 };
95
96
97
98 namespace lyx {
99
100 // Local translators
101 namespace {
102
103 // Paragraph separation
104 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
105
106
107 ParSepTranslator const init_parseptranslator()
108 {
109         ParSepTranslator translator
110                 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
111         translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
112         return translator;
113 }
114
115
116 ParSepTranslator const & parseptranslator()
117 {
118         static ParSepTranslator translator = init_parseptranslator();
119         return translator;
120 }
121
122
123 // Quotes language
124 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
125
126
127 QuotesLangTranslator const init_quoteslangtranslator()
128 {
129         QuotesLangTranslator translator
130                 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
131         translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
132         translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
133         translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
134         translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
135         translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
136         return translator;
137 }
138
139
140 QuotesLangTranslator const & quoteslangtranslator()
141 {
142         static QuotesLangTranslator translator = init_quoteslangtranslator();
143         return translator;
144 }
145
146
147 // Paper size
148 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
149
150
151 static PaperSizeTranslator initPaperSizeTranslator()
152 {
153         PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
154         translator.addPair(string_papersize[1], PAPER_CUSTOM);
155         translator.addPair(string_papersize[2], PAPER_USLETTER);
156         translator.addPair(string_papersize[3], PAPER_USLEGAL);
157         translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
158         translator.addPair(string_papersize[5], PAPER_A3);
159         translator.addPair(string_papersize[6], PAPER_A4);
160         translator.addPair(string_papersize[7], PAPER_A5);
161         translator.addPair(string_papersize[8], PAPER_B3);
162         translator.addPair(string_papersize[9], PAPER_B4);
163         translator.addPair(string_papersize[10], PAPER_B5);
164         return translator;
165 }
166
167
168 PaperSizeTranslator const & papersizetranslator()
169 {
170         static PaperSizeTranslator translator = initPaperSizeTranslator();
171         return translator;
172 }
173
174
175 // Paper orientation
176 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
177
178
179 PaperOrientationTranslator const init_paperorientationtranslator()
180 {
181         PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
182         translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
183         return translator;
184 }
185
186
187 PaperOrientationTranslator const & paperorientationtranslator()
188 {
189         static PaperOrientationTranslator translator = init_paperorientationtranslator();
190         return translator;
191 }
192
193
194 // Page sides
195 typedef Translator<int, PageSides> SidesTranslator;
196
197
198 SidesTranslator const init_sidestranslator()
199 {
200         SidesTranslator translator(1, OneSide);
201         translator.addPair(2, TwoSides);
202         return translator;
203 }
204
205
206 SidesTranslator const & sidestranslator()
207 {
208         static SidesTranslator translator = init_sidestranslator();
209         return translator;
210 }
211
212
213 // LaTeX packages
214 typedef Translator<int, BufferParams::Package> PackageTranslator;
215
216
217 PackageTranslator const init_packagetranslator()
218 {
219         PackageTranslator translator(0, BufferParams::package_off);
220         translator.addPair(1, BufferParams::package_auto);
221         translator.addPair(2, BufferParams::package_on);
222         return translator;
223 }
224
225
226 PackageTranslator const & packagetranslator()
227 {
228         static PackageTranslator translator = init_packagetranslator();
229         return translator;
230 }
231
232
233 // Cite engine
234 typedef Translator<string, CiteEngine> CiteEngineTranslator;
235
236
237 CiteEngineTranslator const init_citeenginetranslator()
238 {
239         CiteEngineTranslator translator("basic", ENGINE_BASIC);
240         translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
241         translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
242         translator.addPair("jurabib", ENGINE_JURABIB);
243         return translator;
244 }
245
246
247 CiteEngineTranslator const & citeenginetranslator()
248 {
249         static CiteEngineTranslator translator = init_citeenginetranslator();
250         return translator;
251 }
252
253
254 // Spacing
255 typedef Translator<string, Spacing::Space> SpaceTranslator;
256
257
258 SpaceTranslator const init_spacetranslator()
259 {
260         SpaceTranslator translator("default", Spacing::Default);
261         translator.addPair("single", Spacing::Single);
262         translator.addPair("onehalf", Spacing::Onehalf);
263         translator.addPair("double", Spacing::Double);
264         translator.addPair("other", Spacing::Other);
265         return translator;
266 }
267
268
269 SpaceTranslator const & spacetranslator()
270 {
271         static SpaceTranslator translator = init_spacetranslator();
272         return translator;
273 }
274
275 } // anon namespace
276
277
278 class BufferParams::Impl
279 {
280 public:
281         Impl();
282
283         AuthorList authorlist;
284         BranchList branchlist;
285         Bullet temp_bullets[4];
286         Bullet user_defined_bullets[4];
287         IndicesList indiceslist;
288         Spacing spacing;
289         /** This is the amount of space used for paragraph_separation "skip",
290          * and for detached paragraphs in "indented" documents.
291          */
292         VSpace defskip;
293         PDFOptions pdfoptions;
294         LayoutFileIndex baseClass_;
295 };
296
297
298 BufferParams::Impl::Impl()
299         : defskip(VSpace::MEDSKIP), baseClass_(string(""))
300 {
301         // set initial author
302         // FIXME UNICODE
303         authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
304 }
305
306
307 BufferParams::Impl *
308 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
309 {
310         LASSERT(ptr, /**/);
311
312         return new BufferParams::Impl(*ptr);
313 }
314
315
316 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
317 {
318         delete ptr;
319 }
320
321
322 BufferParams::BufferParams()
323         : pimpl_(new Impl)
324 {
325         setBaseClass(defaultBaseclass());
326         makeDocumentClass();
327         paragraph_separation = ParagraphIndentSeparation;
328         quotes_language = InsetQuotes::EnglishQuotes;
329         fontsize = "default";
330
331         /*  PaperLayout */
332         papersize = PAPER_DEFAULT;
333         orientation = ORIENTATION_PORTRAIT;
334         use_geometry = false;
335         use_amsmath = package_auto;
336         use_esint = package_auto;
337         cite_engine_ = ENGINE_BASIC;
338         use_bibtopic = false;
339         use_indices = false;
340         trackChanges = false;
341         outputChanges = false;
342         use_default_options = true;
343         secnumdepth = 3;
344         tocdepth = 3;
345         language = default_language;
346         fontsRoman = "default";
347         fontsSans = "default";
348         fontsTypewriter = "default";
349         fontsDefaultFamily = "default";
350         useXetex = false;
351         fontsSC = false;
352         fontsOSF = false;
353         fontsSansScale = 100;
354         fontsTypewriterScale = 100;
355         inputenc = "auto";
356         graphicsDriver = "default";
357         defaultOutputFormat = "default";
358         bibtex_command = "default";
359         index_command = "default";
360         sides = OneSide;
361         columns = 1;
362         listings_params = string();
363         pagestyle = "default";
364         // white is equal to no background color
365         backgroundcolor = lyx::rgbFromHexName("#ffffff");
366         compressed = false;
367         for (int iter = 0; iter < 4; ++iter) {
368                 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
369                 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
370         }
371         // default index
372         indiceslist().addDefault(B_("Index"));
373 }
374
375
376 docstring BufferParams::B_(string const & l10n) const
377 {
378         LASSERT(language, /**/);
379         return getMessages(language->code()).get(l10n);
380 }
381
382
383 AuthorList & BufferParams::authors()
384 {
385         return pimpl_->authorlist;
386 }
387
388
389 AuthorList const & BufferParams::authors() const
390 {
391         return pimpl_->authorlist;
392 }
393
394
395 BranchList & BufferParams::branchlist()
396 {
397         return pimpl_->branchlist;
398 }
399
400
401 BranchList const & BufferParams::branchlist() const
402 {
403         return pimpl_->branchlist;
404 }
405
406
407 IndicesList & BufferParams::indiceslist()
408 {
409         return pimpl_->indiceslist;
410 }
411
412
413 IndicesList const & BufferParams::indiceslist() const
414 {
415         return pimpl_->indiceslist;
416 }
417
418
419 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
420 {
421         LASSERT(index < 4, /**/);
422         return pimpl_->temp_bullets[index];
423 }
424
425
426 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
427 {
428         LASSERT(index < 4, /**/);
429         return pimpl_->temp_bullets[index];
430 }
431
432
433 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
434 {
435         LASSERT(index < 4, /**/);
436         return pimpl_->user_defined_bullets[index];
437 }
438
439
440 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
441 {
442         LASSERT(index < 4, /**/);
443         return pimpl_->user_defined_bullets[index];
444 }
445
446
447 Spacing & BufferParams::spacing()
448 {
449         return pimpl_->spacing;
450 }
451
452
453 Spacing const & BufferParams::spacing() const
454 {
455         return pimpl_->spacing;
456 }
457
458
459 PDFOptions & BufferParams::pdfoptions()
460 {
461         return pimpl_->pdfoptions;
462 }
463
464
465 PDFOptions const & BufferParams::pdfoptions() const
466 {
467         return pimpl_->pdfoptions;
468 }
469
470
471 VSpace const & BufferParams::getDefSkip() const
472 {
473         return pimpl_->defskip;
474 }
475
476
477 void BufferParams::setDefSkip(VSpace const & vs)
478 {
479         pimpl_->defskip = vs;
480 }
481
482
483 string BufferParams::readToken(Lexer & lex, string const & token,
484         FileName const & filepath)
485 {
486         if (token == "\\textclass") {
487                 lex.next();
488                 string const classname = lex.getString();
489                 // if there exists a local layout file, ignore the system one
490                 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
491                 string tcp;
492                 LayoutFileList & bcl = LayoutFileList::get();
493                 if (tcp.empty() && !filepath.empty())
494                         tcp = bcl.addLocalLayout(classname, filepath.absFilename());
495                 if (!tcp.empty())
496                         setBaseClass(tcp);
497                 else
498                         setBaseClass(classname);
499                 // We assume that a tex class exists for local or unknown layouts so this warning
500                 // will only be given for system layouts.
501                 if (!baseClass()->isTeXClassAvailable()) {
502                         docstring const msg =
503                                 bformat(_("The layout file requested by this document,\n"
504                                                  "%1$s.layout,\n"
505                                                  "is not usable. This is probably because a LaTeX\n"
506                                                  "class or style file required by it is not\n"
507                                                  "available. See the Customization documentation\n"
508                                                  "for more information.\n"), from_utf8(classname));
509                         frontend::Alert::warning(_("Document class not available"),
510                                        msg + _("LyX will not be able to produce output."));
511                 } 
512         } else if (token == "\\begin_preamble") {
513                 readPreamble(lex);
514         } else if (token == "\\begin_local_layout") {
515                 readLocalLayout(lex);
516         } else if (token == "\\begin_modules") {
517                 readModules(lex);
518         } else if (token == "\\begin_removed_modules") {
519                 readRemovedModules(lex);
520         } else if (token == "\\options") {
521                 lex.eatLine();
522                 options = lex.getString();
523         } else if (token == "\\use_default_options") {
524                 lex >> use_default_options;
525         } else if (token == "\\master") {
526                 lex.eatLine();
527                 master = lex.getString();
528         } else if (token == "\\language") {
529                 readLanguage(lex);
530         } else if (token == "\\inputencoding") {
531                 lex >> inputenc;
532         } else if (token == "\\graphics") {
533                 readGraphicsDriver(lex);
534         } else if (token == "\\default_output_format") {
535                 lex >> defaultOutputFormat;
536         } else if (token == "\\bibtex_command") {
537                 lex.eatLine();
538                 bibtex_command = lex.getString();
539         } else if (token == "\\index_command") {
540                 lex.eatLine();
541                 index_command = lex.getString();
542         } else if (token == "\\font_roman") {
543                 lex.eatLine();
544                 fontsRoman = lex.getString();
545         } else if (token == "\\font_sans") {
546                 lex.eatLine();
547                 fontsSans = lex.getString();
548         } else if (token == "\\font_typewriter") {
549                 lex.eatLine();
550                 fontsTypewriter = lex.getString();
551         } else if (token == "\\font_default_family") {
552                 lex >> fontsDefaultFamily;
553         } else if (token == "\\use_xetex") {
554                 lex >> useXetex;
555         } else if (token == "\\font_sc") {
556                 lex >> fontsSC;
557         } else if (token == "\\font_osf") {
558                 lex >> fontsOSF;
559         } else if (token == "\\font_sf_scale") {
560                 lex >> fontsSansScale;
561         } else if (token == "\\font_tt_scale") {
562                 lex >> fontsTypewriterScale;
563         } else if (token == "\\font_cjk") {
564                 lex >> fontsCJK;
565         } else if (token == "\\paragraph_separation") {
566                 string parsep;
567                 lex >> parsep;
568                 paragraph_separation = parseptranslator().find(parsep);
569         } else if (token == "\\defskip") {
570                 lex.next();
571                 string defskip = lex.getString();
572                 if (defskip == "defskip")
573                         // this is invalid
574                         defskip = "medskip";
575                 pimpl_->defskip = VSpace(defskip);
576         } else if (token == "\\quotes_language") {
577                 string quotes_lang;
578                 lex >> quotes_lang;
579                 quotes_language = quoteslangtranslator().find(quotes_lang);
580         } else if (token == "\\papersize") {
581                 string ppsize;
582                 lex >> ppsize;
583                 papersize = papersizetranslator().find(ppsize);
584         } else if (token == "\\use_geometry") {
585                 lex >> use_geometry;
586         } else if (token == "\\use_amsmath") {
587                 int use_ams;
588                 lex >> use_ams;
589                 use_amsmath = packagetranslator().find(use_ams);
590         } else if (token == "\\use_esint") {
591                 int useesint;
592                 lex >> useesint;
593                 use_esint = packagetranslator().find(useesint);
594         } else if (token == "\\cite_engine") {
595                 string engine;
596                 lex >> engine;
597                 cite_engine_ = citeenginetranslator().find(engine);
598         } else if (token == "\\use_bibtopic") {
599                 lex >> use_bibtopic;
600         } else if (token == "\\use_indices") {
601                 lex >> use_indices;
602         } else if (token == "\\tracking_changes") {
603                 lex >> trackChanges;
604         } else if (token == "\\output_changes") {
605                 lex >> outputChanges;
606         } else if (token == "\\branch") {
607                 lex.eatLine();
608                 docstring branch = lex.getDocString();
609                 branchlist().add(branch);
610                 while (true) {
611                         lex.next();
612                         string const tok = lex.getString();
613                         if (tok == "\\end_branch")
614                                 break;
615                         Branch * branch_ptr = branchlist().find(branch);
616                         if (tok == "\\selected") {
617                                 lex.next();
618                                 if (branch_ptr)
619                                         branch_ptr->setSelected(lex.getInteger());
620                         }
621                         if (tok == "\\filename_suffix") {
622                                 lex.next();
623                                 if (branch_ptr)
624                                         branch_ptr->setFilenameSuffix(lex.getInteger());
625                         }
626                         // not yet operational
627                         if (tok == "\\color") {
628                                 lex.eatLine();
629                                 string color = lex.getString();
630                                 if (branch_ptr)
631                                         branch_ptr->setColor(color);
632                                 // Update also the Color table:
633                                 if (color == "none")
634                                         color = lcolor.getX11Name(Color_background);
635                                 // FIXME UNICODE
636                                 lcolor.setColor(to_utf8(branch), color);
637                         }
638                 }
639         } else if (token == "\\index") {
640                 lex.eatLine();
641                 docstring index = lex.getDocString();
642                 indiceslist().add(index);
643                 while (true) {
644                         lex.next();
645                         string const tok = lex.getString();
646                         if (tok == "\\end_index")
647                                 break;
648                         Index * index_ptr = indiceslist().find(index);
649                         if (tok == "\\shortcut") {
650                                 lex.next();
651                                 if (index_ptr)
652                                         index_ptr->setShortcut(lex.getDocString());
653                         }
654                         // not yet operational
655                         if (tok == "\\color") {
656                                 lex.eatLine();
657                                 string color = lex.getString();
658                                 if (index_ptr)
659                                         index_ptr->setColor(color);
660                                 // Update also the Color table:
661                                 if (color == "none")
662                                         color = lcolor.getX11Name(Color_background);
663                                 // FIXME UNICODE
664                                 lcolor.setColor(to_utf8(index), color);
665                         }
666                 }
667         } else if (token == "\\author") {
668                 lex.eatLine();
669                 istringstream ss(lex.getString());
670                 Author a;
671                 ss >> a;
672                 author_map.push_back(pimpl_->authorlist.record(a));
673         } else if (token == "\\paperorientation") {
674                 string orient;
675                 lex >> orient;
676                 orientation = paperorientationtranslator().find(orient);
677         } else if (token == "\\backgroundcolor") {
678                 lex.eatLine();
679                 backgroundcolor = lyx::rgbFromHexName(lex.getString());
680         } else if (token == "\\paperwidth") {
681                 lex >> paperwidth;
682         } else if (token == "\\paperheight") {
683                 lex >> paperheight;
684         } else if (token == "\\leftmargin") {
685                 lex >> leftmargin;
686         } else if (token == "\\topmargin") {
687                 lex >> topmargin;
688         } else if (token == "\\rightmargin") {
689                 lex >> rightmargin;
690         } else if (token == "\\bottommargin") {
691                 lex >> bottommargin;
692         } else if (token == "\\headheight") {
693                 lex >> headheight;
694         } else if (token == "\\headsep") {
695                 lex >> headsep;
696         } else if (token == "\\footskip") {
697                 lex >> footskip;
698         } else if (token == "\\columnsep") {
699                 lex >> columnsep;
700         } else if (token == "\\paperfontsize") {
701                 lex >> fontsize;
702         } else if (token == "\\papercolumns") {
703                 lex >> columns;
704         } else if (token == "\\listings_params") {
705                 string par;
706                 lex >> par;
707                 listings_params = InsetListingsParams(par).params();
708         } else if (token == "\\papersides") {
709                 int psides;
710                 lex >> psides;
711                 sides = sidestranslator().find(psides);
712         } else if (token == "\\paperpagestyle") {
713                 lex >> pagestyle;
714         } else if (token == "\\bullet") {
715                 readBullets(lex);
716         } else if (token == "\\bulletLaTeX") {
717                 readBulletsLaTeX(lex);
718         } else if (token == "\\secnumdepth") {
719                 lex >> secnumdepth;
720         } else if (token == "\\tocdepth") {
721                 lex >> tocdepth;
722         } else if (token == "\\spacing") {
723                 string nspacing;
724                 lex >> nspacing;
725                 string tmp_val;
726                 if (nspacing == "other") {
727                         lex >> tmp_val;
728                 }
729                 spacing().set(spacetranslator().find(nspacing), tmp_val);
730         } else if (token == "\\float_placement") {
731                 lex >> float_placement;
732
733         } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
734                 string toktmp = pdfoptions().readToken(lex, token);
735                 if (!toktmp.empty()) {
736                         lyxerr << "PDFOptions::readToken(): Unknown token: " <<
737                                 toktmp << endl;
738                         return toktmp;
739                 }
740         } else {
741                 lyxerr << "BufferParams::readToken(): Unknown token: " << 
742                         token << endl;
743                 return token;
744         }
745
746         return string();
747 }
748
749
750 void BufferParams::writeFile(ostream & os) const
751 {
752         // The top of the file is written by the buffer.
753         // Prints out the buffer info into the .lyx file given by file
754
755         // the textclass
756         os << "\\textclass " << baseClass()->name() << '\n';
757
758         // then the preamble
759         if (!preamble.empty()) {
760                 // remove '\n' from the end of preamble
761                 string const tmppreamble = rtrim(preamble, "\n");
762                 os << "\\begin_preamble\n"
763                    << tmppreamble
764                    << "\n\\end_preamble\n";
765         }
766
767         // the options
768         if (!options.empty()) {
769                 os << "\\options " << options << '\n';
770         }
771
772         // use the class options defined in the layout?
773         os << "\\use_default_options " 
774            << convert<string>(use_default_options) << "\n";
775
776         // the master document
777         if (!master.empty()) {
778                 os << "\\master " << master << '\n';
779         }
780         
781         // removed modules
782         if (!removedModules_.empty()) {
783                 os << "\\begin_removed_modules" << '\n';
784                 list<string>::const_iterator it = removedModules_.begin();
785                 list<string>::const_iterator en = removedModules_.end();
786                 for (; it != en; it++)
787                         os << *it << '\n';
788                 os << "\\end_removed_modules" << '\n';
789         }
790
791         // the modules
792         if (!layoutModules_.empty()) {
793                 os << "\\begin_modules" << '\n';
794                 LayoutModuleList::const_iterator it = layoutModules_.begin();
795                 LayoutModuleList::const_iterator en = layoutModules_.end();
796                 for (; it != en; it++)
797                         os << *it << '\n';
798                 os << "\\end_modules" << '\n';
799         }
800         
801         // local layout information
802         if (!local_layout.empty()) {
803                 // remove '\n' from the end 
804                 string const tmplocal = rtrim(local_layout, "\n");
805                 os << "\\begin_local_layout\n"
806                    << tmplocal
807                    << "\n\\end_local_layout\n";
808         }
809
810         // then the text parameters
811         if (language != ignore_language)
812                 os << "\\language " << language->lang() << '\n';
813         os << "\\inputencoding " << inputenc
814            << "\n\\font_roman " << fontsRoman
815            << "\n\\font_sans " << fontsSans
816            << "\n\\font_typewriter " << fontsTypewriter
817            << "\n\\font_default_family " << fontsDefaultFamily
818            << "\n\\use_xetex " << convert<string>(useXetex)
819            << "\n\\font_sc " << convert<string>(fontsSC)
820            << "\n\\font_osf " << convert<string>(fontsOSF)
821            << "\n\\font_sf_scale " << fontsSansScale
822            << "\n\\font_tt_scale " << fontsTypewriterScale
823            << '\n';
824         if (!fontsCJK.empty()) {
825                 os << "\\font_cjk " << fontsCJK << '\n';
826         }
827         os << "\n\\graphics " << graphicsDriver << '\n';
828         os << "\\default_output_format " << defaultOutputFormat << '\n';
829         os << "\\bibtex_command " << bibtex_command << '\n';
830         os << "\\index_command " << index_command << '\n';
831
832         if (!float_placement.empty()) {
833                 os << "\\float_placement " << float_placement << '\n';
834         }
835         os << "\\paperfontsize " << fontsize << '\n';
836
837         spacing().writeFile(os);
838         pdfoptions().writeFile(os);
839
840         os << "\\papersize " << string_papersize[papersize]
841            << "\n\\use_geometry " << convert<string>(use_geometry)
842            << "\n\\use_amsmath " << use_amsmath
843            << "\n\\use_esint " << use_esint
844            << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
845            << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
846            << "\n\\use_indices " << convert<string>(use_indices)
847            << "\n\\paperorientation " << string_orientation[orientation]
848            << '\n';
849            if (backgroundcolor != lyx::rgbFromHexName("#ffffff"))
850                 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
851
852         BranchList::const_iterator it = branchlist().begin();
853         BranchList::const_iterator end = branchlist().end();
854         for (; it != end; ++it) {
855                 os << "\\branch " << to_utf8(it->branch())
856                    << "\n\\selected " << it->isSelected()
857                    << "\n\\filename_suffix " << it->hasFilenameSuffix()
858                    << "\n\\color " << lyx::X11hexname(it->color())
859                    << "\n\\end_branch"
860                    << "\n";
861         }
862
863         IndicesList::const_iterator iit = indiceslist().begin();
864         IndicesList::const_iterator iend = indiceslist().end();
865         for (; iit != iend; ++iit) {
866                 os << "\\index " << to_utf8(iit->index())
867                    << "\n\\shortcut " << to_utf8(iit->shortcut())
868                    << "\n\\color " << lyx::X11hexname(iit->color())
869                    << "\n\\end_index"
870                    << "\n";
871         }
872
873         if (!paperwidth.empty())
874                 os << "\\paperwidth "
875                    << VSpace(paperwidth).asLyXCommand() << '\n';
876         if (!paperheight.empty())
877                 os << "\\paperheight "
878                    << VSpace(paperheight).asLyXCommand() << '\n';
879         if (!leftmargin.empty())
880                 os << "\\leftmargin "
881                    << VSpace(leftmargin).asLyXCommand() << '\n';
882         if (!topmargin.empty())
883                 os << "\\topmargin "
884                    << VSpace(topmargin).asLyXCommand() << '\n';
885         if (!rightmargin.empty())
886                 os << "\\rightmargin "
887                    << VSpace(rightmargin).asLyXCommand() << '\n';
888         if (!bottommargin.empty())
889                 os << "\\bottommargin "
890                    << VSpace(bottommargin).asLyXCommand() << '\n';
891         if (!headheight.empty())
892                 os << "\\headheight "
893                    << VSpace(headheight).asLyXCommand() << '\n';
894         if (!headsep.empty())
895                 os << "\\headsep "
896                    << VSpace(headsep).asLyXCommand() << '\n';
897         if (!footskip.empty())
898                 os << "\\footskip "
899                    << VSpace(footskip).asLyXCommand() << '\n';
900         if (!columnsep.empty())
901                 os << "\\columnsep " 
902                          << VSpace(columnsep).asLyXCommand() << '\n';
903         os << "\\secnumdepth " << secnumdepth
904            << "\n\\tocdepth " << tocdepth
905            << "\n\\paragraph_separation "
906            << string_paragraph_separation[paragraph_separation]
907            << "\n\\defskip " << getDefSkip().asLyXCommand()
908            << "\n\\quotes_language "
909            << string_quotes_language[quotes_language]
910            << "\n\\papercolumns " << columns
911            << "\n\\papersides " << sides
912            << "\n\\paperpagestyle " << pagestyle << '\n';
913         if (!listings_params.empty())
914                 os << "\\listings_params \"" <<
915                         InsetListingsParams(listings_params).encodedString() << "\"\n";
916         for (int i = 0; i < 4; ++i) {
917                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
918                         if (user_defined_bullet(i).getFont() != -1) {
919                                 os << "\\bullet " << i << " "
920                                    << user_defined_bullet(i).getFont() << " "
921                                    << user_defined_bullet(i).getCharacter() << " "
922                                    << user_defined_bullet(i).getSize() << "\n";
923                         }
924                         else {
925                                 // FIXME UNICODE
926                                 os << "\\bulletLaTeX " << i << " \""
927                                    << lyx::to_ascii(user_defined_bullet(i).getText())
928                                    << "\"\n";
929                         }
930                 }
931         }
932
933         os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
934         os << "\\output_changes " << convert<string>(outputChanges) << "\n";
935
936         AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
937         AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
938         for (; a_it != a_end; ++a_it) {
939                 if (a_it->second.used())
940                         os << "\\author " << a_it->second << "\n";
941                 else
942                         os << "\\author " << Author() << "\n";
943         }
944 }
945
946
947 void BufferParams::validate(LaTeXFeatures & features) const
948 {
949         features.require(documentClass().requires());
950
951         if (outputChanges) {
952                 bool dvipost    = LaTeXFeatures::isAvailable("dvipost");
953                 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
954                                   LaTeXFeatures::isAvailable("xcolor");
955
956                 switch (features.runparams().flavor) {
957                 case OutputParams::LATEX:
958                         if (dvipost) {
959                                 features.require("ct-dvipost");
960                                 features.require("dvipost");
961                         } else if (xcolorulem) {
962                                 features.require("ct-xcolor-ulem");
963                                 features.require("ulem");
964                                 features.require("xcolor");
965                         } else {
966                                 features.require("ct-none");
967                         }
968                         break;
969                 case OutputParams::PDFLATEX:
970                 case OutputParams::XETEX:
971                         if (xcolorulem) {
972                                 features.require("ct-xcolor-ulem");
973                                 features.require("ulem");
974                                 features.require("xcolor");
975                                 // improves color handling in PDF output
976                                 features.require("pdfcolmk"); 
977                         } else {
978                                 features.require("ct-none");
979                         }
980                         break;
981                 default:
982                         break;
983                 }
984         }
985
986         // Floats with 'Here definitely' as default setting.
987         if (float_placement.find('H') != string::npos)
988                 features.require("float");
989
990         // AMS Style is at document level
991         if (use_amsmath == package_on
992             || documentClass().provides("amsmath"))
993                 features.require("amsmath");
994         if (use_esint == package_on)
995                 features.require("esint");
996
997         // Document-level line spacing
998         if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
999                 features.require("setspace");
1000
1001         // the bullet shapes are buffer level not paragraph level
1002         // so they are tested here
1003         for (int i = 0; i < 4; ++i) {
1004                 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i]) 
1005                         continue;
1006                 int const font = user_defined_bullet(i).getFont();
1007                 if (font == 0) {
1008                         int const c = user_defined_bullet(i).getCharacter();
1009                         if (c == 16
1010                             || c == 17
1011                             || c == 25
1012                             || c == 26
1013                             || c == 31) {
1014                                 features.require("latexsym");
1015                         }
1016                 } else if (font == 1) {
1017                         features.require("amssymb");
1018                 } else if (font >= 2 && font <= 5) {
1019                         features.require("pifont");
1020                 }
1021         }
1022
1023         if (pdfoptions().use_hyperref) {
1024                 features.require("hyperref");
1025                 // due to interferences with babel and hyperref, the color package has to
1026                 // be loaded after hyperref when hyperref is used with the colorlinks
1027                 // option, see http://bugzilla.lyx.org/show_bug.cgi?id=5291
1028                 if (pdfoptions().colorlinks)
1029                         features.require("color");
1030         }
1031
1032         if (useXetex)
1033                 features.require("xetex");
1034
1035         if (language->lang() == "vietnamese")
1036                 features.require("vietnamese");
1037         else if (language->lang() == "japanese")
1038                 features.require("japanese");
1039 }
1040
1041
1042 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
1043                               TexRow & texrow) const
1044 {
1045         os << "\\documentclass";
1046
1047         DocumentClass const & tclass = documentClass();
1048
1049         ostringstream clsoptions; // the document class options.
1050
1051         if (tokenPos(tclass.opt_fontsize(),
1052                      '|', fontsize) >= 0) {
1053                 // only write if existing in list (and not default)
1054                 clsoptions << fontsize << "pt,";
1055         }
1056
1057         // custom, A3, B3 and B4 paper sizes need geometry
1058         bool nonstandard_papersize = papersize == PAPER_B3
1059                 || papersize == PAPER_B4
1060                 || papersize == PAPER_A3
1061                 || papersize == PAPER_CUSTOM;
1062
1063         if (!use_geometry) {
1064                 switch (papersize) {
1065                 case PAPER_A4:
1066                         clsoptions << "a4paper,";
1067                         break;
1068                 case PAPER_USLETTER:
1069                         clsoptions << "letterpaper,";
1070                         break;
1071                 case PAPER_A5:
1072                         clsoptions << "a5paper,";
1073                         break;
1074                 case PAPER_B5:
1075                         clsoptions << "b5paper,";
1076                         break;
1077                 case PAPER_USEXECUTIVE:
1078                         clsoptions << "executivepaper,";
1079                         break;
1080                 case PAPER_USLEGAL:
1081                         clsoptions << "legalpaper,";
1082                         break;
1083                 case PAPER_DEFAULT:
1084                 case PAPER_A3:
1085                 case PAPER_B3:
1086                 case PAPER_B4:
1087                 case PAPER_CUSTOM:
1088                         break;
1089                 }
1090         }
1091
1092         // if needed
1093         if (sides != tclass.sides()) {
1094                 switch (sides) {
1095                 case OneSide:
1096                         clsoptions << "oneside,";
1097                         break;
1098                 case TwoSides:
1099                         clsoptions << "twoside,";
1100                         break;
1101                 }
1102         }
1103
1104         // if needed
1105         if (columns != tclass.columns()) {
1106                 if (columns == 2)
1107                         clsoptions << "twocolumn,";
1108                 else
1109                         clsoptions << "onecolumn,";
1110         }
1111
1112         if (!use_geometry
1113             && orientation == ORIENTATION_LANDSCAPE)
1114                 clsoptions << "landscape,";
1115
1116         // language should be a parameter to \documentclass
1117         if (language->babel() == "hebrew"
1118             && default_language->babel() != "hebrew")
1119                 // This seems necessary
1120                 features.useLanguage(default_language);
1121
1122         ostringstream language_options;
1123         bool const use_babel = features.useBabel();
1124         if (use_babel) {
1125                 language_options << features.getLanguages();
1126                 if (!language->babel().empty()) {
1127                         if (!language_options.str().empty())
1128                                 language_options << ',';
1129                         language_options << language->babel();
1130                 }
1131                 // if Vietnamese is used, babel must directly be loaded
1132                 // with language options, not in the class options, see
1133                 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1134                 size_t viet = language_options.str().find("vietnam");
1135                 // viet = string::npos when not found
1136                 // the same is for all other languages that are not directly supported by
1137                 // babel, but where LaTeX-packages add babel support.
1138                 // this is currently the case for Latvian, Lithuanian, and Mongolian
1139                 size_t latvian = language_options.str().find("latvian");
1140                 size_t lithu = language_options.str().find("lithuanian");
1141                 size_t mongo = language_options.str().find("mongolian");
1142                 // if Japanese is used, babel must directly be loaded
1143                 // with language options, not in the class options, see
1144                 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1145                 size_t japan = language_options.str().find("japanese");
1146                 if (lyxrc.language_global_options && !language_options.str().empty()
1147                         && viet == string::npos && japan == string::npos
1148                         && latvian == string::npos && lithu == string::npos
1149                         && mongo == string::npos)
1150                         clsoptions << language_options.str() << ',';
1151         }
1152
1153         // the predefined options from the layout
1154         if (use_default_options && !tclass.options().empty())
1155                 clsoptions << tclass.options() << ',';
1156
1157         // the user-defined options
1158         if (!options.empty()) {
1159                 clsoptions << options << ',';
1160         }
1161
1162         string strOptions(clsoptions.str());
1163         if (!strOptions.empty()) {
1164                 strOptions = rtrim(strOptions, ",");
1165                 // FIXME UNICODE
1166                 os << '[' << from_utf8(strOptions) << ']';
1167         }
1168
1169         os << '{' << from_ascii(tclass.latexname()) << "}\n";
1170         texrow.newline();
1171         // end of \documentclass defs
1172
1173         if (useXetex) {
1174                 os << "\\usepackage{fontspec}\n";
1175                 texrow.newline();
1176         }
1177
1178         // font selection must be done before loading fontenc.sty
1179         string const fonts =
1180                 loadFonts(fontsRoman, fontsSans,
1181                           fontsTypewriter, fontsSC, fontsOSF,
1182                           fontsSansScale, fontsTypewriterScale, useXetex);
1183         if (!fonts.empty()) {
1184                 os << from_ascii(fonts);
1185                 texrow.newline();
1186         }
1187         if (fontsDefaultFamily != "default")
1188                 os << "\\renewcommand{\\familydefault}{\\"
1189                    << from_ascii(fontsDefaultFamily) << "}\n";
1190
1191         // set font encoding
1192         // this one is not per buffer
1193         // for arabic_arabi and farsi we also need to load the LAE and
1194         // LFE encoding
1195         // XeTeX works without fontenc
1196         if (lyxrc.fontenc != "default" && language->lang() != "japanese"
1197             && !useXetex) {
1198                 if (language->lang() == "arabic_arabi"
1199                     || language->lang() == "farsi") {
1200                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1201                            << ",LFE,LAE]{fontenc}\n";
1202                         texrow.newline();
1203                 } else {
1204                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1205                            << "]{fontenc}\n";
1206                         texrow.newline();
1207                 }
1208         }
1209
1210         // handle inputenc etc.
1211         writeEncodingPreamble(os, features, texrow);
1212
1213         if (!listings_params.empty() || features.isRequired("listings")) {
1214                 os << "\\usepackage{listings}\n";
1215                 texrow.newline();
1216         }
1217         if (!listings_params.empty()) {
1218                 os << "\\lstset{";
1219                 // do not test validity because listings_params is 
1220                 // supposed to be valid
1221                 string par =
1222                         InsetListingsParams(listings_params).separatedParams(true);
1223                 // we can't support all packages, but we should load the color package
1224                 if (par.find("\\color", 0) != string::npos)
1225                         features.require("color");
1226                 os << from_utf8(par);
1227                 // count the number of newlines
1228                 for (size_t i = 0; i < par.size(); ++i)
1229                         if (par[i] == '\n')
1230                                 texrow.newline();
1231                 os << "}\n";
1232                 texrow.newline();
1233         }
1234         if (!tclass.provides("geometry")
1235             && (use_geometry || nonstandard_papersize)) {
1236                 odocstringstream ods;
1237                 if (!getGraphicsDriver("geometry").empty())
1238                         ods << getGraphicsDriver("geometry");
1239                 if (orientation == ORIENTATION_LANDSCAPE)
1240                         ods << ",landscape";
1241                 switch (papersize) {
1242                 case PAPER_CUSTOM:
1243                         if (!paperwidth.empty())
1244                                 ods << ",paperwidth="
1245                                    << from_ascii(paperwidth);
1246                         if (!paperheight.empty())
1247                                 ods << ",paperheight="
1248                                    << from_ascii(paperheight);
1249                         break;
1250                 case PAPER_USLETTER:
1251                         ods << ",letterpaper";
1252                         break;
1253                 case PAPER_USLEGAL:
1254                         ods << ",legalpaper";
1255                         break;
1256                 case PAPER_USEXECUTIVE:
1257                         ods << ",executivepaper";
1258                         break;
1259                 case PAPER_A3:
1260                         ods << ",a3paper";
1261                         break;
1262                 case PAPER_A4:
1263                         ods << ",a4paper";
1264                         break;
1265                 case PAPER_A5:
1266                         ods << ",a5paper";
1267                         break;
1268                 case PAPER_B3:
1269                         ods << ",b3paper";
1270                         break;
1271                 case PAPER_B4:
1272                         ods << ",b4paper";
1273                         break;
1274                 case PAPER_B5:
1275                         ods << ",b5paper";
1276                         break;
1277                 default:
1278                         // default papersize ie PAPER_DEFAULT
1279                         switch (lyxrc.default_papersize) {
1280                         case PAPER_DEFAULT: // keep compiler happy
1281                         case PAPER_USLETTER:
1282                                 ods << ",letterpaper";
1283                                 break;
1284                         case PAPER_USLEGAL:
1285                                 ods << ",legalpaper";
1286                                 break;
1287                         case PAPER_USEXECUTIVE:
1288                                 ods << ",executivepaper";
1289                                 break;
1290                         case PAPER_A3:
1291                                 ods << ",a3paper";
1292                                 break;
1293                         case PAPER_A4:
1294                                 ods << ",a4paper";
1295                                 break;
1296                         case PAPER_A5:
1297                                 ods << ",a5paper";
1298                                 break;
1299                         case PAPER_B5:
1300                                 ods << ",b5paper";
1301                                 break;
1302                         case PAPER_B3:
1303                         case PAPER_B4:
1304                         case PAPER_CUSTOM:
1305                                 break;
1306                         }
1307                 }
1308                 docstring const g_options = trim(ods.str(), ",");
1309                 os << "\\usepackage";
1310                 if (!g_options.empty())
1311                         os << '[' << g_options << ']';
1312                 os << "{geometry}\n";
1313                 texrow.newline();
1314                 os << "\\geometry{verbose";
1315                 if (!topmargin.empty())
1316                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1317                 if (!bottommargin.empty())
1318                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1319                 if (!leftmargin.empty())
1320                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1321                 if (!rightmargin.empty())
1322                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1323                 if (!headheight.empty())
1324                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1325                 if (!headsep.empty())
1326                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1327                 if (!footskip.empty())
1328                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1329                 if (!columnsep.empty())
1330                         os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1331                 os << "}\n";
1332                 texrow.newline();
1333         } else if (orientation == ORIENTATION_LANDSCAPE) {
1334                 features.require("papersize");
1335         }
1336
1337         if (tokenPos(tclass.opt_pagestyle(),
1338                      '|', pagestyle) >= 0) {
1339                 if (pagestyle == "fancy") {
1340                         os << "\\usepackage{fancyhdr}\n";
1341                         texrow.newline();
1342                 }
1343                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1344                 texrow.newline();
1345         }
1346
1347         // only output when the background color is not white
1348         if (backgroundcolor != lyx::rgbFromHexName("#ffffff")) {
1349                 // only require color here, the background color will be defined
1350                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1351                 // package pdfpages 
1352                 features.require("color");
1353                 features.require("pagecolor");
1354         }
1355
1356         // Only if class has a ToC hierarchy
1357         if (tclass.hasTocLevels()) {
1358                 if (secnumdepth != tclass.secnumdepth()) {
1359                         os << "\\setcounter{secnumdepth}{"
1360                            << secnumdepth
1361                            << "}\n";
1362                         texrow.newline();
1363                 }
1364                 if (tocdepth != tclass.tocdepth()) {
1365                         os << "\\setcounter{tocdepth}{"
1366                            << tocdepth
1367                            << "}\n";
1368                         texrow.newline();
1369                 }
1370         }
1371
1372         if (paragraph_separation) {
1373                 switch (getDefSkip().kind()) {
1374                 case VSpace::SMALLSKIP:
1375                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1376                         break;
1377                 case VSpace::MEDSKIP:
1378                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1379                         break;
1380                 case VSpace::BIGSKIP:
1381                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1382                         break;
1383                 case VSpace::LENGTH:
1384                         os << "\\setlength{\\parskip}{"
1385                            << from_utf8(getDefSkip().length().asLatexString())
1386                            << "}\n";
1387                         break;
1388                 default: // should never happen // Then delete it.
1389                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1390                         break;
1391                 }
1392                 texrow.newline();
1393
1394                 os << "\\setlength{\\parindent}{0pt}\n";
1395                 texrow.newline();
1396         }
1397
1398         // Now insert the LyX specific LaTeX commands...
1399         docstring lyxpreamble;
1400
1401         // due to interferences with babel and hyperref, the color package has to
1402         // be loaded (when it is not already loaded) before babel when hyperref
1403         // is used with the colorlinks option, see
1404         // http://bugzilla.lyx.org/show_bug.cgi?id=5291
1405         // we decided therefore to load color always before babel, see
1406         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1407         lyxpreamble += from_ascii(features.getColorOptions());
1408         
1409         // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1410         if (use_babel
1411                 && (features.isRequired("jurabib")
1412                         || features.isRequired("hyperref")
1413                         || features.isRequired("vietnamese")
1414                         || features.isRequired("japanese") ) ) {
1415                                 // FIXME UNICODE
1416                                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1417                                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1418         }
1419
1420         // The optional packages;
1421         lyxpreamble += from_ascii(features.getPackages());
1422
1423         // Additional Indices
1424         if (features.isRequired("splitidx")) {
1425                 IndicesList::const_iterator iit = indiceslist().begin();
1426                 IndicesList::const_iterator iend = indiceslist().end();
1427                 for (; iit != iend; ++iit) {
1428                         lyxpreamble += "\\newindex[";
1429                         lyxpreamble += iit->index();
1430                         lyxpreamble += "]{";
1431                         lyxpreamble += iit->shortcut();
1432                         lyxpreamble += "}\n";
1433                 }
1434         }
1435
1436         // Line spacing
1437         lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1438
1439         // PDF support.
1440         // * Hyperref manual: "Make sure it comes last of your loaded
1441         //   packages, to give it a fighting chance of not being over-written,
1442         //   since its job is to redefine many LaTeX commands."
1443         // * Email from Heiko Oberdiek: "It is usually better to load babel
1444         //   before hyperref. Then hyperref has a chance to detect babel.
1445         // * Has to be loaded before the "LyX specific LaTeX commands" to
1446         //   avoid errors with algorithm floats.
1447         // use hyperref explicitely when it is required
1448         if (features.isRequired("hyperref")) {
1449                 odocstringstream oss;
1450                 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1451                 lyxpreamble += oss.str();
1452         }
1453         
1454         // Will be surrounded by \makeatletter and \makeatother when not empty
1455         docstring atlyxpreamble;
1456
1457         // Some macros LyX will need
1458         docstring tmppreamble(features.getMacros());
1459
1460         if (!tmppreamble.empty())
1461                 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1462                         "LyX specific LaTeX commands.\n"
1463                         + tmppreamble + '\n';
1464
1465         // the text class specific preamble
1466         tmppreamble = features.getTClassPreamble();
1467         if (!tmppreamble.empty())
1468                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1469                         "Textclass specific LaTeX commands.\n"
1470                         + tmppreamble + '\n';
1471
1472         /* the user-defined preamble */
1473         if (!containsOnly(preamble, " \n\t"))
1474                 // FIXME UNICODE
1475                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1476                         "User specified LaTeX commands.\n"
1477                         + from_utf8(preamble) + '\n';
1478
1479         // subfig loads internally the LaTeX package "caption". As
1480         // caption is a very popular package, users will load it in
1481         // the preamble. Therefore we must load subfig behind the
1482         // user-defined preamble and check if the caption package was
1483         // loaded or not. For the case that caption is loaded before
1484         // subfig, there is the subfig option "caption=false". This
1485         // option also works when a koma-script class is used and
1486         // koma's own caption commands are used instead of caption. We
1487         // use \PassOptionsToPackage here because the user could have
1488         // already loaded subfig in the preamble.
1489         if (features.isRequired("subfig")) {
1490                 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1491                         " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1492                         "\\usepackage{subfig}\n";
1493         }
1494
1495         // Itemize bullet settings need to be last in case the user
1496         // defines their own bullets that use a package included
1497         // in the user-defined preamble -- ARRae
1498         // Actually it has to be done much later than that
1499         // since some packages like frenchb make modifications
1500         // at \begin{document} time -- JMarc
1501         docstring bullets_def;
1502         for (int i = 0; i < 4; ++i) {
1503                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1504                         if (bullets_def.empty())
1505                                 bullets_def += "\\AtBeginDocument{\n";
1506                         bullets_def += "  \\def\\labelitemi";
1507                         switch (i) {
1508                                 // `i' is one less than the item to modify
1509                         case 0:
1510                                 break;
1511                         case 1:
1512                                 bullets_def += 'i';
1513                                 break;
1514                         case 2:
1515                                 bullets_def += "ii";
1516                                 break;
1517                         case 3:
1518                                 bullets_def += 'v';
1519                                 break;
1520                         }
1521                         bullets_def += '{' +
1522                                 user_defined_bullet(i).getText()
1523                                 + "}\n";
1524                 }
1525         }
1526
1527         if (!bullets_def.empty())
1528                 atlyxpreamble += bullets_def + "}\n\n";
1529
1530         if (!atlyxpreamble.empty())
1531                 lyxpreamble += "\n\\makeatletter\n"
1532                         + atlyxpreamble + "\\makeatother\n\n";
1533
1534         // We try to load babel late, in case it interferes with other packages.
1535         // Jurabib and Hyperref have to be called after babel, though.
1536         if (use_babel && !features.isRequired("jurabib")
1537             && !features.isRequired("hyperref")
1538             && !features.isRequired("vietnamese")
1539             && !features.isRequired("japanese")) {
1540                 // FIXME UNICODE
1541                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1542                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1543         }
1544
1545         docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1546         if (!i18npreamble.empty())
1547                 lyxpreamble += i18npreamble + '\n';
1548
1549         int const nlines =
1550                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1551         for (int j = 0; j != nlines; ++j) {
1552                 texrow.newline();
1553         }
1554
1555         os << lyxpreamble;
1556
1557         // these packages (xunicode, for that matter) need to be loaded at least
1558         // after amsmath, amssymb, esint and the other packages that provide 
1559         // special glyphs
1560         if (useXetex) {
1561                 os << "\\usepackage{xunicode}\n";
1562                 texrow.newline();
1563                 os << "\\usepackage{xltxtra}\n";
1564                 texrow.newline();
1565         }
1566         return use_babel;
1567 }
1568
1569
1570 void BufferParams::useClassDefaults()
1571 {
1572         DocumentClass const & tclass = documentClass();
1573
1574         sides = tclass.sides();
1575         columns = tclass.columns();
1576         pagestyle = tclass.pagestyle();
1577         use_default_options = true;
1578         // Only if class has a ToC hierarchy
1579         if (tclass.hasTocLevels()) {
1580                 secnumdepth = tclass.secnumdepth();
1581                 tocdepth = tclass.tocdepth();
1582         }
1583 }
1584
1585
1586 bool BufferParams::hasClassDefaults() const
1587 {
1588         DocumentClass const & tclass = documentClass();
1589
1590         return sides == tclass.sides()
1591                 && columns == tclass.columns()
1592                 && pagestyle == tclass.pagestyle()
1593                 && use_default_options
1594                 && secnumdepth == tclass.secnumdepth()
1595                 && tocdepth == tclass.tocdepth();
1596 }
1597
1598
1599 DocumentClass const & BufferParams::documentClass() const
1600 {
1601         return *doc_class_;
1602 }
1603
1604
1605 DocumentClass const * BufferParams::documentClassPtr() const {
1606         return doc_class_;
1607 }
1608
1609
1610 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1611         // evil, but this function is evil
1612         doc_class_ = const_cast<DocumentClass *>(tc);
1613 }
1614
1615
1616 bool BufferParams::setBaseClass(string const & classname)
1617 {
1618         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1619         LayoutFileList & bcl = LayoutFileList::get();
1620         if (!bcl.haveClass(classname)) {
1621                 docstring s = 
1622                         bformat(_("The document class %1$s could not be found. "
1623                                 "A default textclass with default layouts will be used. "
1624                                 "LyX might not be able to produce output unless a correct "
1625                                 "textclass is selected from the document settings dialog."),
1626                         from_utf8(classname));
1627                 frontend::Alert::error(_("Document class not found"), s);
1628                 bcl.addEmptyClass(classname);
1629         }
1630
1631         bool const success = bcl[classname].load();
1632         if (!success) {
1633                 docstring s = 
1634                         bformat(_("The document class %1$s could not be loaded."),
1635                         from_utf8(classname));
1636                 frontend::Alert::error(_("Could not load class"), s);
1637                 return false;
1638         }
1639
1640         pimpl_->baseClass_ = classname;
1641         layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1642         return true;
1643 }
1644
1645
1646 LayoutFile const * BufferParams::baseClass() const
1647 {
1648         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1649                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1650         else 
1651                 return 0;
1652 }
1653
1654
1655 LayoutFileIndex const & BufferParams::baseClassID() const
1656 {
1657         return pimpl_->baseClass_;
1658 }
1659
1660
1661 void BufferParams::makeDocumentClass()
1662 {
1663         if (!baseClass())
1664                 return;
1665
1666         doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1667
1668         if (!local_layout.empty()) {
1669                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1670                         docstring const msg = _("Error reading internal layout information");
1671                         frontend::Alert::warning(_("Read Error"), msg);
1672                 }
1673         }
1674 }
1675
1676 bool BufferParams::moduleCanBeAdded(string const & modName) const
1677 {
1678         return layoutModules_.moduleCanBeAdded(modName, baseClass());
1679 }
1680
1681
1682 bool BufferParams::addLayoutModule(string const & modName)
1683 {
1684         LayoutModuleList::const_iterator it = layoutModules_.begin();
1685         LayoutModuleList::const_iterator end = layoutModules_.end();
1686         for (; it != end; it++)
1687                 if (*it == modName) 
1688                         return false;
1689         layoutModules_.push_back(modName);
1690         return true;
1691 }
1692
1693
1694 Font const BufferParams::getFont() const
1695 {
1696         FontInfo f = documentClass().defaultfont();
1697         if (fontsDefaultFamily == "rmdefault")
1698                 f.setFamily(ROMAN_FAMILY);
1699         else if (fontsDefaultFamily == "sfdefault")
1700                 f.setFamily(SANS_FAMILY);
1701         else if (fontsDefaultFamily == "ttdefault")
1702                 f.setFamily(TYPEWRITER_FAMILY);
1703         return Font(f, language);
1704 }
1705
1706
1707 void BufferParams::readPreamble(Lexer & lex)
1708 {
1709         if (lex.getString() != "\\begin_preamble")
1710                 lyxerr << "Error (BufferParams::readPreamble):"
1711                         "consistency check failed." << endl;
1712
1713         preamble = lex.getLongString("\\end_preamble");
1714 }
1715
1716
1717 void BufferParams::readLocalLayout(Lexer & lex)
1718 {
1719         if (lex.getString() != "\\begin_local_layout")
1720                 lyxerr << "Error (BufferParams::readLocalLayout):"
1721                         "consistency check failed." << endl;
1722
1723         local_layout = lex.getLongString("\\end_local_layout");
1724 }
1725
1726
1727 void BufferParams::readLanguage(Lexer & lex)
1728 {
1729         if (!lex.next()) return;
1730
1731         string const tmptok = lex.getString();
1732
1733         // check if tmptok is part of tex_babel in tex-defs.h
1734         language = languages.getLanguage(tmptok);
1735         if (!language) {
1736                 // Language tmptok was not found
1737                 language = default_language;
1738                 lyxerr << "Warning: Setting language `"
1739                        << tmptok << "' to `" << language->lang()
1740                        << "'." << endl;
1741         }
1742 }
1743
1744
1745 void BufferParams::readGraphicsDriver(Lexer & lex)
1746 {
1747         if (!lex.next()) 
1748                 return;
1749
1750         string const tmptok = lex.getString();
1751         // check if tmptok is part of tex_graphics in tex_defs.h
1752         int n = 0;
1753         while (true) {
1754                 string const test = tex_graphics[n++];
1755
1756                 if (test == tmptok) {
1757                         graphicsDriver = tmptok;
1758                         break;
1759                 }
1760                 if (test.empty()) {
1761                         lex.printError(
1762                                 "Warning: graphics driver `$$Token' not recognized!\n"
1763                                 "         Setting graphics driver to `default'.\n");
1764                         graphicsDriver = "default";
1765                         break;
1766                 }
1767         }
1768 }
1769
1770
1771 void BufferParams::readBullets(Lexer & lex)
1772 {
1773         if (!lex.next()) 
1774                 return;
1775
1776         int const index = lex.getInteger();
1777         lex.next();
1778         int temp_int = lex.getInteger();
1779         user_defined_bullet(index).setFont(temp_int);
1780         temp_bullet(index).setFont(temp_int);
1781         lex >> temp_int;
1782         user_defined_bullet(index).setCharacter(temp_int);
1783         temp_bullet(index).setCharacter(temp_int);
1784         lex >> temp_int;
1785         user_defined_bullet(index).setSize(temp_int);
1786         temp_bullet(index).setSize(temp_int);
1787 }
1788
1789
1790 void BufferParams::readBulletsLaTeX(Lexer & lex)
1791 {
1792         // The bullet class should be able to read this.
1793         if (!lex.next()) 
1794                 return;
1795         int const index = lex.getInteger();
1796         lex.next(true);
1797         docstring const temp_str = lex.getDocString();
1798
1799         user_defined_bullet(index).setText(temp_str);
1800         temp_bullet(index).setText(temp_str);
1801 }
1802
1803
1804 void BufferParams::readModules(Lexer & lex)
1805 {
1806         if (!lex.eatLine()) {
1807                 lyxerr << "Error (BufferParams::readModules):"
1808                                 "Unexpected end of input." << endl;
1809                 return;
1810         }
1811         while (true) {
1812                 string mod = lex.getString();
1813                 if (mod == "\\end_modules")
1814                         break;
1815                 addLayoutModule(mod);
1816                 lex.eatLine();
1817         }
1818 }
1819
1820
1821 void BufferParams::readRemovedModules(Lexer & lex)
1822 {
1823         if (!lex.eatLine()) {
1824                 lyxerr << "Error (BufferParams::readRemovedModules):"
1825                                 "Unexpected end of input." << endl;
1826                 return;
1827         }
1828         while (true) {
1829                 string mod = lex.getString();
1830                 if (mod == "\\end_removed_modules")
1831                         break;
1832                 removedModules_.push_back(mod);
1833                 lex.eatLine();
1834         }
1835         // now we want to remove any removed modules that were previously 
1836         // added. normally, that will be because default modules were added in 
1837         // setBaseClass(), which gets called when \textclass is read at the 
1838         // start of the read.
1839         list<string>::const_iterator rit = removedModules_.begin();
1840         list<string>::const_iterator const ren = removedModules_.end();
1841         for (; rit != ren; rit++) {
1842                 LayoutModuleList::iterator const mit = layoutModules_.begin();
1843                 LayoutModuleList::iterator const men = layoutModules_.end();
1844                 LayoutModuleList::iterator found = find(mit, men, *rit);
1845                 if (found == men)
1846                         continue;
1847                 layoutModules_.erase(found);
1848         }
1849 }
1850
1851
1852 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1853 {
1854         char real_papersize = papersize;
1855         if (real_papersize == PAPER_DEFAULT)
1856                 real_papersize = lyxrc.default_papersize;
1857
1858         switch (real_papersize) {
1859         case PAPER_DEFAULT:
1860                 // could be anything, so don't guess
1861                 return string();
1862         case PAPER_CUSTOM: {
1863                 if (purpose == XDVI && !paperwidth.empty() &&
1864                     !paperheight.empty()) {
1865                         // heightxwidth<unit>
1866                         string first = paperwidth;
1867                         string second = paperheight;
1868                         if (orientation == ORIENTATION_LANDSCAPE)
1869                                 first.swap(second);
1870                         // cut off unit.
1871                         return first.erase(first.length() - 2)
1872                                 + "x" + second;
1873                 }
1874                 return string();
1875         }
1876         case PAPER_A3:
1877                 return "a3";
1878         case PAPER_A4:
1879                 return "a4";
1880         case PAPER_A5:
1881                 return "a5";
1882         case PAPER_B3:
1883                 // dvips and dvipdfm do not know this
1884                 if (purpose == DVIPS || purpose == DVIPDFM)
1885                         return string();
1886                 return "b3";
1887         case PAPER_B4:
1888                 // dvipdfm does not know this
1889                 if (purpose == DVIPDFM)
1890                         return string();
1891                 return "b4";
1892         case PAPER_B5:
1893                 // dvipdfm does not know this
1894                 if (purpose == DVIPDFM)
1895                         return string();
1896                 return "b5";
1897         case PAPER_USEXECUTIVE:
1898                 // dvipdfm does not know this
1899                 if (purpose == DVIPDFM)
1900                         return string();
1901                 return "foolscap";
1902         case PAPER_USLEGAL:
1903                 return "legal";
1904         case PAPER_USLETTER:
1905         default:
1906                 if (purpose == XDVI)
1907                         return "us";
1908                 return "letter";
1909         }
1910 }
1911
1912
1913 string const BufferParams::dvips_options() const
1914 {
1915         string result;
1916
1917         if (use_geometry
1918             && papersize == PAPER_CUSTOM
1919             && !lyxrc.print_paper_dimension_flag.empty()
1920             && !paperwidth.empty()
1921             && !paperheight.empty()) {
1922                 // using a custom papersize
1923                 result = lyxrc.print_paper_dimension_flag;
1924                 result += ' ' + paperwidth;
1925                 result += ',' + paperheight;
1926         } else {
1927                 string const paper_option = paperSizeName(DVIPS);
1928                 if (!paper_option.empty() && (paper_option != "letter" ||
1929                     orientation != ORIENTATION_LANDSCAPE)) {
1930                         // dvips won't accept -t letter -t landscape.
1931                         // In all other cases, include the paper size
1932                         // explicitly.
1933                         result = lyxrc.print_paper_flag;
1934                         result += ' ' + paper_option;
1935                 }
1936         }
1937         if (orientation == ORIENTATION_LANDSCAPE &&
1938             papersize != PAPER_CUSTOM)
1939                 result += ' ' + lyxrc.print_landscape_flag;
1940         return result;
1941 }
1942
1943
1944 string BufferParams::babelCall(string const & lang_opts) const
1945 {
1946         string lang_pack = lyxrc.language_package;
1947         if (lang_pack != "\\usepackage{babel}")
1948                 return lang_pack;
1949         // suppress the babel call when there is no babel language defined
1950         // for the document language in the lib/languages file and if no
1951         // other languages are used (lang_opts is then empty)
1952         if (lang_opts.empty())
1953                 return string();
1954         // If Vietnamese is used, babel must directly be loaded with the
1955         // language options, see
1956         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1957         size_t viet = lang_opts.find("vietnam");
1958         // viet = string::npos when not found
1959         // the same is for all other languages that are not directly supported by
1960         // babel, but where LaTeX-packages add babel support.
1961         // this is currently the case for Latvian, Lithuanian, and Mongolian
1962         size_t latvian = lang_opts.find("latvian");
1963         size_t lithu = lang_opts.find("lithuanian");
1964         size_t mongo = lang_opts.find("mongolian");
1965         // If Japanese is used, babel must directly be loaded with the
1966         // language options, see
1967         // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1968         size_t japan = lang_opts.find("japanese");
1969         if (!lyxrc.language_global_options || viet != string::npos
1970                 || japan != string::npos || latvian != string::npos
1971                 || lithu != string::npos || mongo != string::npos)
1972                 return "\\usepackage[" + lang_opts + "]{babel}";
1973         return lang_pack;
1974 }
1975
1976
1977 docstring BufferParams::getGraphicsDriver(string const & package) const
1978 {
1979         docstring result;
1980
1981         if (package == "geometry") {
1982                 if (graphicsDriver == "dvips"
1983                     || graphicsDriver == "dvipdfm"
1984                     || graphicsDriver == "pdftex"
1985                     || graphicsDriver == "vtex")
1986                         result = from_ascii(graphicsDriver);
1987                 else if (graphicsDriver == "dvipdfmx")
1988                         result = from_ascii("dvipdfm");
1989         }
1990
1991         return result;
1992 }
1993
1994
1995 void BufferParams::writeEncodingPreamble(odocstream & os,
1996                 LaTeXFeatures & features, TexRow & texrow) const
1997 {
1998         if (useXetex)
1999                 return;
2000         if (inputenc == "auto") {
2001                 string const doc_encoding =
2002                         language->encoding()->latexName();
2003                 Encoding::Package const package =
2004                         language->encoding()->package();
2005
2006                 // Create a list with all the input encodings used
2007                 // in the document
2008                 set<string> encodings =
2009                         features.getEncodingSet(doc_encoding);
2010
2011                 // If the "japanese" package (i.e. pLaTeX) is used,
2012                 // inputenc must be omitted.
2013                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2014                 if (package == Encoding::japanese)
2015                      features.require("japanese");
2016
2017                 if ((!encodings.empty() || package == Encoding::inputenc)
2018                     && !features.isRequired("japanese")) {
2019                         os << "\\usepackage[";
2020                         set<string>::const_iterator it = encodings.begin();
2021                         set<string>::const_iterator const end = encodings.end();
2022                         if (it != end) {
2023                                 os << from_ascii(*it);
2024                                 ++it;
2025                         }
2026                         for (; it != end; ++it)
2027                                 os << ',' << from_ascii(*it);
2028                         if (package == Encoding::inputenc) {
2029                                 if (!encodings.empty())
2030                                         os << ',';
2031                                 os << from_ascii(doc_encoding);
2032                         }
2033                         os << "]{inputenc}\n";
2034                         texrow.newline();
2035                 }
2036                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2037                         if (language->encoding()->name() == "utf8-cjk"
2038                             && LaTeXFeatures::isAvailable("CJKutf8"))
2039                                 os << "\\usepackage{CJKutf8}\n";
2040                         else
2041                                 os << "\\usepackage{CJK}\n";
2042                         texrow.newline();
2043                 }
2044         } else if (inputenc != "default") {
2045                 switch (encoding().package()) {
2046                 case Encoding::none:
2047                 case Encoding::japanese:
2048                         break;
2049                 case Encoding::inputenc:
2050                         // do not load inputenc if japanese is used
2051                         if (features.isRequired("japanese"))
2052                                 break;
2053                         os << "\\usepackage[" << from_ascii(inputenc)
2054                            << "]{inputenc}\n";
2055                         texrow.newline();
2056                         break;
2057                 case Encoding::CJK:
2058                         if (encoding().name() == "utf8-cjk"
2059                             && LaTeXFeatures::isAvailable("CJKutf8"))
2060                                 os << "\\usepackage{CJKutf8}\n";
2061                         else
2062                                 os << "\\usepackage{CJK}\n";
2063                         texrow.newline();
2064                         break;
2065                 }
2066         }
2067
2068         // The encoding "armscii8" (for Armenian) is only available when
2069         // the package "armtex" is loaded.
2070         if (language->encoding()->latexName() == "armscii8"
2071             || inputenc == "armscii8") {
2072                 os << "\\usepackage{armtex}\n";
2073                 texrow.newline();
2074         }
2075 }
2076
2077
2078 string const BufferParams::parseFontName(string const & name) const
2079 {
2080         string mangled = name;
2081         size_t const idx = mangled.find('[');
2082         if (idx == string::npos || idx == 0)
2083                 return mangled;
2084         else
2085                 return mangled.substr(0, idx - 1);
2086 }
2087
2088
2089 string const BufferParams::loadFonts(string const & rm,
2090                                      string const & sf, string const & tt,
2091                                      bool const & sc, bool const & osf,
2092                                      int const & sfscale, int const & ttscale,
2093                                      bool const & xetex) const
2094 {
2095         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2096            several packages have been replaced by others, that might not
2097            be installed on every system. We have to take care for that
2098            (see psnfss.pdf). We try to support all psnfss fonts as well
2099            as the fonts that have become de facto standard in the LaTeX
2100            world (e.g. Latin Modern). We do not support obsolete fonts
2101            (like PSLatex). In general, it should be possible to mix any
2102            rm font with any sf or tt font, respectively. (JSpitzm)
2103            TODO:
2104                 -- separate math fonts.
2105         */
2106
2107         if (rm == "default" && sf == "default" && tt == "default")
2108                 //nothing to do
2109                 return string();
2110
2111         ostringstream os;
2112
2113         if (xetex) {
2114                 if (rm != "default")
2115                         os << "\\setmainfont[Mapping=tex-text]{"
2116                            << parseFontName(rm) << "}\n";
2117                 if (sf != "default") {
2118                         string const sans = parseFontName(sf);
2119                         if (sfscale != 100)
2120                                 os << "\\setsansfont[Scale=" 
2121                                    << float(sfscale) / 100 
2122                                    << ",Mapping=tex-text]{"
2123                                    << sans << "}\n";
2124                         else
2125                                 os << "\\setsansfont[Mapping=tex-text]{"
2126                                    << sans << "}\n";
2127                 }
2128                 if (tt != "default") {
2129                         string const mono = parseFontName(tt);
2130                         if (ttscale != 100)
2131                                 os << "\\setmonofont[Scale=" 
2132                                    << float(sfscale) / 100 
2133                                    << "]{"
2134                                    << mono << "}\n";
2135                         else
2136                                 os << "\\setmonofont[Mapping=tex-text]{"
2137                                    << mono << "}\n";
2138                 }
2139                 if (osf)
2140                         os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2141                 return os.str();
2142         }
2143
2144         // ROMAN FONTS
2145         // Computer Modern (must be explicitely selectable -- there might be classes
2146         // that define a different default font!
2147         if (rm == "cmr") {
2148                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2149                 // osf for Computer Modern needs eco.sty
2150                 if (osf)
2151                         os << "\\usepackage{eco}\n";
2152         }
2153         // Latin Modern Roman
2154         else if (rm == "lmodern")
2155                 os << "\\usepackage{lmodern}\n";
2156         // AE
2157         else if (rm == "ae") {
2158                 // not needed when using OT1 font encoding.
2159                 if (lyxrc.fontenc != "default")
2160                         os << "\\usepackage{ae,aecompl}\n";
2161         }
2162         // Times
2163         else if (rm == "times") {
2164                 // try to load the best available package
2165                 if (LaTeXFeatures::isAvailable("mathptmx"))
2166                         os << "\\usepackage{mathptmx}\n";
2167                 else if (LaTeXFeatures::isAvailable("mathptm"))
2168                         os << "\\usepackage{mathptm}\n";
2169                 else
2170                         os << "\\usepackage{times}\n";
2171         }
2172         // Palatino
2173         else if (rm == "palatino") {
2174                 // try to load the best available package
2175                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2176                         os << "\\usepackage";
2177                         if (osf || sc) {
2178                                 os << '[';
2179                                 if (!osf)
2180                                         os << "sc";
2181                                 else
2182                                         // "osf" includes "sc"!
2183                                         os << "osf";
2184                                 os << ']';
2185                         }
2186                         os << "{mathpazo}\n";
2187                 }
2188                 else if (LaTeXFeatures::isAvailable("mathpple"))
2189                         os << "\\usepackage{mathpple}\n";
2190                 else
2191                         os << "\\usepackage{palatino}\n";
2192         }
2193         // Utopia
2194         else if (rm == "utopia") {
2195                 // fourier supersedes utopia.sty, but does
2196                 // not work with OT1 encoding.
2197                 if (LaTeXFeatures::isAvailable("fourier")
2198                     && lyxrc.fontenc != "default") {
2199                         os << "\\usepackage";
2200                         if (osf || sc) {
2201                                 os << '[';
2202                                 if (sc)
2203                                         os << "expert";
2204                                 if (osf && sc)
2205                                         os << ',';
2206                                 if (osf)
2207                                         os << "oldstyle";
2208                                 os << ']';
2209                         }
2210                         os << "{fourier}\n";
2211                 }
2212                 else
2213                         os << "\\usepackage{utopia}\n";
2214         }
2215         // Bera (complete fontset)
2216         else if (rm == "bera" && sf == "default" && tt == "default")
2217                 os << "\\usepackage{bera}\n";
2218         // everything else
2219         else if (rm != "default")
2220                 os << "\\usepackage" << "{" << rm << "}\n";
2221
2222         // SANS SERIF
2223         // Helvetica, Bera Sans
2224         if (sf == "helvet" || sf == "berasans") {
2225                 if (sfscale != 100)
2226                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2227                            << "]{" << sf << "}\n";
2228                 else
2229                         os << "\\usepackage{" << sf << "}\n";
2230         }
2231         // Avant Garde
2232         else if (sf == "avant")
2233                 os << "\\usepackage{" << sf << "}\n";
2234         // Computer Modern, Latin Modern, CM Bright
2235         else if (sf != "default")
2236                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2237
2238         // monospaced/typewriter
2239         // Courier, LuxiMono
2240         if (tt == "luximono" || tt == "beramono") {
2241                 if (ttscale != 100)
2242                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2243                            << "]{" << tt << "}\n";
2244                 else
2245                         os << "\\usepackage{" << tt << "}\n";
2246         }
2247         // Courier
2248         else if (tt == "courier" )
2249                 os << "\\usepackage{" << tt << "}\n";
2250         // Computer Modern, Latin Modern, CM Bright
2251         else if (tt != "default")
2252                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2253
2254         return os.str();
2255 }
2256
2257
2258 Encoding const & BufferParams::encoding() const
2259 {
2260         if (useXetex)
2261                 return *(encodings.fromLaTeXName("utf8-plain"));
2262         if (inputenc == "auto" || inputenc == "default")
2263                 return *language->encoding();
2264         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2265         if (enc)
2266                 return *enc;
2267         LYXERR0("Unknown inputenc value `" << inputenc
2268                << "'. Using `auto' instead.");
2269         return *language->encoding();
2270 }
2271
2272
2273 CiteEngine BufferParams::citeEngine() const
2274 {
2275         // FIXME the class should provide the numerical/
2276         // authoryear choice
2277         if (documentClass().provides("natbib")
2278             && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2279                 return ENGINE_NATBIB_AUTHORYEAR;
2280         return cite_engine_;
2281 }
2282
2283
2284 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2285 {
2286         cite_engine_ = cite_engine;
2287 }
2288
2289 } // namespace lyx