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