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