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