]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
d2192067d1cb47ce187db9df5fa2f888c71c0717
[lyx.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                         // not yet operational
622                         if (tok == "\\color") {
623                                 lex.eatLine();
624                                 string color = lex.getString();
625                                 if (branch_ptr)
626                                         branch_ptr->setColor(color);
627                                 // Update also the Color table:
628                                 if (color == "none")
629                                         color = lcolor.getX11Name(Color_background);
630                                 // FIXME UNICODE
631                                 lcolor.setColor(to_utf8(branch), color);
632                         }
633                 }
634         } else if (token == "\\index") {
635                 lex.eatLine();
636                 docstring index = lex.getDocString();
637                 indiceslist().add(index);
638                 while (true) {
639                         lex.next();
640                         string const tok = lex.getString();
641                         if (tok == "\\end_index")
642                                 break;
643                         Index * index_ptr = indiceslist().find(index);
644                         if (tok == "\\shortcut") {
645                                 lex.next();
646                                 if (index_ptr)
647                                         index_ptr->setShortcut(lex.getDocString());
648                         }
649                         // not yet operational
650                         if (tok == "\\color") {
651                                 lex.eatLine();
652                                 string color = lex.getString();
653                                 if (index_ptr)
654                                         index_ptr->setColor(color);
655                                 // Update also the Color table:
656                                 if (color == "none")
657                                         color = lcolor.getX11Name(Color_background);
658                                 // FIXME UNICODE
659                                 lcolor.setColor(to_utf8(index), color);
660                         }
661                 }
662         } else if (token == "\\author") {
663                 lex.eatLine();
664                 istringstream ss(lex.getString());
665                 Author a;
666                 ss >> a;
667                 author_map.push_back(pimpl_->authorlist.record(a));
668         } else if (token == "\\paperorientation") {
669                 string orient;
670                 lex >> orient;
671                 orientation = paperorientationtranslator().find(orient);
672         } else if (token == "\\backgroundcolor") {
673                 lex.eatLine();
674                 backgroundcolor = lyx::rgbFromHexName(lex.getString());
675         } else if (token == "\\paperwidth") {
676                 lex >> paperwidth;
677         } else if (token == "\\paperheight") {
678                 lex >> paperheight;
679         } else if (token == "\\leftmargin") {
680                 lex >> leftmargin;
681         } else if (token == "\\topmargin") {
682                 lex >> topmargin;
683         } else if (token == "\\rightmargin") {
684                 lex >> rightmargin;
685         } else if (token == "\\bottommargin") {
686                 lex >> bottommargin;
687         } else if (token == "\\headheight") {
688                 lex >> headheight;
689         } else if (token == "\\headsep") {
690                 lex >> headsep;
691         } else if (token == "\\footskip") {
692                 lex >> footskip;
693         } else if (token == "\\columnsep") {
694                 lex >> columnsep;
695         } else if (token == "\\paperfontsize") {
696                 lex >> fontsize;
697         } else if (token == "\\papercolumns") {
698                 lex >> columns;
699         } else if (token == "\\listings_params") {
700                 string par;
701                 lex >> par;
702                 listings_params = InsetListingsParams(par).params();
703         } else if (token == "\\papersides") {
704                 int psides;
705                 lex >> psides;
706                 sides = sidestranslator().find(psides);
707         } else if (token == "\\paperpagestyle") {
708                 lex >> pagestyle;
709         } else if (token == "\\bullet") {
710                 readBullets(lex);
711         } else if (token == "\\bulletLaTeX") {
712                 readBulletsLaTeX(lex);
713         } else if (token == "\\secnumdepth") {
714                 lex >> secnumdepth;
715         } else if (token == "\\tocdepth") {
716                 lex >> tocdepth;
717         } else if (token == "\\spacing") {
718                 string nspacing;
719                 lex >> nspacing;
720                 string tmp_val;
721                 if (nspacing == "other") {
722                         lex >> tmp_val;
723                 }
724                 spacing().set(spacetranslator().find(nspacing), tmp_val);
725         } else if (token == "\\float_placement") {
726                 lex >> float_placement;
727
728         } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
729                 string toktmp = pdfoptions().readToken(lex, token);
730                 if (!toktmp.empty()) {
731                         lyxerr << "PDFOptions::readToken(): Unknown token: " <<
732                                 toktmp << endl;
733                         return toktmp;
734                 }
735         } else {
736                 lyxerr << "BufferParams::readToken(): Unknown token: " << 
737                         token << endl;
738                 return token;
739         }
740
741         return string();
742 }
743
744
745 void BufferParams::writeFile(ostream & os) const
746 {
747         // The top of the file is written by the buffer.
748         // Prints out the buffer info into the .lyx file given by file
749
750         // the textclass
751         os << "\\textclass " << baseClass()->name() << '\n';
752
753         // then the preamble
754         if (!preamble.empty()) {
755                 // remove '\n' from the end of preamble
756                 string const tmppreamble = rtrim(preamble, "\n");
757                 os << "\\begin_preamble\n"
758                    << tmppreamble
759                    << "\n\\end_preamble\n";
760         }
761
762         // the options
763         if (!options.empty()) {
764                 os << "\\options " << options << '\n';
765         }
766
767         // use the class options defined in the layout?
768         os << "\\use_default_options " 
769            << convert<string>(use_default_options) << "\n";
770
771         // the master document
772         if (!master.empty()) {
773                 os << "\\master " << master << '\n';
774         }
775         
776         // removed modules
777         if (!removedModules_.empty()) {
778                 os << "\\begin_removed_modules" << '\n';
779                 list<string>::const_iterator it = removedModules_.begin();
780                 list<string>::const_iterator en = removedModules_.end();
781                 for (; it != en; it++)
782                         os << *it << '\n';
783                 os << "\\end_removed_modules" << '\n';
784         }
785
786         // the modules
787         if (!layoutModules_.empty()) {
788                 os << "\\begin_modules" << '\n';
789                 LayoutModuleList::const_iterator it = layoutModules_.begin();
790                 LayoutModuleList::const_iterator en = layoutModules_.end();
791                 for (; it != en; it++)
792                         os << *it << '\n';
793                 os << "\\end_modules" << '\n';
794         }
795         
796         // local layout information
797         if (!local_layout.empty()) {
798                 // remove '\n' from the end 
799                 string const tmplocal = rtrim(local_layout, "\n");
800                 os << "\\begin_local_layout\n"
801                    << tmplocal
802                    << "\n\\end_local_layout\n";
803         }
804
805         // then the text parameters
806         if (language != ignore_language)
807                 os << "\\language " << language->lang() << '\n';
808         os << "\\inputencoding " << inputenc
809            << "\n\\font_roman " << fontsRoman
810            << "\n\\font_sans " << fontsSans
811            << "\n\\font_typewriter " << fontsTypewriter
812            << "\n\\font_default_family " << fontsDefaultFamily
813            << "\n\\use_xetex " << convert<string>(useXetex)
814            << "\n\\font_sc " << convert<string>(fontsSC)
815            << "\n\\font_osf " << convert<string>(fontsOSF)
816            << "\n\\font_sf_scale " << fontsSansScale
817            << "\n\\font_tt_scale " << fontsTypewriterScale
818            << '\n';
819         if (!fontsCJK.empty()) {
820                 os << "\\font_cjk " << fontsCJK << '\n';
821         }
822         os << "\n\\graphics " << graphicsDriver << '\n';
823         os << "\\default_output_format " << defaultOutputFormat << '\n';
824         os << "\\bibtex_command " << bibtex_command << '\n';
825         os << "\\index_command " << index_command << '\n';
826
827         if (!float_placement.empty()) {
828                 os << "\\float_placement " << float_placement << '\n';
829         }
830         os << "\\paperfontsize " << fontsize << '\n';
831
832         spacing().writeFile(os);
833         pdfoptions().writeFile(os);
834
835         os << "\\papersize " << string_papersize[papersize]
836            << "\n\\use_geometry " << convert<string>(use_geometry)
837            << "\n\\use_amsmath " << use_amsmath
838            << "\n\\use_esint " << use_esint
839            << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
840            << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
841            << "\n\\use_indices " << convert<string>(use_indices)
842            << "\n\\paperorientation " << string_orientation[orientation]
843            << '\n';
844            if (backgroundcolor != lyx::rgbFromHexName("#ffffff"))
845                 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
846
847         BranchList::const_iterator it = branchlist().begin();
848         BranchList::const_iterator end = branchlist().end();
849         for (; it != end; ++it) {
850                 os << "\\branch " << to_utf8(it->branch())
851                    << "\n\\selected " << it->isSelected()
852                    << "\n\\color " << lyx::X11hexname(it->color())
853                    << "\n\\end_branch"
854                    << "\n";
855         }
856
857         IndicesList::const_iterator iit = indiceslist().begin();
858         IndicesList::const_iterator iend = indiceslist().end();
859         for (; iit != iend; ++iit) {
860                 os << "\\index " << to_utf8(iit->index())
861                    << "\n\\shortcut " << to_utf8(iit->shortcut())
862                    << "\n\\color " << lyx::X11hexname(iit->color())
863                    << "\n\\end_index"
864                    << "\n";
865         }
866
867         if (!paperwidth.empty())
868                 os << "\\paperwidth "
869                    << VSpace(paperwidth).asLyXCommand() << '\n';
870         if (!paperheight.empty())
871                 os << "\\paperheight "
872                    << VSpace(paperheight).asLyXCommand() << '\n';
873         if (!leftmargin.empty())
874                 os << "\\leftmargin "
875                    << VSpace(leftmargin).asLyXCommand() << '\n';
876         if (!topmargin.empty())
877                 os << "\\topmargin "
878                    << VSpace(topmargin).asLyXCommand() << '\n';
879         if (!rightmargin.empty())
880                 os << "\\rightmargin "
881                    << VSpace(rightmargin).asLyXCommand() << '\n';
882         if (!bottommargin.empty())
883                 os << "\\bottommargin "
884                    << VSpace(bottommargin).asLyXCommand() << '\n';
885         if (!headheight.empty())
886                 os << "\\headheight "
887                    << VSpace(headheight).asLyXCommand() << '\n';
888         if (!headsep.empty())
889                 os << "\\headsep "
890                    << VSpace(headsep).asLyXCommand() << '\n';
891         if (!footskip.empty())
892                 os << "\\footskip "
893                    << VSpace(footskip).asLyXCommand() << '\n';
894         if (!columnsep.empty())
895                 os << "\\columnsep " 
896                          << VSpace(columnsep).asLyXCommand() << '\n';
897         os << "\\secnumdepth " << secnumdepth
898            << "\n\\tocdepth " << tocdepth
899            << "\n\\paragraph_separation "
900            << string_paragraph_separation[paragraph_separation]
901            << "\n\\defskip " << getDefSkip().asLyXCommand()
902            << "\n\\quotes_language "
903            << string_quotes_language[quotes_language]
904            << "\n\\papercolumns " << columns
905            << "\n\\papersides " << sides
906            << "\n\\paperpagestyle " << pagestyle << '\n';
907         if (!listings_params.empty())
908                 os << "\\listings_params \"" <<
909                         InsetListingsParams(listings_params).encodedString() << "\"\n";
910         for (int i = 0; i < 4; ++i) {
911                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
912                         if (user_defined_bullet(i).getFont() != -1) {
913                                 os << "\\bullet " << i << " "
914                                    << user_defined_bullet(i).getFont() << " "
915                                    << user_defined_bullet(i).getCharacter() << " "
916                                    << user_defined_bullet(i).getSize() << "\n";
917                         }
918                         else {
919                                 // FIXME UNICODE
920                                 os << "\\bulletLaTeX " << i << " \""
921                                    << lyx::to_ascii(user_defined_bullet(i).getText())
922                                    << "\"\n";
923                         }
924                 }
925         }
926
927         os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
928         os << "\\output_changes " << convert<string>(outputChanges) << "\n";
929
930         AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
931         AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
932         for (; a_it != a_end; ++a_it) {
933                 if (a_it->second.used())
934                         os << "\\author " << a_it->second << "\n";
935                 else
936                         os << "\\author " << Author() << "\n";
937         }
938 }
939
940
941 void BufferParams::validate(LaTeXFeatures & features) const
942 {
943         features.require(documentClass().requires());
944
945         if (outputChanges) {
946                 bool dvipost    = LaTeXFeatures::isAvailable("dvipost");
947                 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
948                                   LaTeXFeatures::isAvailable("xcolor");
949
950                 switch (features.runparams().flavor) {
951                 case OutputParams::LATEX:
952                         if (dvipost) {
953                                 features.require("ct-dvipost");
954                                 features.require("dvipost");
955                         } else if (xcolorulem) {
956                                 features.require("ct-xcolor-ulem");
957                                 features.require("ulem");
958                                 features.require("xcolor");
959                         } else {
960                                 features.require("ct-none");
961                         }
962                         break;
963                 case OutputParams::PDFLATEX:
964                 case OutputParams::XETEX:
965                         if (xcolorulem) {
966                                 features.require("ct-xcolor-ulem");
967                                 features.require("ulem");
968                                 features.require("xcolor");
969                                 // improves color handling in PDF output
970                                 features.require("pdfcolmk"); 
971                         } else {
972                                 features.require("ct-none");
973                         }
974                         break;
975                 default:
976                         break;
977                 }
978         }
979
980         // Floats with 'Here definitely' as default setting.
981         if (float_placement.find('H') != string::npos)
982                 features.require("float");
983
984         // AMS Style is at document level
985         if (use_amsmath == package_on
986             || documentClass().provides("amsmath"))
987                 features.require("amsmath");
988         if (use_esint == package_on)
989                 features.require("esint");
990
991         // Document-level line spacing
992         if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
993                 features.require("setspace");
994
995         // the bullet shapes are buffer level not paragraph level
996         // so they are tested here
997         for (int i = 0; i < 4; ++i) {
998                 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i]) 
999                         continue;
1000                 int const font = user_defined_bullet(i).getFont();
1001                 if (font == 0) {
1002                         int const c = user_defined_bullet(i).getCharacter();
1003                         if (c == 16
1004                             || c == 17
1005                             || c == 25
1006                             || c == 26
1007                             || c == 31) {
1008                                 features.require("latexsym");
1009                         }
1010                 } else if (font == 1) {
1011                         features.require("amssymb");
1012                 } else if (font >= 2 && font <= 5) {
1013                         features.require("pifont");
1014                 }
1015         }
1016
1017         if (pdfoptions().use_hyperref) {
1018                 features.require("hyperref");
1019                 // due to interferences with babel and hyperref, the color package has to
1020                 // be loaded after hyperref when hyperref is used with the colorlinks
1021                 // option, see http://bugzilla.lyx.org/show_bug.cgi?id=5291
1022                 if (pdfoptions().colorlinks)
1023                         features.require("color");
1024         }
1025
1026         if (useXetex)
1027                 features.require("xetex");
1028
1029         if (language->lang() == "vietnamese")
1030                 features.require("vietnamese");
1031         else if (language->lang() == "japanese")
1032                 features.require("japanese");
1033 }
1034
1035
1036 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
1037                               TexRow & texrow) const
1038 {
1039         os << "\\documentclass";
1040
1041         DocumentClass const & tclass = documentClass();
1042
1043         ostringstream clsoptions; // the document class options.
1044
1045         if (tokenPos(tclass.opt_fontsize(),
1046                      '|', fontsize) >= 0) {
1047                 // only write if existing in list (and not default)
1048                 clsoptions << fontsize << "pt,";
1049         }
1050
1051         // custom, A3, B3 and B4 paper sizes need geometry
1052         bool nonstandard_papersize = papersize == PAPER_B3
1053                 || papersize == PAPER_B4
1054                 || papersize == PAPER_A3
1055                 || papersize == PAPER_CUSTOM;
1056
1057         if (!use_geometry) {
1058                 switch (papersize) {
1059                 case PAPER_A4:
1060                         clsoptions << "a4paper,";
1061                         break;
1062                 case PAPER_USLETTER:
1063                         clsoptions << "letterpaper,";
1064                         break;
1065                 case PAPER_A5:
1066                         clsoptions << "a5paper,";
1067                         break;
1068                 case PAPER_B5:
1069                         clsoptions << "b5paper,";
1070                         break;
1071                 case PAPER_USEXECUTIVE:
1072                         clsoptions << "executivepaper,";
1073                         break;
1074                 case PAPER_USLEGAL:
1075                         clsoptions << "legalpaper,";
1076                         break;
1077                 case PAPER_DEFAULT:
1078                 case PAPER_A3:
1079                 case PAPER_B3:
1080                 case PAPER_B4:
1081                 case PAPER_CUSTOM:
1082                         break;
1083                 }
1084         }
1085
1086         // if needed
1087         if (sides != tclass.sides()) {
1088                 switch (sides) {
1089                 case OneSide:
1090                         clsoptions << "oneside,";
1091                         break;
1092                 case TwoSides:
1093                         clsoptions << "twoside,";
1094                         break;
1095                 }
1096         }
1097
1098         // if needed
1099         if (columns != tclass.columns()) {
1100                 if (columns == 2)
1101                         clsoptions << "twocolumn,";
1102                 else
1103                         clsoptions << "onecolumn,";
1104         }
1105
1106         if (!use_geometry
1107             && orientation == ORIENTATION_LANDSCAPE)
1108                 clsoptions << "landscape,";
1109
1110         // language should be a parameter to \documentclass
1111         if (language->babel() == "hebrew"
1112             && default_language->babel() != "hebrew")
1113                 // This seems necessary
1114                 features.useLanguage(default_language);
1115
1116         ostringstream language_options;
1117         bool const use_babel = features.useBabel();
1118         if (use_babel) {
1119                 language_options << features.getLanguages();
1120                 if (!language->babel().empty()) {
1121                         if (!language_options.str().empty())
1122                                 language_options << ',';
1123                         language_options << language->babel();
1124                 }
1125                 // if Vietnamese is used, babel must directly be loaded
1126                 // with language options, not in the class options, see
1127                 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1128                 size_t viet = language_options.str().find("vietnam");
1129                 // viet = string::npos when not found
1130                 // the same is for all other languages that are not directly supported by
1131                 // babel, but where LaTeX-packages add babel support.
1132                 // this is currently the case for Latvian, Lithuanian, and Mongolian
1133                 size_t latvian = language_options.str().find("latvian");
1134                 size_t lithu = language_options.str().find("lithuanian");
1135                 size_t mongo = language_options.str().find("mongolian");
1136                 // if Japanese is used, babel must directly be loaded
1137                 // with language options, not in the class options, see
1138                 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1139                 size_t japan = language_options.str().find("japanese");
1140                 if (lyxrc.language_global_options && !language_options.str().empty()
1141                         && viet == string::npos && japan == string::npos
1142                         && latvian == string::npos && lithu == string::npos
1143                         && mongo == string::npos)
1144                         clsoptions << language_options.str() << ',';
1145         }
1146
1147         // the predefined options from the layout
1148         if (use_default_options && !tclass.options().empty())
1149                 clsoptions << tclass.options() << ',';
1150
1151         // the user-defined options
1152         if (!options.empty()) {
1153                 clsoptions << options << ',';
1154         }
1155
1156         string strOptions(clsoptions.str());
1157         if (!strOptions.empty()) {
1158                 strOptions = rtrim(strOptions, ",");
1159                 // FIXME UNICODE
1160                 os << '[' << from_utf8(strOptions) << ']';
1161         }
1162
1163         os << '{' << from_ascii(tclass.latexname()) << "}\n";
1164         texrow.newline();
1165         // end of \documentclass defs
1166
1167         if (useXetex) {
1168                 os << "\\usepackage{fontspec}\n";
1169                 texrow.newline();
1170         }
1171
1172         // font selection must be done before loading fontenc.sty
1173         string const fonts =
1174                 loadFonts(fontsRoman, fontsSans,
1175                           fontsTypewriter, fontsSC, fontsOSF,
1176                           fontsSansScale, fontsTypewriterScale, useXetex);
1177         if (!fonts.empty()) {
1178                 os << from_ascii(fonts);
1179                 texrow.newline();
1180         }
1181         if (fontsDefaultFamily != "default")
1182                 os << "\\renewcommand{\\familydefault}{\\"
1183                    << from_ascii(fontsDefaultFamily) << "}\n";
1184
1185         // set font encoding
1186         // this one is not per buffer
1187         // for arabic_arabi and farsi we also need to load the LAE and
1188         // LFE encoding
1189         // XeTeX works without fontenc
1190         if (lyxrc.fontenc != "default" && language->lang() != "japanese"
1191             && !useXetex) {
1192                 if (language->lang() == "arabic_arabi"
1193                     || language->lang() == "farsi") {
1194                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1195                            << ",LFE,LAE]{fontenc}\n";
1196                         texrow.newline();
1197                 } else {
1198                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1199                            << "]{fontenc}\n";
1200                         texrow.newline();
1201                 }
1202         }
1203
1204         // handle inputenc etc.
1205         writeEncodingPreamble(os, features, texrow);
1206
1207         if (!listings_params.empty() || features.isRequired("listings")) {
1208                 os << "\\usepackage{listings}\n";
1209                 texrow.newline();
1210         }
1211         if (!listings_params.empty()) {
1212                 os << "\\lstset{";
1213                 // do not test validity because listings_params is 
1214                 // supposed to be valid
1215                 string par =
1216                         InsetListingsParams(listings_params).separatedParams(true);
1217                 // we can't support all packages, but we should load the color package
1218                 if (par.find("\\color", 0) != string::npos)
1219                         features.require("color");
1220                 os << from_utf8(par);
1221                 // count the number of newlines
1222                 for (size_t i = 0; i < par.size(); ++i)
1223                         if (par[i] == '\n')
1224                                 texrow.newline();
1225                 os << "}\n";
1226                 texrow.newline();
1227         }
1228         if (!tclass.provides("geometry")
1229             && (use_geometry || nonstandard_papersize)) {
1230                 odocstringstream ods;
1231                 if (!getGraphicsDriver("geometry").empty())
1232                         ods << getGraphicsDriver("geometry");
1233                 if (orientation == ORIENTATION_LANDSCAPE)
1234                         ods << ",landscape";
1235                 switch (papersize) {
1236                 case PAPER_CUSTOM:
1237                         if (!paperwidth.empty())
1238                                 ods << ",paperwidth="
1239                                    << from_ascii(paperwidth);
1240                         if (!paperheight.empty())
1241                                 ods << ",paperheight="
1242                                    << from_ascii(paperheight);
1243                         break;
1244                 case PAPER_USLETTER:
1245                         ods << ",letterpaper";
1246                         break;
1247                 case PAPER_USLEGAL:
1248                         ods << ",legalpaper";
1249                         break;
1250                 case PAPER_USEXECUTIVE:
1251                         ods << ",executivepaper";
1252                         break;
1253                 case PAPER_A3:
1254                         ods << ",a3paper";
1255                         break;
1256                 case PAPER_A4:
1257                         ods << ",a4paper";
1258                         break;
1259                 case PAPER_A5:
1260                         ods << ",a5paper";
1261                         break;
1262                 case PAPER_B3:
1263                         ods << ",b3paper";
1264                         break;
1265                 case PAPER_B4:
1266                         ods << ",b4paper";
1267                         break;
1268                 case PAPER_B5:
1269                         ods << ",b5paper";
1270                         break;
1271                 default:
1272                         // default papersize ie PAPER_DEFAULT
1273                         switch (lyxrc.default_papersize) {
1274                         case PAPER_DEFAULT: // keep compiler happy
1275                         case PAPER_USLETTER:
1276                                 ods << ",letterpaper";
1277                                 break;
1278                         case PAPER_USLEGAL:
1279                                 ods << ",legalpaper";
1280                                 break;
1281                         case PAPER_USEXECUTIVE:
1282                                 ods << ",executivepaper";
1283                                 break;
1284                         case PAPER_A3:
1285                                 ods << ",a3paper";
1286                                 break;
1287                         case PAPER_A4:
1288                                 ods << ",a4paper";
1289                                 break;
1290                         case PAPER_A5:
1291                                 ods << ",a5paper";
1292                                 break;
1293                         case PAPER_B5:
1294                                 ods << ",b5paper";
1295                                 break;
1296                         case PAPER_B3:
1297                         case PAPER_B4:
1298                         case PAPER_CUSTOM:
1299                                 break;
1300                         }
1301                 }
1302                 docstring const g_options = trim(ods.str(), ",");
1303                 os << "\\usepackage";
1304                 if (!g_options.empty())
1305                         os << '[' << g_options << ']';
1306                 os << "{geometry}\n";
1307                 texrow.newline();
1308                 os << "\\geometry{verbose";
1309                 if (!topmargin.empty())
1310                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1311                 if (!bottommargin.empty())
1312                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1313                 if (!leftmargin.empty())
1314                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1315                 if (!rightmargin.empty())
1316                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1317                 if (!headheight.empty())
1318                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1319                 if (!headsep.empty())
1320                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1321                 if (!footskip.empty())
1322                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1323                 if (!columnsep.empty())
1324                         os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1325                 os << "}\n";
1326                 texrow.newline();
1327         } else if (orientation == ORIENTATION_LANDSCAPE) {
1328                 features.require("papersize");
1329         }
1330
1331         if (tokenPos(tclass.opt_pagestyle(),
1332                      '|', pagestyle) >= 0) {
1333                 if (pagestyle == "fancy") {
1334                         os << "\\usepackage{fancyhdr}\n";
1335                         texrow.newline();
1336                 }
1337                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1338                 texrow.newline();
1339         }
1340
1341         // only output when the background color is not white
1342         if (backgroundcolor != lyx::rgbFromHexName("#ffffff")) {
1343                 // only require color here, the background color will be defined
1344                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1345                 // package pdfpages 
1346                 features.require("color");
1347                 features.require("pagecolor");
1348         }
1349
1350         // Only if class has a ToC hierarchy
1351         if (tclass.hasTocLevels()) {
1352                 if (secnumdepth != tclass.secnumdepth()) {
1353                         os << "\\setcounter{secnumdepth}{"
1354                            << secnumdepth
1355                            << "}\n";
1356                         texrow.newline();
1357                 }
1358                 if (tocdepth != tclass.tocdepth()) {
1359                         os << "\\setcounter{tocdepth}{"
1360                            << tocdepth
1361                            << "}\n";
1362                         texrow.newline();
1363                 }
1364         }
1365
1366         if (paragraph_separation) {
1367                 switch (getDefSkip().kind()) {
1368                 case VSpace::SMALLSKIP:
1369                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1370                         break;
1371                 case VSpace::MEDSKIP:
1372                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1373                         break;
1374                 case VSpace::BIGSKIP:
1375                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1376                         break;
1377                 case VSpace::LENGTH:
1378                         os << "\\setlength{\\parskip}{"
1379                            << from_utf8(getDefSkip().length().asLatexString())
1380                            << "}\n";
1381                         break;
1382                 default: // should never happen // Then delete it.
1383                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1384                         break;
1385                 }
1386                 texrow.newline();
1387
1388                 os << "\\setlength{\\parindent}{0pt}\n";
1389                 texrow.newline();
1390         }
1391
1392         // Now insert the LyX specific LaTeX commands...
1393         docstring lyxpreamble;
1394
1395         // due to interferences with babel and hyperref, the color package has to
1396         // be loaded (when it is not already loaded) before babel when hyperref
1397         // is used with the colorlinks option, see
1398         // http://bugzilla.lyx.org/show_bug.cgi?id=5291
1399         // we decided therefore to load color always before babel, see
1400         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1401         lyxpreamble += from_ascii(features.getColorOptions());
1402         
1403         // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1404         if (use_babel
1405                 && (features.isRequired("jurabib")
1406                         || features.isRequired("hyperref")
1407                         || features.isRequired("vietnamese")
1408                         || features.isRequired("japanese") ) ) {
1409                                 // FIXME UNICODE
1410                                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1411                                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1412         }
1413
1414         // The optional packages;
1415         lyxpreamble += from_ascii(features.getPackages());
1416
1417         // Additional Indices
1418         if (features.isRequired("splitidx")) {
1419                 IndicesList::const_iterator iit = indiceslist().begin();
1420                 IndicesList::const_iterator iend = indiceslist().end();
1421                 for (; iit != iend; ++iit) {
1422                         lyxpreamble += "\\newindex[";
1423                         lyxpreamble += iit->index();
1424                         lyxpreamble += "]{";
1425                         lyxpreamble += iit->shortcut();
1426                         lyxpreamble += "}\n";
1427                 }
1428         }
1429
1430         // Line spacing
1431         lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1432
1433         // PDF support.
1434         // * Hyperref manual: "Make sure it comes last of your loaded
1435         //   packages, to give it a fighting chance of not being over-written,
1436         //   since its job is to redefine many LaTeX commands."
1437         // * Email from Heiko Oberdiek: "It is usually better to load babel
1438         //   before hyperref. Then hyperref has a chance to detect babel.
1439         // * Has to be loaded before the "LyX specific LaTeX commands" to
1440         //   avoid errors with algorithm floats.
1441         // use hyperref explicitely when it is required
1442         if (features.isRequired("hyperref")) {
1443                 odocstringstream oss;
1444                 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1445                 lyxpreamble += oss.str();
1446         }
1447         
1448         // Will be surrounded by \makeatletter and \makeatother when needed
1449         docstring atlyxpreamble;
1450
1451         // Some macros LyX will need
1452         docstring tmppreamble(from_ascii(features.getMacros()));
1453
1454         if (!tmppreamble.empty())
1455                 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1456                         "LyX specific LaTeX commands.\n"
1457                         + tmppreamble + '\n';
1458
1459         // the text class specific preamble
1460         tmppreamble = features.getTClassPreamble();
1461         if (!tmppreamble.empty())
1462                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1463                         "Textclass specific LaTeX commands.\n"
1464                         + tmppreamble + '\n';
1465
1466         /* the user-defined preamble */
1467         if (!preamble.empty())
1468                 // FIXME UNICODE
1469                 atlyxpreamble += from_utf8(preamble);
1470
1471         // subfig loads internally the LaTeX package "caption". As
1472         // caption is a very popular package, users will load it in
1473         // the preamble. Therefore we must load subfig behind the
1474         // user-defined preamble and check if the caption package was
1475         // loaded or not. For the case that caption is loaded before
1476         // subfig, there is the subfig option "caption=false". This
1477         // option also works when a koma-script class is used and
1478         // koma's own caption commands are used instead of caption. We
1479         // use \PassOptionsToPackage here because the user could have
1480         // already loaded subfig in the preamble.
1481         if (features.isRequired("subfig")) {
1482                 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1483                         " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1484                         "\\usepackage{subfig}\n";
1485         }
1486
1487         // Itemize bullet settings need to be last in case the user
1488         // defines their own bullets that use a package included
1489         // in the user-defined preamble -- ARRae
1490         // Actually it has to be done much later than that
1491         // since some packages like frenchb make modifications
1492         // at \begin{document} time -- JMarc
1493         docstring bullets_def;
1494         for (int i = 0; i < 4; ++i) {
1495                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1496                         if (bullets_def.empty())
1497                                 bullets_def += "\\AtBeginDocument{\n";
1498                         bullets_def += "  \\def\\labelitemi";
1499                         switch (i) {
1500                                 // `i' is one less than the item to modify
1501                         case 0:
1502                                 break;
1503                         case 1:
1504                                 bullets_def += 'i';
1505                                 break;
1506                         case 2:
1507                                 bullets_def += "ii";
1508                                 break;
1509                         case 3:
1510                                 bullets_def += 'v';
1511                                 break;
1512                         }
1513                         bullets_def += '{' +
1514                                 user_defined_bullet(i).getText()
1515                                 + "}\n";
1516                 }
1517         }
1518
1519         if (!bullets_def.empty())
1520                 atlyxpreamble += bullets_def + "}\n\n";
1521
1522         lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1523                         "User specified LaTeX commands.\n";
1524
1525         // Check whether we should change the catcode of '@' in the preamble.
1526         // We do it when '@' explicitly appears and, as a safety measure, also
1527         // when an external file is included.
1528         if (atlyxpreamble.find(from_ascii("@")) != docstring::npos
1529             || atlyxpreamble.find(from_ascii("\\input")) != docstring::npos
1530             || atlyxpreamble.find(from_ascii("\\include")) != docstring::npos)
1531                 lyxpreamble += "\\makeatletter\n"
1532                         + atlyxpreamble + "\\makeatother\n\n";
1533         else
1534                 lyxpreamble += atlyxpreamble + '\n';
1535
1536         // We try to load babel late, in case it interferes with other packages.
1537         // Jurabib and Hyperref have to be called after babel, though.
1538         if (use_babel && !features.isRequired("jurabib")
1539             && !features.isRequired("hyperref")
1540             && !features.isRequired("vietnamese")
1541             && !features.isRequired("japanese")) {
1542                 // FIXME UNICODE
1543                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1544                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1545         }
1546
1547         docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1548         if (!i18npreamble.empty())
1549                 lyxpreamble += i18npreamble + '\n';
1550
1551         int const nlines =
1552                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1553         for (int j = 0; j != nlines; ++j) {
1554                 texrow.newline();
1555         }
1556
1557         os << lyxpreamble;
1558
1559         // these packages (xunicode, for that matter) need to be loaded at least
1560         // after amsmath, amssymb, esint and the other packages that provide 
1561         // special glyphs
1562         if (useXetex) {
1563                 os << "\\usepackage{xunicode}\n";
1564                 texrow.newline();
1565                 os << "\\usepackage{xltxtra}\n";
1566                 texrow.newline();
1567         }
1568         return use_babel;
1569 }
1570
1571
1572 void BufferParams::useClassDefaults()
1573 {
1574         DocumentClass const & tclass = documentClass();
1575
1576         sides = tclass.sides();
1577         columns = tclass.columns();
1578         pagestyle = tclass.pagestyle();
1579         use_default_options = true;
1580         // Only if class has a ToC hierarchy
1581         if (tclass.hasTocLevels()) {
1582                 secnumdepth = tclass.secnumdepth();
1583                 tocdepth = tclass.tocdepth();
1584         }
1585 }
1586
1587
1588 bool BufferParams::hasClassDefaults() const
1589 {
1590         DocumentClass const & tclass = documentClass();
1591
1592         return sides == tclass.sides()
1593                 && columns == tclass.columns()
1594                 && pagestyle == tclass.pagestyle()
1595                 && use_default_options
1596                 && secnumdepth == tclass.secnumdepth()
1597                 && tocdepth == tclass.tocdepth();
1598 }
1599
1600
1601 DocumentClass const & BufferParams::documentClass() const
1602 {
1603         return *doc_class_;
1604 }
1605
1606
1607 DocumentClass const * BufferParams::documentClassPtr() const {
1608         return doc_class_;
1609 }
1610
1611
1612 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1613         // evil, but this function is evil
1614         doc_class_ = const_cast<DocumentClass *>(tc);
1615 }
1616
1617
1618 bool BufferParams::setBaseClass(string const & classname)
1619 {
1620         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1621         LayoutFileList & bcl = LayoutFileList::get();
1622         if (!bcl.haveClass(classname)) {
1623                 docstring s = 
1624                         bformat(_("The document class %1$s could not be found. "
1625                                 "A default textclass with default layouts will be used. "
1626                                 "LyX might not be able to produce output unless a correct "
1627                                 "textclass is selected from the document settings dialog."),
1628                         from_utf8(classname));
1629                 frontend::Alert::error(_("Document class not found"), s);
1630                 bcl.addEmptyClass(classname);
1631         }
1632
1633         bool const success = bcl[classname].load();
1634         if (!success) {
1635                 docstring s = 
1636                         bformat(_("The document class %1$s could not be loaded."),
1637                         from_utf8(classname));
1638                 frontend::Alert::error(_("Could not load class"), s);
1639                 return false;
1640         }
1641
1642         pimpl_->baseClass_ = classname;
1643         layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1644         return true;
1645 }
1646
1647
1648 LayoutFile const * BufferParams::baseClass() const
1649 {
1650         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1651                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1652         else 
1653                 return 0;
1654 }
1655
1656
1657 LayoutFileIndex const & BufferParams::baseClassID() const
1658 {
1659         return pimpl_->baseClass_;
1660 }
1661
1662
1663 void BufferParams::makeDocumentClass()
1664 {
1665         if (!baseClass())
1666                 return;
1667
1668         doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1669
1670         if (!local_layout.empty()) {
1671                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1672                         docstring const msg = _("Error reading internal layout information");
1673                         frontend::Alert::warning(_("Read Error"), msg);
1674                 }
1675         }
1676 }
1677
1678 bool BufferParams::moduleCanBeAdded(string const & modName) const
1679 {
1680         return layoutModules_.moduleCanBeAdded(modName, baseClass());
1681 }
1682
1683
1684 bool BufferParams::addLayoutModule(string const & modName)
1685 {
1686         LayoutModuleList::const_iterator it = layoutModules_.begin();
1687         LayoutModuleList::const_iterator end = layoutModules_.end();
1688         for (; it != end; it++)
1689                 if (*it == modName) 
1690                         return false;
1691         layoutModules_.push_back(modName);
1692         return true;
1693 }
1694
1695
1696 Font const BufferParams::getFont() const
1697 {
1698         FontInfo f = documentClass().defaultfont();
1699         if (fontsDefaultFamily == "rmdefault")
1700                 f.setFamily(ROMAN_FAMILY);
1701         else if (fontsDefaultFamily == "sfdefault")
1702                 f.setFamily(SANS_FAMILY);
1703         else if (fontsDefaultFamily == "ttdefault")
1704                 f.setFamily(TYPEWRITER_FAMILY);
1705         return Font(f, language);
1706 }
1707
1708
1709 void BufferParams::readPreamble(Lexer & lex)
1710 {
1711         if (lex.getString() != "\\begin_preamble")
1712                 lyxerr << "Error (BufferParams::readPreamble):"
1713                         "consistency check failed." << endl;
1714
1715         preamble = lex.getLongString("\\end_preamble");
1716 }
1717
1718
1719 void BufferParams::readLocalLayout(Lexer & lex)
1720 {
1721         if (lex.getString() != "\\begin_local_layout")
1722                 lyxerr << "Error (BufferParams::readLocalLayout):"
1723                         "consistency check failed." << endl;
1724
1725         local_layout = lex.getLongString("\\end_local_layout");
1726 }
1727
1728
1729 void BufferParams::readLanguage(Lexer & lex)
1730 {
1731         if (!lex.next()) return;
1732
1733         string const tmptok = lex.getString();
1734
1735         // check if tmptok is part of tex_babel in tex-defs.h
1736         language = languages.getLanguage(tmptok);
1737         if (!language) {
1738                 // Language tmptok was not found
1739                 language = default_language;
1740                 lyxerr << "Warning: Setting language `"
1741                        << tmptok << "' to `" << language->lang()
1742                        << "'." << endl;
1743         }
1744 }
1745
1746
1747 void BufferParams::readGraphicsDriver(Lexer & lex)
1748 {
1749         if (!lex.next()) 
1750                 return;
1751
1752         string const tmptok = lex.getString();
1753         // check if tmptok is part of tex_graphics in tex_defs.h
1754         int n = 0;
1755         while (true) {
1756                 string const test = tex_graphics[n++];
1757
1758                 if (test == tmptok) {
1759                         graphicsDriver = tmptok;
1760                         break;
1761                 }
1762                 if (test.empty()) {
1763                         lex.printError(
1764                                 "Warning: graphics driver `$$Token' not recognized!\n"
1765                                 "         Setting graphics driver to `default'.\n");
1766                         graphicsDriver = "default";
1767                         break;
1768                 }
1769         }
1770 }
1771
1772
1773 void BufferParams::readBullets(Lexer & lex)
1774 {
1775         if (!lex.next()) 
1776                 return;
1777
1778         int const index = lex.getInteger();
1779         lex.next();
1780         int temp_int = lex.getInteger();
1781         user_defined_bullet(index).setFont(temp_int);
1782         temp_bullet(index).setFont(temp_int);
1783         lex >> temp_int;
1784         user_defined_bullet(index).setCharacter(temp_int);
1785         temp_bullet(index).setCharacter(temp_int);
1786         lex >> temp_int;
1787         user_defined_bullet(index).setSize(temp_int);
1788         temp_bullet(index).setSize(temp_int);
1789 }
1790
1791
1792 void BufferParams::readBulletsLaTeX(Lexer & lex)
1793 {
1794         // The bullet class should be able to read this.
1795         if (!lex.next()) 
1796                 return;
1797         int const index = lex.getInteger();
1798         lex.next(true);
1799         docstring const temp_str = lex.getDocString();
1800
1801         user_defined_bullet(index).setText(temp_str);
1802         temp_bullet(index).setText(temp_str);
1803 }
1804
1805
1806 void BufferParams::readModules(Lexer & lex)
1807 {
1808         if (!lex.eatLine()) {
1809                 lyxerr << "Error (BufferParams::readModules):"
1810                                 "Unexpected end of input." << endl;
1811                 return;
1812         }
1813         while (true) {
1814                 string mod = lex.getString();
1815                 if (mod == "\\end_modules")
1816                         break;
1817                 addLayoutModule(mod);
1818                 lex.eatLine();
1819         }
1820 }
1821
1822
1823 void BufferParams::readRemovedModules(Lexer & lex)
1824 {
1825         if (!lex.eatLine()) {
1826                 lyxerr << "Error (BufferParams::readRemovedModules):"
1827                                 "Unexpected end of input." << endl;
1828                 return;
1829         }
1830         while (true) {
1831                 string mod = lex.getString();
1832                 if (mod == "\\end_removed_modules")
1833                         break;
1834                 removedModules_.push_back(mod);
1835                 lex.eatLine();
1836         }
1837         // now we want to remove any removed modules that were previously 
1838         // added. normally, that will be because default modules were added in 
1839         // setBaseClass(), which gets called when \textclass is read at the 
1840         // start of the read.
1841         list<string>::const_iterator rit = removedModules_.begin();
1842         list<string>::const_iterator const ren = removedModules_.end();
1843         for (; rit != ren; rit++) {
1844                 LayoutModuleList::iterator const mit = layoutModules_.begin();
1845                 LayoutModuleList::iterator const men = layoutModules_.end();
1846                 LayoutModuleList::iterator found = find(mit, men, *rit);
1847                 if (found == men)
1848                         continue;
1849                 layoutModules_.erase(found);
1850         }
1851 }
1852
1853
1854 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1855 {
1856         char real_papersize = papersize;
1857         if (real_papersize == PAPER_DEFAULT)
1858                 real_papersize = lyxrc.default_papersize;
1859
1860         switch (real_papersize) {
1861         case PAPER_DEFAULT:
1862                 // could be anything, so don't guess
1863                 return string();
1864         case PAPER_CUSTOM: {
1865                 if (purpose == XDVI && !paperwidth.empty() &&
1866                     !paperheight.empty()) {
1867                         // heightxwidth<unit>
1868                         string first = paperwidth;
1869                         string second = paperheight;
1870                         if (orientation == ORIENTATION_LANDSCAPE)
1871                                 first.swap(second);
1872                         // cut off unit.
1873                         return first.erase(first.length() - 2)
1874                                 + "x" + second;
1875                 }
1876                 return string();
1877         }
1878         case PAPER_A3:
1879                 return "a3";
1880         case PAPER_A4:
1881                 return "a4";
1882         case PAPER_A5:
1883                 return "a5";
1884         case PAPER_B3:
1885                 // dvips and dvipdfm do not know this
1886                 if (purpose == DVIPS || purpose == DVIPDFM)
1887                         return string();
1888                 return "b3";
1889         case PAPER_B4:
1890                 // dvipdfm does not know this
1891                 if (purpose == DVIPDFM)
1892                         return string();
1893                 return "b4";
1894         case PAPER_B5:
1895                 // dvipdfm does not know this
1896                 if (purpose == DVIPDFM)
1897                         return string();
1898                 return "b5";
1899         case PAPER_USEXECUTIVE:
1900                 // dvipdfm does not know this
1901                 if (purpose == DVIPDFM)
1902                         return string();
1903                 return "foolscap";
1904         case PAPER_USLEGAL:
1905                 return "legal";
1906         case PAPER_USLETTER:
1907         default:
1908                 if (purpose == XDVI)
1909                         return "us";
1910                 return "letter";
1911         }
1912 }
1913
1914
1915 string const BufferParams::dvips_options() const
1916 {
1917         string result;
1918
1919         if (use_geometry
1920             && papersize == PAPER_CUSTOM
1921             && !lyxrc.print_paper_dimension_flag.empty()
1922             && !paperwidth.empty()
1923             && !paperheight.empty()) {
1924                 // using a custom papersize
1925                 result = lyxrc.print_paper_dimension_flag;
1926                 result += ' ' + paperwidth;
1927                 result += ',' + paperheight;
1928         } else {
1929                 string const paper_option = paperSizeName(DVIPS);
1930                 if (!paper_option.empty() && (paper_option != "letter" ||
1931                     orientation != ORIENTATION_LANDSCAPE)) {
1932                         // dvips won't accept -t letter -t landscape.
1933                         // In all other cases, include the paper size
1934                         // explicitly.
1935                         result = lyxrc.print_paper_flag;
1936                         result += ' ' + paper_option;
1937                 }
1938         }
1939         if (orientation == ORIENTATION_LANDSCAPE &&
1940             papersize != PAPER_CUSTOM)
1941                 result += ' ' + lyxrc.print_landscape_flag;
1942         return result;
1943 }
1944
1945
1946 string BufferParams::babelCall(string const & lang_opts) const
1947 {
1948         string lang_pack = lyxrc.language_package;
1949         if (lang_pack != "\\usepackage{babel}")
1950                 return lang_pack;
1951         // suppress the babel call when there is no babel language defined
1952         // for the document language in the lib/languages file and if no
1953         // other languages are used (lang_opts is then empty)
1954         if (lang_opts.empty())
1955                 return string();
1956         // If Vietnamese is used, babel must directly be loaded with the
1957         // language options, see
1958         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1959         size_t viet = lang_opts.find("vietnam");
1960         // viet = string::npos when not found
1961         // the same is for all other languages that are not directly supported by
1962         // babel, but where LaTeX-packages add babel support.
1963         // this is currently the case for Latvian, Lithuanian, and Mongolian
1964         size_t latvian = lang_opts.find("latvian");
1965         size_t lithu = lang_opts.find("lithuanian");
1966         size_t mongo = lang_opts.find("mongolian");
1967         // If Japanese is used, babel must directly be loaded with the
1968         // language options, see
1969         // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1970         size_t japan = lang_opts.find("japanese");
1971         if (!lyxrc.language_global_options || viet != string::npos
1972                 || japan != string::npos || latvian != string::npos
1973                 || lithu != string::npos || mongo != string::npos)
1974                 return "\\usepackage[" + lang_opts + "]{babel}";
1975         return lang_pack;
1976 }
1977
1978
1979 docstring BufferParams::getGraphicsDriver(string const & package) const
1980 {
1981         docstring result;
1982
1983         if (package == "geometry") {
1984                 if (graphicsDriver == "dvips"
1985                     || graphicsDriver == "dvipdfm"
1986                     || graphicsDriver == "pdftex"
1987                     || graphicsDriver == "vtex")
1988                         result = from_ascii(graphicsDriver);
1989                 else if (graphicsDriver == "dvipdfmx")
1990                         result = from_ascii("dvipdfm");
1991         }
1992
1993         return result;
1994 }
1995
1996
1997 void BufferParams::writeEncodingPreamble(odocstream & os,
1998                 LaTeXFeatures & features, TexRow & texrow) const
1999 {
2000         if (useXetex)
2001                 return;
2002         if (inputenc == "auto") {
2003                 string const doc_encoding =
2004                         language->encoding()->latexName();
2005                 Encoding::Package const package =
2006                         language->encoding()->package();
2007
2008                 // Create a list with all the input encodings used
2009                 // in the document
2010                 set<string> encodings =
2011                         features.getEncodingSet(doc_encoding);
2012
2013                 // If the "japanese" package (i.e. pLaTeX) is used,
2014                 // inputenc must be omitted.
2015                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2016                 if (package == Encoding::japanese)
2017                      features.require("japanese");
2018
2019                 if ((!encodings.empty() || package == Encoding::inputenc)
2020                     && !features.isRequired("japanese")) {
2021                         os << "\\usepackage[";
2022                         set<string>::const_iterator it = encodings.begin();
2023                         set<string>::const_iterator const end = encodings.end();
2024                         if (it != end) {
2025                                 os << from_ascii(*it);
2026                                 ++it;
2027                         }
2028                         for (; it != end; ++it)
2029                                 os << ',' << from_ascii(*it);
2030                         if (package == Encoding::inputenc) {
2031                                 if (!encodings.empty())
2032                                         os << ',';
2033                                 os << from_ascii(doc_encoding);
2034                         }
2035                         os << "]{inputenc}\n";
2036                         texrow.newline();
2037                 }
2038                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2039                         if (language->encoding()->name() == "utf8-cjk"
2040                             && LaTeXFeatures::isAvailable("CJKutf8"))
2041                                 os << "\\usepackage{CJKutf8}\n";
2042                         else
2043                                 os << "\\usepackage{CJK}\n";
2044                         texrow.newline();
2045                 }
2046         } else if (inputenc != "default") {
2047                 switch (encoding().package()) {
2048                 case Encoding::none:
2049                 case Encoding::japanese:
2050                         break;
2051                 case Encoding::inputenc:
2052                         // do not load inputenc if japanese is used
2053                         if (features.isRequired("japanese"))
2054                                 break;
2055                         os << "\\usepackage[" << from_ascii(inputenc)
2056                            << "]{inputenc}\n";
2057                         texrow.newline();
2058                         break;
2059                 case Encoding::CJK:
2060                         if (encoding().name() == "utf8-cjk"
2061                             && LaTeXFeatures::isAvailable("CJKutf8"))
2062                                 os << "\\usepackage{CJKutf8}\n";
2063                         else
2064                                 os << "\\usepackage{CJK}\n";
2065                         texrow.newline();
2066                         break;
2067                 }
2068         }
2069
2070         // The encoding "armscii8" (for Armenian) is only available when
2071         // the package "armtex" is loaded.
2072         if (language->encoding()->latexName() == "armscii8"
2073             || inputenc == "armscii8") {
2074                 os << "\\usepackage{armtex}\n";
2075                 texrow.newline();
2076         }
2077 }
2078
2079
2080 string const BufferParams::parseFontName(string const & name) const
2081 {
2082         string mangled = name;
2083         size_t const idx = mangled.find('[');
2084         if (idx == string::npos || idx == 0)
2085                 return mangled;
2086         else
2087                 return mangled.substr(0, idx - 1);
2088 }
2089
2090
2091 string const BufferParams::loadFonts(string const & rm,
2092                                      string const & sf, string const & tt,
2093                                      bool const & sc, bool const & osf,
2094                                      int const & sfscale, int const & ttscale,
2095                                      bool const & xetex) const
2096 {
2097         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2098            several packages have been replaced by others, that might not
2099            be installed on every system. We have to take care for that
2100            (see psnfss.pdf). We try to support all psnfss fonts as well
2101            as the fonts that have become de facto standard in the LaTeX
2102            world (e.g. Latin Modern). We do not support obsolete fonts
2103            (like PSLatex). In general, it should be possible to mix any
2104            rm font with any sf or tt font, respectively. (JSpitzm)
2105            TODO:
2106                 -- separate math fonts.
2107         */
2108
2109         if (rm == "default" && sf == "default" && tt == "default")
2110                 //nothing to do
2111                 return string();
2112
2113         ostringstream os;
2114
2115         if (xetex) {
2116                 if (rm != "default")
2117                         os << "\\setmainfont[Mapping=tex-text]{"
2118                            << parseFontName(rm) << "}\n";
2119                 if (sf != "default") {
2120                         string const sans = parseFontName(sf);
2121                         if (sfscale != 100)
2122                                 os << "\\setsansfont[Scale=" 
2123                                    << float(sfscale) / 100 
2124                                    << ",Mapping=tex-text]{"
2125                                    << sans << "}\n";
2126                         else
2127                                 os << "\\setsansfont[Mapping=tex-text]{"
2128                                    << sans << "}\n";
2129                 }
2130                 if (tt != "default") {
2131                         string const mono = parseFontName(tt);
2132                         if (ttscale != 100)
2133                                 os << "\\setmonofont[Scale=" 
2134                                    << float(sfscale) / 100 
2135                                    << "]{"
2136                                    << mono << "}\n";
2137                         else
2138                                 os << "\\setmonofont[Mapping=tex-text]{"
2139                                    << mono << "}\n";
2140                 }
2141                 if (osf)
2142                         os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2143                 return os.str();
2144         }
2145
2146         // ROMAN FONTS
2147         // Computer Modern (must be explicitely selectable -- there might be classes
2148         // that define a different default font!
2149         if (rm == "cmr") {
2150                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2151                 // osf for Computer Modern needs eco.sty
2152                 if (osf)
2153                         os << "\\usepackage{eco}\n";
2154         }
2155         // Latin Modern Roman
2156         else if (rm == "lmodern")
2157                 os << "\\usepackage{lmodern}\n";
2158         // AE
2159         else if (rm == "ae") {
2160                 // not needed when using OT1 font encoding.
2161                 if (lyxrc.fontenc != "default")
2162                         os << "\\usepackage{ae,aecompl}\n";
2163         }
2164         // Times
2165         else if (rm == "times") {
2166                 // try to load the best available package
2167                 if (LaTeXFeatures::isAvailable("mathptmx"))
2168                         os << "\\usepackage{mathptmx}\n";
2169                 else if (LaTeXFeatures::isAvailable("mathptm"))
2170                         os << "\\usepackage{mathptm}\n";
2171                 else
2172                         os << "\\usepackage{times}\n";
2173         }
2174         // Palatino
2175         else if (rm == "palatino") {
2176                 // try to load the best available package
2177                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2178                         os << "\\usepackage";
2179                         if (osf || sc) {
2180                                 os << '[';
2181                                 if (!osf)
2182                                         os << "sc";
2183                                 else
2184                                         // "osf" includes "sc"!
2185                                         os << "osf";
2186                                 os << ']';
2187                         }
2188                         os << "{mathpazo}\n";
2189                 }
2190                 else if (LaTeXFeatures::isAvailable("mathpple"))
2191                         os << "\\usepackage{mathpple}\n";
2192                 else
2193                         os << "\\usepackage{palatino}\n";
2194         }
2195         // Utopia
2196         else if (rm == "utopia") {
2197                 // fourier supersedes utopia.sty, but does
2198                 // not work with OT1 encoding.
2199                 if (LaTeXFeatures::isAvailable("fourier")
2200                     && lyxrc.fontenc != "default") {
2201                         os << "\\usepackage";
2202                         if (osf || sc) {
2203                                 os << '[';
2204                                 if (sc)
2205                                         os << "expert";
2206                                 if (osf && sc)
2207                                         os << ',';
2208                                 if (osf)
2209                                         os << "oldstyle";
2210                                 os << ']';
2211                         }
2212                         os << "{fourier}\n";
2213                 }
2214                 else
2215                         os << "\\usepackage{utopia}\n";
2216         }
2217         // Bera (complete fontset)
2218         else if (rm == "bera" && sf == "default" && tt == "default")
2219                 os << "\\usepackage{bera}\n";
2220         // everything else
2221         else if (rm != "default")
2222                 os << "\\usepackage" << "{" << rm << "}\n";
2223
2224         // SANS SERIF
2225         // Helvetica, Bera Sans
2226         if (sf == "helvet" || sf == "berasans") {
2227                 if (sfscale != 100)
2228                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2229                            << "]{" << sf << "}\n";
2230                 else
2231                         os << "\\usepackage{" << sf << "}\n";
2232         }
2233         // Avant Garde
2234         else if (sf == "avant")
2235                 os << "\\usepackage{" << sf << "}\n";
2236         // Computer Modern, Latin Modern, CM Bright
2237         else if (sf != "default")
2238                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2239
2240         // monospaced/typewriter
2241         // Courier, LuxiMono
2242         if (tt == "luximono" || tt == "beramono") {
2243                 if (ttscale != 100)
2244                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2245                            << "]{" << tt << "}\n";
2246                 else
2247                         os << "\\usepackage{" << tt << "}\n";
2248         }
2249         // Courier
2250         else if (tt == "courier" )
2251                 os << "\\usepackage{" << tt << "}\n";
2252         // Computer Modern, Latin Modern, CM Bright
2253         else if (tt != "default")
2254                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2255
2256         return os.str();
2257 }
2258
2259
2260 Encoding const & BufferParams::encoding() const
2261 {
2262         if (useXetex)
2263                 return *(encodings.fromLaTeXName("utf8-plain"));
2264         if (inputenc == "auto" || inputenc == "default")
2265                 return *language->encoding();
2266         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2267         if (enc)
2268                 return *enc;
2269         LYXERR0("Unknown inputenc value `" << inputenc
2270                << "'. Using `auto' instead.");
2271         return *language->encoding();
2272 }
2273
2274
2275 CiteEngine BufferParams::citeEngine() const
2276 {
2277         // FIXME the class should provide the numerical/
2278         // authoryear choice
2279         if (documentClass().provides("natbib")
2280             && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2281                 return ENGINE_NATBIB_AUTHORYEAR;
2282         return cite_engine_;
2283 }
2284
2285
2286 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2287 {
2288         cite_engine_ = cite_engine;
2289 }
2290
2291 } // namespace lyx