]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
export when building vld
[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 "BranchList.h"
22 #include "buffer_funcs.h"
23 #include "Bullet.h"
24 #include "Color.h"
25 #include "Encoding.h"
26 #include "Language.h"
27 #include "LaTeXFeatures.h"
28 #include "ModuleList.h"
29 #include "Font.h"
30 #include "Lexer.h"
31 #include "LyXRC.h"
32 #include "TextClassList.h"
33 #include "OutputParams.h"
34 #include "Spacing.h"
35 #include "TexRow.h"
36 #include "VSpace.h"
37 #include "PDFOptions.h"
38
39 #include "frontends/alert.h"
40
41 #include "insets/InsetListingsParams.h"
42
43 #include "support/convert.h"
44 #include "support/debug.h"
45 #include "support/docstream.h"
46 #include "support/FileName.h"
47 #include "support/filetools.h"
48 #include "support/gettext.h"
49 #include "support/Messages.h"
50 #include "support/Translator.h"
51 #include "support/lstrings.h"
52
53 #include <algorithm>
54 #include <sstream>
55
56 using std::count;
57 using std::endl;
58 using std::find;
59 using std::string;
60 using std::istringstream;
61 using std::ostream;
62 using std::ostringstream;
63 using std::pair;
64 using std::string;
65 using lyx::support::FileName;
66 using lyx::support::libFileSearch;
67 using lyx::support::bformat;
68 using lyx::support::rtrim;
69 using lyx::support::tokenPos;
70 using lyx::support::prefixIs;
71
72
73 static char const * const string_paragraph_separation[] = {
74         "indent", "skip", ""
75 };
76
77
78 static char const * const string_quotes_language[] = {
79         "english", "swedish", "german", "polish", "french", "danish", ""
80 };
81
82
83 static char const * const string_papersize[] = {
84         "default", "custom", "letterpaper", "executivepaper", "legalpaper",
85         "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
86 };
87
88
89 static char const * const string_orientation[] = {
90         "portrait", "landscape", ""
91 };
92
93
94 static char const * const string_footnotekinds[] = {
95         "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
96 };
97
98
99 static char const * const tex_graphics[] = {
100         "default", "dvips", "dvitops", "emtex",
101         "ln", "oztex", "textures", "none", ""
102 };
103
104
105 namespace lyx {
106
107 // Local translators
108 namespace {
109
110 // Paragraph separation
111 typedef Translator<string, BufferParams::PARSEP> ParSepTranslator;
112
113
114 ParSepTranslator const init_parseptranslator()
115 {
116         ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
117         translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
118         return translator;
119 }
120
121
122 ParSepTranslator const & parseptranslator()
123 {
124         static ParSepTranslator translator = init_parseptranslator();
125         return translator;
126 }
127
128
129 // Quotes language
130 typedef Translator<string, InsetQuotes::quote_language> QuotesLangTranslator;
131
132
133 QuotesLangTranslator const init_quoteslangtranslator()
134 {
135         QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
136         translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
137         translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
138         translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
139         translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
140         translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
141         return translator;
142 }
143
144
145 QuotesLangTranslator const & quoteslangtranslator()
146 {
147         static QuotesLangTranslator translator = init_quoteslangtranslator();
148         return translator;
149 }
150
151
152 // Paper size
153 typedef Translator<std::string, PAPER_SIZE> PaperSizeTranslator;
154
155
156 PaperSizeTranslator const init_papersizetranslator()
157 {
158         PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
159         translator.addPair(string_papersize[1], PAPER_CUSTOM);
160         translator.addPair(string_papersize[2], PAPER_USLETTER);
161         translator.addPair(string_papersize[3], PAPER_USLEGAL);
162         translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
163         translator.addPair(string_papersize[5], PAPER_A3);
164         translator.addPair(string_papersize[6], PAPER_A4);
165         translator.addPair(string_papersize[7], PAPER_A5);
166         translator.addPair(string_papersize[8], PAPER_B3);
167         translator.addPair(string_papersize[9], PAPER_B4);
168         translator.addPair(string_papersize[10], PAPER_B5);
169         return translator;
170 }
171
172
173 PaperSizeTranslator const & papersizetranslator()
174 {
175         static PaperSizeTranslator translator = init_papersizetranslator();
176         return translator;
177 }
178
179
180 // Paper orientation
181 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
182
183
184 PaperOrientationTranslator const init_paperorientationtranslator()
185 {
186         PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
187         translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
188         return translator;
189 }
190
191
192 PaperOrientationTranslator const & paperorientationtranslator()
193 {
194         static PaperOrientationTranslator translator = init_paperorientationtranslator();
195         return translator;
196 }
197
198
199 // Page sides
200 typedef Translator<int, PageSides> SidesTranslator;
201
202
203 SidesTranslator const init_sidestranslator()
204 {
205         SidesTranslator translator(1, OneSide);
206         translator.addPair(2, TwoSides);
207         return translator;
208 }
209
210
211 SidesTranslator const & sidestranslator()
212 {
213         static SidesTranslator translator = init_sidestranslator();
214         return translator;
215 }
216
217
218 // LaTeX packages
219 typedef Translator<int, BufferParams::Package> PackageTranslator;
220
221
222 PackageTranslator const init_packagetranslator()
223 {
224         PackageTranslator translator(0, BufferParams::package_off);
225         translator.addPair(1, BufferParams::package_auto);
226         translator.addPair(2, BufferParams::package_on);
227         return translator;
228 }
229
230
231 PackageTranslator const & packagetranslator()
232 {
233         static PackageTranslator translator = init_packagetranslator();
234         return translator;
235 }
236
237
238 // Cite engine
239 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
240
241
242 CiteEngineTranslator const init_citeenginetranslator()
243 {
244         CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
245         translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
246         translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
247         translator.addPair("jurabib", biblio::ENGINE_JURABIB);
248         return translator;
249 }
250
251
252 CiteEngineTranslator const & citeenginetranslator()
253 {
254         static CiteEngineTranslator translator = init_citeenginetranslator();
255         return translator;
256 }
257
258
259 // Spacing
260 typedef Translator<string, Spacing::Space> SpaceTranslator;
261
262
263 SpaceTranslator const init_spacetranslator()
264 {
265         SpaceTranslator translator("default", Spacing::Default);
266         translator.addPair("single", Spacing::Single);
267         translator.addPair("onehalf", Spacing::Onehalf);
268         translator.addPair("double", Spacing::Double);
269         translator.addPair("other", Spacing::Other);
270         return translator;
271 }
272
273
274 SpaceTranslator const & spacetranslator()
275 {
276         static SpaceTranslator translator = init_spacetranslator();
277         return translator;
278 }
279
280
281 } // anon namespace
282
283
284 class BufferParams::Impl
285 {
286 public:
287         Impl();
288
289         AuthorList authorlist;
290         BranchList branchlist;
291         Bullet temp_bullets[4];
292         Bullet user_defined_bullets[4];
293         Spacing spacing;
294         /** This is the amount of space used for paragraph_separation "skip",
295          * and for detached paragraphs in "indented" documents.
296          */
297         VSpace defskip;
298         PDFOptions pdfoptions;
299 };
300
301
302 BufferParams::Impl::Impl()
303         : defskip(VSpace::MEDSKIP)
304 {
305         // set initial author
306         // FIXME UNICODE
307         authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
308 }
309
310
311 BufferParams::Impl *
312 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
313 {
314         BOOST_ASSERT(ptr);
315
316         return new BufferParams::Impl(*ptr);
317 }
318
319
320 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
321 {
322         delete ptr;
323 }
324
325
326 BufferParams::BufferParams()
327         : pimpl_(new Impl)
328 {
329         setBaseClass(defaultTextclass());
330         paragraph_separation = PARSEP_INDENT;
331         quotes_language = InsetQuotes::EnglishQ;
332         fontsize = "default";
333
334         /*  PaperLayout */
335         papersize = PAPER_DEFAULT;
336         orientation = ORIENTATION_PORTRAIT;
337         use_geometry = false;
338         use_amsmath = package_auto;
339         use_esint = package_auto;
340         cite_engine_ = biblio::ENGINE_BASIC;
341         use_bibtopic = false;
342         trackChanges = false;
343         outputChanges = false;
344         secnumdepth = 3;
345         tocdepth = 3;
346         language = default_language;
347         fontsRoman = "default";
348         fontsSans = "default";
349         fontsTypewriter = "default";
350         fontsDefaultFamily = "default";
351         fontsSC = false;
352         fontsOSF = false;
353         fontsSansScale = 100;
354         fontsTypewriterScale = 100;
355         inputenc = "auto";
356         graphicsDriver = "default";
357         sides = OneSide;
358         columns = 1;
359         listings_params = string();
360         pagestyle = "default";
361         compressed = false;
362         embedded = false;
363         for (int iter = 0; iter < 4; ++iter) {
364                 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
365                 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
366         }
367 }
368
369
370 BufferParams::~BufferParams()
371 {}
372
373
374 docstring const BufferParams::B_(string const & l10n) const
375 {
376         BOOST_ASSERT(language);
377         return getMessages(language->code()).get(l10n);
378 }
379
380
381 AuthorList & BufferParams::authors()
382 {
383         return pimpl_->authorlist;
384 }
385
386
387 AuthorList const & BufferParams::authors() const
388 {
389         return pimpl_->authorlist;
390 }
391
392
393 BranchList & BufferParams::branchlist()
394 {
395         return pimpl_->branchlist;
396 }
397
398
399 BranchList const & BufferParams::branchlist() const
400 {
401         return pimpl_->branchlist;
402 }
403
404
405 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
406 {
407         BOOST_ASSERT(index < 4);
408         return pimpl_->temp_bullets[index];
409 }
410
411
412 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
413 {
414         BOOST_ASSERT(index < 4);
415         return pimpl_->temp_bullets[index];
416 }
417
418
419 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
420 {
421         BOOST_ASSERT(index < 4);
422         return pimpl_->user_defined_bullets[index];
423 }
424
425
426 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
427 {
428         BOOST_ASSERT(index < 4);
429         return pimpl_->user_defined_bullets[index];
430 }
431
432
433 Spacing & BufferParams::spacing()
434 {
435         return pimpl_->spacing;
436 }
437
438
439 Spacing const & BufferParams::spacing() const
440 {
441         return pimpl_->spacing;
442 }
443
444
445 PDFOptions & BufferParams::pdfoptions()
446 {
447         return pimpl_->pdfoptions;
448 }
449
450
451 PDFOptions const & BufferParams::pdfoptions() const
452 {
453         return pimpl_->pdfoptions;
454 }
455
456
457 VSpace const & BufferParams::getDefSkip() const
458 {
459         return pimpl_->defskip;
460 }
461
462
463 void BufferParams::setDefSkip(VSpace const & vs)
464 {
465         pimpl_->defskip = vs;
466 }
467
468
469 string const BufferParams::readToken(Lexer & lex, string const & token,
470         FileName const & filepath)
471 {
472         if (token == "\\textclass") {
473                 lex.next();
474                 string const classname = lex.getString();
475                 // if there exists a local layout file, ignore the system one
476                 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
477                 pair<bool, lyx::textclass_type> pp;
478                 if (!filepath.empty())
479                         pp = textclasslist.addTextClass(
480                                 classname, filepath.absFilename());
481                 if (pp.first)
482                         setBaseClass(pp.second);
483                 else {
484                         pp = textclasslist.numberOfClass(classname);
485                         if (pp.first)
486                                 setBaseClass(pp.second);
487                         else {
488                                 // a warning will be given for unknown class
489                                 setBaseClass(defaultTextclass());
490                                 return classname;
491                         }
492                 }
493                 // FIXME: this warning will be given even if there exists a local .cls
494                 // file. Even worse, the .lyx file can not be compiled or exported
495                 // because the textclass is marked as unavilable.
496                 if (!getTextClass().isTeXClassAvailable()) {
497                         docstring const msg =
498                                 bformat(_("The layout file requested by this document,\n"
499                                                  "%1$s.layout,\n"
500                                                  "is not usable. This is probably because a LaTeX\n"
501                                                  "class or style file required by it is not\n"
502                                                  "available. See the Customization documentation\n"
503                                                  "for more information.\n"), from_utf8(classname));
504                         frontend::Alert::warning(_("Document class not available"),
505                                        msg + _("LyX will not be able to produce output."));
506                 } 
507                 
508         } else if (token == "\\begin_preamble") {
509                 readPreamble(lex);
510         } else if (token == "\\begin_modules") {
511                 readModules(lex);
512                 makeTextClass();
513         } else if (token == "\\options") {
514                 lex.eatLine();
515                 options = lex.getString();
516         } else if (token == "\\language") {
517                 readLanguage(lex);
518         } else if (token == "\\inputencoding") {
519                 lex >> inputenc;
520         } else if (token == "\\graphics") {
521                 readGraphicsDriver(lex);
522         } else if (token == "\\font_roman") {
523                 lex >> fontsRoman;
524         } else if (token == "\\font_sans") {
525                 lex >> fontsSans;
526         } else if (token == "\\font_typewriter") {
527                 lex >> fontsTypewriter;
528         } else if (token == "\\font_default_family") {
529                 lex >> fontsDefaultFamily;
530         } else if (token == "\\font_sc") {
531                 lex >> fontsSC;
532         } else if (token == "\\font_osf") {
533                 lex >> fontsOSF;
534         } else if (token == "\\font_sf_scale") {
535                 lex >> fontsSansScale;
536         } else if (token == "\\font_tt_scale") {
537                 lex >> fontsTypewriterScale;
538         } else if (token == "\\paragraph_separation") {
539                 string parsep;
540                 lex >> parsep;
541                 paragraph_separation = parseptranslator().find(parsep);
542         } else if (token == "\\defskip") {
543                 lex.next();
544                 pimpl_->defskip = VSpace(lex.getString());
545         } else if (token == "\\quotes_language") {
546                 string quotes_lang;
547                 lex >> quotes_lang;
548                 quotes_language = quoteslangtranslator().find(quotes_lang);
549         } else if (token == "\\papersize") {
550                 string ppsize;
551                 lex >> ppsize;
552                 papersize = papersizetranslator().find(ppsize);
553         } else if (token == "\\use_geometry") {
554                 lex >> use_geometry;
555         } else if (token == "\\use_amsmath") {
556                 int use_ams;
557                 lex >> use_ams;
558                 use_amsmath = packagetranslator().find(use_ams);
559         } else if (token == "\\use_esint") {
560                 int useesint;
561                 lex >> useesint;
562                 use_esint = packagetranslator().find(useesint);
563         } else if (token == "\\cite_engine") {
564                 string engine;
565                 lex >> engine;
566                 cite_engine_ = citeenginetranslator().find(engine);
567         } else if (token == "\\use_bibtopic") {
568                 lex >> use_bibtopic;
569         } else if (token == "\\tracking_changes") {
570                 lex >> trackChanges;
571         } else if (token == "\\output_changes") {
572                 lex >> outputChanges;
573         } else if (token == "\\branch") {
574                 lex.next();
575                 docstring branch = lex.getDocString();
576                 branchlist().add(branch);
577                 while (true) {
578                         lex.next();
579                         string const tok = lex.getString();
580                         if (tok == "\\end_branch")
581                                 break;
582                         Branch * branch_ptr = branchlist().find(branch);
583                         if (tok == "\\selected") {
584                                 lex.next();
585                                 if (branch_ptr)
586                                         branch_ptr->setSelected(lex.getInteger());
587                         }
588                         // not yet operational
589                         if (tok == "\\color") {
590                                 lex.eatLine();
591                                 string color = lex.getString();
592                                 if (branch_ptr)
593                                         branch_ptr->setColor(color);
594                                 // Update also the Color table:
595                                 if (color == "none")
596                                         color = lcolor.getX11Name(Color_background);
597                                 // FIXME UNICODE
598                                 lcolor.setColor(to_utf8(branch), color);
599
600                         }
601                 }
602         } else if (token == "\\author") {
603                 lex.eatLine();
604                 istringstream ss(lex.getString());
605                 Author a;
606                 ss >> a;
607                 author_map.push_back(pimpl_->authorlist.record(a));
608         } else if (token == "\\paperorientation") {
609                 string orient;
610                 lex >> orient;
611                 orientation = paperorientationtranslator().find(orient);
612         } else if (token == "\\paperwidth") {
613                 lex >> paperwidth;
614         } else if (token == "\\paperheight") {
615                 lex >> paperheight;
616         } else if (token == "\\leftmargin") {
617                 lex >> leftmargin;
618         } else if (token == "\\topmargin") {
619                 lex >> topmargin;
620         } else if (token == "\\rightmargin") {
621                 lex >> rightmargin;
622         } else if (token == "\\bottommargin") {
623                 lex >> bottommargin;
624         } else if (token == "\\headheight") {
625                 lex >> headheight;
626         } else if (token == "\\headsep") {
627                 lex >> headsep;
628         } else if (token == "\\footskip") {
629                 lex >> footskip;
630         } else if (token == "\\paperfontsize") {
631                 lex >> fontsize;
632         } else if (token == "\\papercolumns") {
633                 lex >> columns;
634         } else if (token == "\\listings_params") {
635                 string par;
636                 lex >> par;
637                 listings_params = InsetListingsParams(par).params();
638         } else if (token == "\\papersides") {
639                 int psides;
640                 lex >> psides;
641                 sides = sidestranslator().find(psides);
642         } else if (token == "\\paperpagestyle") {
643                 lex >> pagestyle;
644         } else if (token == "\\bullet") {
645                 readBullets(lex);
646         } else if (token == "\\bulletLaTeX") {
647                 readBulletsLaTeX(lex);
648         } else if (token == "\\secnumdepth") {
649                 lex >> secnumdepth;
650         } else if (token == "\\tocdepth") {
651                 lex >> tocdepth;
652         } else if (token == "\\spacing") {
653                 string nspacing;
654                 lex >> nspacing;
655                 string tmp_val;
656                 if (nspacing == "other") {
657                         lex >> tmp_val;
658                 }
659                 spacing().set(spacetranslator().find(nspacing), tmp_val);
660         } else if (token == "\\float_placement") {
661                 lex >> float_placement;
662
663         } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
664                 string toktmp = pdfoptions().readToken(lex, token);
665                 if (!toktmp.empty()) {
666                         lyxerr << "PDFOptions::readToken(): Unknown token: " <<
667                                 toktmp << endl;
668                         return toktmp;
669                 }
670         } else {
671                 lyxerr << "BufferParams::readToken(): Unknown token: " << 
672                         token << endl;
673                 return token;
674         }
675
676         return string();
677 }
678
679
680 void BufferParams::writeFile(ostream & os) const
681 {
682         // The top of the file is written by the buffer.
683         // Prints out the buffer info into the .lyx file given by file
684
685         // the textclass
686         os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
687
688         // then the preamble
689         if (!preamble.empty()) {
690                 // remove '\n' from the end of preamble
691                 string const tmppreamble = rtrim(preamble, "\n");
692                 os << "\\begin_preamble\n"
693                    << tmppreamble
694                    << "\n\\end_preamble\n";
695         }
696
697         // the options
698         if (!options.empty()) {
699                 os << "\\options " << options << '\n';
700         }
701         
702         //the modules
703         if (!layoutModules_.empty()) {
704                 os << "\\begin_modules" << '\n';
705                 LayoutModuleList::const_iterator it = layoutModules_.begin();
706                 for (; it != layoutModules_.end(); it++)
707                         os << *it << '\n';
708                 os << "\\end_modules" << '\n';
709         }
710
711         // then the text parameters
712         if (language != ignore_language)
713                 os << "\\language " << language->lang() << '\n';
714         os << "\\inputencoding " << inputenc
715            << "\n\\font_roman " << fontsRoman
716            << "\n\\font_sans " << fontsSans
717            << "\n\\font_typewriter " << fontsTypewriter
718            << "\n\\font_default_family " << fontsDefaultFamily
719            << "\n\\font_sc " << convert<string>(fontsSC)
720            << "\n\\font_osf " << convert<string>(fontsOSF)
721            << "\n\\font_sf_scale " << fontsSansScale
722            << "\n\\font_tt_scale " << fontsTypewriterScale
723            << "\n\\graphics " << graphicsDriver << '\n';
724
725         if (!float_placement.empty()) {
726                 os << "\\float_placement " << float_placement << '\n';
727         }
728         os << "\\paperfontsize " << fontsize << '\n';
729
730         spacing().writeFile(os);
731         pdfoptions().writeFile(os);
732
733         os << "\\papersize " << string_papersize[papersize]
734            << "\n\\use_geometry " << convert<string>(use_geometry)
735            << "\n\\use_amsmath " << use_amsmath
736            << "\n\\use_esint " << use_esint
737            << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
738            << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
739            << "\n\\paperorientation " << string_orientation[orientation]
740            << '\n';
741
742         BranchList::const_iterator it = branchlist().begin();
743         BranchList::const_iterator end = branchlist().end();
744         for (; it != end; ++it) {
745                 os << "\\branch " << to_utf8(it->getBranch())
746                    << "\n\\selected " << it->getSelected()
747                    << "\n\\color " << lyx::X11hexname(it->getColor())
748                    << "\n\\end_branch"
749                    << "\n";
750         }
751
752         if (!paperwidth.empty())
753                 os << "\\paperwidth "
754                    << VSpace(paperwidth).asLyXCommand() << '\n';
755         if (!paperheight.empty())
756                 os << "\\paperheight "
757                    << VSpace(paperheight).asLyXCommand() << '\n';
758         if (!leftmargin.empty())
759                 os << "\\leftmargin "
760                    << VSpace(leftmargin).asLyXCommand() << '\n';
761         if (!topmargin.empty())
762                 os << "\\topmargin "
763                    << VSpace(topmargin).asLyXCommand() << '\n';
764         if (!rightmargin.empty())
765                 os << "\\rightmargin "
766                    << VSpace(rightmargin).asLyXCommand() << '\n';
767         if (!bottommargin.empty())
768                 os << "\\bottommargin "
769                    << VSpace(bottommargin).asLyXCommand() << '\n';
770         if (!headheight.empty())
771                 os << "\\headheight "
772                    << VSpace(headheight).asLyXCommand() << '\n';
773         if (!headsep.empty())
774                 os << "\\headsep "
775                    << VSpace(headsep).asLyXCommand() << '\n';
776         if (!footskip.empty())
777                 os << "\\footskip "
778                    << VSpace(footskip).asLyXCommand() << '\n';
779         os << "\\secnumdepth " << secnumdepth
780            << "\n\\tocdepth " << tocdepth
781            << "\n\\paragraph_separation "
782            << string_paragraph_separation[paragraph_separation]
783            << "\n\\defskip " << getDefSkip().asLyXCommand()
784            << "\n\\quotes_language "
785            << string_quotes_language[quotes_language]
786            << "\n\\papercolumns " << columns
787            << "\n\\papersides " << sides
788            << "\n\\paperpagestyle " << pagestyle << '\n';
789         if (!listings_params.empty())
790                 os << "\\listings_params \"" <<
791                         InsetListingsParams(listings_params).encodedString() << "\"\n";
792         for (int i = 0; i < 4; ++i) {
793                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
794                         if (user_defined_bullet(i).getFont() != -1) {
795                                 os << "\\bullet " << i << " "
796                                    << user_defined_bullet(i).getFont() << " "
797                                    << user_defined_bullet(i).getCharacter() << " "
798                                    << user_defined_bullet(i).getSize() << "\n";
799                         }
800                         else {
801                                 // FIXME UNICODE
802                                 os << "\\bulletLaTeX " << i << " \""
803                                    << lyx::to_ascii(user_defined_bullet(i).getText())
804                                    << "\"\n";
805                         }
806                 }
807         }
808
809         os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
810         os << "\\output_changes " << convert<string>(outputChanges) << "\n";
811
812         AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
813         AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
814         for (; a_it != a_end; ++a_it) {
815                 if (a_it->second.used())
816                         os << "\\author " << a_it->second << "\n";
817                 else
818                         os << "\\author " << Author() << "\n";
819         }
820 }
821
822
823 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
824                               TexRow & texrow) const
825 {
826         os << "\\documentclass";
827
828         TextClass const & tclass = getTextClass();
829
830         ostringstream clsoptions; // the document class options.
831
832         if (tokenPos(tclass.opt_fontsize(),
833                      '|', fontsize) >= 0) {
834                 // only write if existing in list (and not default)
835                 clsoptions << fontsize << "pt,";
836         }
837
838         // custom, A3, B3 and B4 paper sizes need geometry
839         bool nonstandard_papersize = papersize == PAPER_B3
840                 || papersize == PAPER_B4
841                 || papersize == PAPER_A3
842                 || papersize == PAPER_CUSTOM;
843
844         if (!use_geometry) {
845                 switch (papersize) {
846                 case PAPER_A4:
847                         clsoptions << "a4paper,";
848                         break;
849                 case PAPER_USLETTER:
850                         clsoptions << "letterpaper,";
851                         break;
852                 case PAPER_A5:
853                         clsoptions << "a5paper,";
854                         break;
855                 case PAPER_B5:
856                         clsoptions << "b5paper,";
857                         break;
858                 case PAPER_USEXECUTIVE:
859                         clsoptions << "executivepaper,";
860                         break;
861                 case PAPER_USLEGAL:
862                         clsoptions << "legalpaper,";
863                         break;
864                 case PAPER_DEFAULT:
865                 case PAPER_A3:
866                 case PAPER_B3:
867                 case PAPER_B4:
868                 case PAPER_CUSTOM:
869                         break;
870                 }
871         }
872
873         // if needed
874         if (sides != tclass.sides()) {
875                 switch (sides) {
876                 case OneSide:
877                         clsoptions << "oneside,";
878                         break;
879                 case TwoSides:
880                         clsoptions << "twoside,";
881                         break;
882                 }
883         }
884
885         // if needed
886         if (columns != tclass.columns()) {
887                 if (columns == 2)
888                         clsoptions << "twocolumn,";
889                 else
890                         clsoptions << "onecolumn,";
891         }
892
893         if (!use_geometry
894             && orientation == ORIENTATION_LANDSCAPE)
895                 clsoptions << "landscape,";
896
897         // language should be a parameter to \documentclass
898         if (language->babel() == "hebrew"
899             && default_language->babel() != "hebrew")
900                 // This seems necessary
901                 features.useLanguage(default_language);
902
903         ostringstream language_options;
904         bool const use_babel = features.useBabel();
905         if (use_babel) {
906                 language_options << features.getLanguages();
907                 if (!language->babel().empty()) {
908                         if (!language_options.str().empty())
909                                 language_options << ',';
910                         language_options << language->babel();
911                 }
912                 // when Vietnamese is used, babel must directly be loaded with the
913                 // language options, not in the class options, see
914                 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
915                 size_t viet = language_options.str().find("vietnam");
916                 // viet = string::npos when not found
917                 if (lyxrc.language_global_options && !language_options.str().empty()
918                         && viet == string::npos)
919                         clsoptions << language_options.str() << ',';
920         }
921
922         // the user-defined options
923         if (!options.empty()) {
924                 clsoptions << options << ',';
925         }
926
927         string strOptions(clsoptions.str());
928         if (!strOptions.empty()) {
929                 strOptions = rtrim(strOptions, ",");
930                 // FIXME UNICODE
931                 os << '[' << from_utf8(strOptions) << ']';
932         }
933
934         os << '{' << from_ascii(tclass.latexname()) << "}\n";
935         texrow.newline();
936         // end of \documentclass defs
937
938         // font selection must be done before loading fontenc.sty
939         string const fonts =
940                 loadFonts(fontsRoman, fontsSans,
941                           fontsTypewriter, fontsSC, fontsOSF,
942                           fontsSansScale, fontsTypewriterScale);
943         if (!fonts.empty()) {
944                 os << from_ascii(fonts);
945                 texrow.newline();
946         }
947         if (fontsDefaultFamily != "default")
948                 os << "\\renewcommand{\\familydefault}{\\"
949                    << from_ascii(fontsDefaultFamily) << "}\n";
950
951         // set font encoding
952         // this one is not per buffer
953         // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
954         if (lyxrc.fontenc != "default") {
955                 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
956                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
957                            << ",LFE,LAE]{fontenc}\n";
958                         texrow.newline();
959                 } else {
960                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
961                            << "]{fontenc}\n";
962                         texrow.newline();
963                 }
964         }
965
966         // handle inputenc etc.
967         writeEncodingPreamble(os, features, texrow);
968
969         if (!listings_params.empty()) {
970                 os << "\\usepackage{listings}\n";
971                 texrow.newline();
972                 os << "\\lstset{";
973                 // do not test validity because listings_params is supposed to be valid
974                 string par = InsetListingsParams(listings_params).separatedParams(true);
975                 os << from_ascii(par);
976                 // count the number of newlines
977                 for (size_t i = 0; i < par.size(); ++i)
978                         if (par[i] == '\n')
979                                 texrow.newline();
980                 os << "}\n";
981                 texrow.newline();
982         }
983         if (use_geometry || nonstandard_papersize) {
984                 os << "\\usepackage{geometry}\n";
985                 texrow.newline();
986                 os << "\\geometry{verbose";
987                 if (orientation == ORIENTATION_LANDSCAPE)
988                         os << ",landscape";
989                 switch (papersize) {
990                 case PAPER_CUSTOM:
991                         if (!paperwidth.empty())
992                                 os << ",paperwidth="
993                                    << from_ascii(paperwidth);
994                         if (!paperheight.empty())
995                                 os << ",paperheight="
996                                    << from_ascii(paperheight);
997                         break;
998                 case PAPER_USLETTER:
999                         os << ",letterpaper";
1000                         break;
1001                 case PAPER_USLEGAL:
1002                         os << ",legalpaper";
1003                         break;
1004                 case PAPER_USEXECUTIVE:
1005                         os << ",executivepaper";
1006                         break;
1007                 case PAPER_A3:
1008                         os << ",a3paper";
1009                         break;
1010                 case PAPER_A4:
1011                         os << ",a4paper";
1012                         break;
1013                 case PAPER_A5:
1014                         os << ",a5paper";
1015                         break;
1016                 case PAPER_B3:
1017                         os << ",b3paper";
1018                         break;
1019                 case PAPER_B4:
1020                         os << ",b4paper";
1021                         break;
1022                 case PAPER_B5:
1023                         os << ",b5paper";
1024                         break;
1025                 default:
1026                         // default papersize ie PAPER_DEFAULT
1027                         switch (lyxrc.default_papersize) {
1028                         case PAPER_DEFAULT: // keep compiler happy
1029                         case PAPER_USLETTER:
1030                                 os << ",letterpaper";
1031                                 break;
1032                         case PAPER_USLEGAL:
1033                                 os << ",legalpaper";
1034                                 break;
1035                         case PAPER_USEXECUTIVE:
1036                                 os << ",executivepaper";
1037                                 break;
1038                         case PAPER_A3:
1039                                 os << ",a3paper";
1040                                 break;
1041                         case PAPER_A4:
1042                                 os << ",a4paper";
1043                                 break;
1044                         case PAPER_A5:
1045                                 os << ",a5paper";
1046                                 break;
1047                         case PAPER_B5:
1048                                 os << ",b5paper";
1049                                 break;
1050                         case PAPER_B3:
1051                         case PAPER_B4:
1052                         case PAPER_CUSTOM:
1053                                 break;
1054                         }
1055                 }
1056                 if (!topmargin.empty())
1057                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1058                 if (!bottommargin.empty())
1059                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1060                 if (!leftmargin.empty())
1061                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1062                 if (!rightmargin.empty())
1063                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1064                 if (!headheight.empty())
1065                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1066                 if (!headsep.empty())
1067                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1068                 if (!footskip.empty())
1069                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1070                 os << "}\n";
1071                 texrow.newline();
1072         }
1073
1074         if (tokenPos(tclass.opt_pagestyle(),
1075                      '|', pagestyle) >= 0) {
1076                 if (pagestyle == "fancy") {
1077                         os << "\\usepackage{fancyhdr}\n";
1078                         texrow.newline();
1079                 }
1080                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1081                 texrow.newline();
1082         }
1083
1084         // Only if class has a ToC hierarchy
1085         if (tclass.hasTocLevels()) {
1086                 if (secnumdepth != tclass.secnumdepth()) {
1087                         os << "\\setcounter{secnumdepth}{"
1088                            << secnumdepth
1089                            << "}\n";
1090                         texrow.newline();
1091                 }
1092                 if (tocdepth != tclass.tocdepth()) {
1093                         os << "\\setcounter{tocdepth}{"
1094                            << tocdepth
1095                            << "}\n";
1096                         texrow.newline();
1097                 }
1098         }
1099
1100         if (paragraph_separation) {
1101                 switch (getDefSkip().kind()) {
1102                 case VSpace::SMALLSKIP:
1103                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1104                         break;
1105                 case VSpace::MEDSKIP:
1106                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1107                         break;
1108                 case VSpace::BIGSKIP:
1109                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1110                         break;
1111                 case VSpace::LENGTH:
1112                         os << "\\setlength{\\parskip}{"
1113                            << from_utf8(getDefSkip().length().asLatexString())
1114                            << "}\n";
1115                         break;
1116                 default: // should never happen // Then delete it.
1117                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1118                         break;
1119                 }
1120                 texrow.newline();
1121
1122                 os << "\\setlength{\\parindent}{0pt}\n";
1123                 texrow.newline();
1124         }
1125
1126         // If we use jurabib, we have to call babel here.
1127         if (use_babel && features.isRequired("jurabib")) {
1128                 os << from_ascii(babelCall(language_options.str()))
1129                    << '\n'
1130                    << from_ascii(features.getBabelOptions());
1131                 texrow.newline();
1132         }
1133
1134         // Now insert the LyX specific LaTeX commands...
1135
1136         // The optional packages;
1137         docstring lyxpreamble(from_ascii(features.getPackages()));
1138
1139         // We try to load babel late, in case it interferes
1140         // with other packages. But some packages also need babel to be loaded
1141         // before, e.g. jurabib has to be called after babel.
1142         // So load babel after the optional packages but before the user-defined
1143         // preamble. This allows the users to redefine babel commands, e.g. to
1144         // translate the word "Index" to the German "Stichwortverzeichnis".
1145         // For more infos why this place was chosen, see
1146         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1147         // If you encounter problems, you can shift babel to its old place behind
1148         // the user-defined preamble. But in this case you must change the Vietnamese
1149         // support from currently "\usepackage[vietnamese]{babel}" to:
1150         // \usepackage{vietnamese}
1151         // \usepackage{babel}
1152         // because vietnamese must be loaded before hyperref
1153         if (use_babel && !features.isRequired("jurabib")) {
1154                 // FIXME UNICODE
1155                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1156                 lyxpreamble += from_utf8(features.getBabelOptions());
1157         }
1158
1159         // When the language "japanese-plain" is used, the package "japanese" must
1160         // be loaded behind babel (it provides babel support for Japanese) but before
1161         // hyperref, see
1162         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1163         if (language->lang() == "japanese-plain" &&
1164                 !getTextClass().provides("japanese")) {
1165                 //load babel in case it was not loaded due to an empty language list
1166                 if (language_options.str().empty())
1167                         lyxpreamble += "\\usepackage{babel}\n";
1168                 lyxpreamble += "\\usepackage{japanese}\n";
1169         }
1170
1171         // PDF support.
1172         // * Hyperref manual: "Make sure it comes last of your loaded
1173         //   packages, to give it a fighting chance of not being over-written,
1174         //   since its job is to redefine many LATEX commands."
1175         // * Email from Heiko Oberdiek: "It is usually better to load babel
1176         //   before hyperref. Then hyperref has a chance to detect babel.
1177         // * Has to be loaded before the "LyX specific LaTeX commands" to
1178         //   avoid errors with algorithm floats.
1179         odocstringstream oss;
1180         // use hyperref explicitely when it is required
1181         pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1182         lyxpreamble += oss.str();
1183
1184         // this might be useful...
1185         lyxpreamble += "\n\\makeatletter\n";
1186
1187         // Some macros LyX will need
1188         docstring tmppreamble(from_ascii(features.getMacros()));
1189
1190         if (!tmppreamble.empty()) {
1191                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1192                         "LyX specific LaTeX commands.\n"
1193                         + tmppreamble + '\n';
1194         }
1195
1196         // the text class specific preamble
1197         tmppreamble = features.getTClassPreamble();
1198         if (!tmppreamble.empty()) {
1199                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1200                         "Textclass specific LaTeX commands.\n"
1201                         + tmppreamble + '\n';
1202         }
1203
1204         /* the user-defined preamble */
1205         if (!preamble.empty()) {
1206                 // FIXME UNICODE
1207                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1208                         "User specified LaTeX commands.\n"
1209                         + from_utf8(preamble) + '\n';
1210         }
1211
1212         // Itemize bullet settings need to be last in case the user
1213         // defines their own bullets that use a package included
1214         // in the user-defined preamble -- ARRae
1215         // Actually it has to be done much later than that
1216         // since some packages like frenchb make modifications
1217         // at \begin{document} time -- JMarc
1218         docstring bullets_def;
1219         for (int i = 0; i < 4; ++i) {
1220                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1221                         if (bullets_def.empty())
1222                                 bullets_def += "\\AtBeginDocument{\n";
1223                         bullets_def += "  \\def\\labelitemi";
1224                         switch (i) {
1225                                 // `i' is one less than the item to modify
1226                         case 0:
1227                                 break;
1228                         case 1:
1229                                 bullets_def += 'i';
1230                                 break;
1231                         case 2:
1232                                 bullets_def += "ii";
1233                                 break;
1234                         case 3:
1235                                 bullets_def += 'v';
1236                                 break;
1237                         }
1238                         bullets_def += '{' +
1239                                 user_defined_bullet(i).getText()
1240                                 + "}\n";
1241                 }
1242         }
1243
1244         if (!bullets_def.empty())
1245                 lyxpreamble += bullets_def + "}\n\n";
1246
1247         lyxpreamble += "\\makeatother\n\n";
1248
1249         int const nlines =
1250                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1251         for (int j = 0; j != nlines; ++j) {
1252                 texrow.newline();
1253         }
1254
1255         os << lyxpreamble;
1256         return use_babel;
1257 }
1258
1259
1260 void BufferParams::useClassDefaults()
1261 {
1262         TextClass const & tclass = textclasslist[baseClass_];
1263
1264         sides = tclass.sides();
1265         columns = tclass.columns();
1266         pagestyle = tclass.pagestyle();
1267         options = tclass.options();
1268         // Only if class has a ToC hierarchy
1269         if (tclass.hasTocLevels()) {
1270                 secnumdepth = tclass.secnumdepth();
1271                 tocdepth = tclass.tocdepth();
1272         }
1273 }
1274
1275
1276 bool BufferParams::hasClassDefaults() const
1277 {
1278         TextClass const & tclass = textclasslist[baseClass_];
1279
1280         return (sides == tclass.sides()
1281                 && columns == tclass.columns()
1282                 && pagestyle == tclass.pagestyle()
1283                 && options == tclass.options()
1284                 && secnumdepth == tclass.secnumdepth()
1285                 && tocdepth == tclass.tocdepth());
1286 }
1287
1288
1289 TextClass const & BufferParams::getTextClass() const
1290 {
1291         return *textClass_;
1292 }
1293
1294
1295 TextClassPtr BufferParams::getTextClassPtr() const {
1296         return textClass_;
1297 }
1298
1299
1300 void BufferParams::setTextClass(TextClassPtr tc) {
1301         textClass_ = tc;
1302 }
1303
1304
1305 bool BufferParams::setBaseClass(textclass_type tc)
1306 {
1307         bool retVal = true;
1308         if (textclasslist[tc].load())
1309                 baseClass_ = tc;
1310         else {
1311                 docstring s = 
1312                         bformat(_("The document class %1$s could not be loaded."),
1313                  from_utf8(textclasslist[tc].name()));
1314                 frontend::Alert::error(_("Could not load class"), s);
1315                 retVal = false;
1316         }
1317         makeTextClass();
1318         return retVal;
1319 }
1320
1321
1322 void BufferParams::setJustBaseClass(textclass_type tc)
1323
1324         baseClass_ = tc; 
1325 }
1326
1327
1328 textclass_type BufferParams::getBaseClass() const
1329 {
1330         return baseClass_;
1331 }
1332
1333
1334 void BufferParams::makeTextClass()
1335 {
1336         textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1337         //FIXME It might be worth loading the children's modules here,
1338         //just as we load their bibliographies and such, instead of just 
1339         //doing a check in InsetInclude.
1340         LayoutModuleList::const_iterator it = layoutModules_.begin();
1341         for (; it != layoutModules_.end(); it++) {
1342                 string const modName = *it;
1343                 LyXModule * lm = moduleList[modName];
1344                 if (!lm) {
1345                         docstring const msg =
1346                                 bformat(_("The module %1$s has been requested by\n"
1347                                         "this document but has not been found in the list of\n"
1348                                         "available modules. If you recently installed it, you\n"
1349                                         "probalby need to reconfigure LyX.\n"), from_utf8(modName));
1350                         frontend::Alert::warning(_("Module not available"),
1351                                         msg + _("Some layouts may not be available."));
1352                         lyxerr << "BufferParams::makeTextClass(): Module " <<
1353                                         modName << " requested but not found in module list." <<
1354                                         endl;
1355                         continue;
1356                 }
1357                 FileName layout_file = libFileSearch("layouts", lm->filename);
1358                 textClass_->read(layout_file, TextClass::MODULE);
1359         }
1360 }
1361
1362
1363 std::vector<string> const & BufferParams::getModules() const {
1364         return layoutModules_;
1365 }
1366
1367
1368
1369 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1370         LayoutModuleList::const_iterator it = layoutModules_.begin();
1371         LayoutModuleList::const_iterator end = layoutModules_.end();
1372         for (; it != end; it++) {
1373                 if (*it == modName) 
1374                         break;
1375         }
1376         if (it != layoutModules_.end())
1377                 return false;
1378         layoutModules_.push_back(modName);
1379         if (makeClass)
1380                 makeTextClass();
1381         return true;
1382 }
1383
1384
1385 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1386 {
1387         bool retval = true;
1388         std::vector<string>::const_iterator it = modNames.begin();
1389         std::vector<string>::const_iterator end = modNames.end();
1390         for (; it != end; ++it)
1391                 retval &= addLayoutModule(*it, false);
1392         makeTextClass();
1393         return retval;
1394 }
1395
1396
1397 void BufferParams::clearLayoutModules() {
1398         layoutModules_.clear();
1399         makeTextClass();
1400 }
1401
1402
1403 Font const BufferParams::getFont() const
1404 {
1405         FontInfo f = getTextClass().defaultfont();
1406         if (fontsDefaultFamily == "rmdefault")
1407                 f.setFamily(ROMAN_FAMILY);
1408         else if (fontsDefaultFamily == "sfdefault")
1409                 f.setFamily(SANS_FAMILY);
1410         else if (fontsDefaultFamily == "ttdefault")
1411                 f.setFamily(TYPEWRITER_FAMILY);
1412         return Font(f, language);
1413 }
1414
1415
1416 void BufferParams::readPreamble(Lexer & lex)
1417 {
1418         if (lex.getString() != "\\begin_preamble")
1419                 lyxerr << "Error (BufferParams::readPreamble):"
1420                         "consistency check failed." << endl;
1421
1422         preamble = lex.getLongString("\\end_preamble");
1423 }
1424
1425
1426 void BufferParams::readLanguage(Lexer & lex)
1427 {
1428         if (!lex.next()) return;
1429
1430         string const tmptok = lex.getString();
1431
1432         // check if tmptok is part of tex_babel in tex-defs.h
1433         language = languages.getLanguage(tmptok);
1434         if (!language) {
1435                 // Language tmptok was not found
1436                 language = default_language;
1437                 lyxerr << "Warning: Setting language `"
1438                        << tmptok << "' to `" << language->lang()
1439                        << "'." << endl;
1440         }
1441 }
1442
1443
1444 void BufferParams::readGraphicsDriver(Lexer & lex)
1445 {
1446         if (!lex.next()) return;
1447
1448         string const tmptok = lex.getString();
1449         // check if tmptok is part of tex_graphics in tex_defs.h
1450         int n = 0;
1451         while (true) {
1452                 string const test = tex_graphics[n++];
1453
1454                 if (test == tmptok) {
1455                         graphicsDriver = tmptok;
1456                         break;
1457                 } else if (test == "") {
1458                         lex.printError(
1459                                 "Warning: graphics driver `$$Token' not recognized!\n"
1460                                 "         Setting graphics driver to `default'.\n");
1461                         graphicsDriver = "default";
1462                         break;
1463                 }
1464         }
1465 }
1466
1467
1468 void BufferParams::readBullets(Lexer & lex)
1469 {
1470         if (!lex.next()) return;
1471
1472         int const index = lex.getInteger();
1473         lex.next();
1474         int temp_int = lex.getInteger();
1475         user_defined_bullet(index).setFont(temp_int);
1476         temp_bullet(index).setFont(temp_int);
1477         lex >> temp_int;
1478         user_defined_bullet(index).setCharacter(temp_int);
1479         temp_bullet(index).setCharacter(temp_int);
1480         lex >> temp_int;
1481         user_defined_bullet(index).setSize(temp_int);
1482         temp_bullet(index).setSize(temp_int);
1483 }
1484
1485
1486 void BufferParams::readBulletsLaTeX(Lexer & lex)
1487 {
1488         // The bullet class should be able to read this.
1489         if (!lex.next()) return;
1490         int const index = lex.getInteger();
1491         lex.next(true);
1492         docstring const temp_str = lex.getDocString();
1493
1494         user_defined_bullet(index).setText(temp_str);
1495         temp_bullet(index).setText(temp_str);
1496 }
1497
1498
1499 void BufferParams::readModules(Lexer & lex)
1500 {
1501         if (!lex.eatLine()) {
1502                 lyxerr << "Error (BufferParams::readModules):"
1503                                 "Unexpected end of input." << endl;
1504                 return;
1505         }
1506         while (true) {
1507                 string mod = lex.getString();
1508                 if (mod == "\\end_modules")
1509                         break;
1510                 addLayoutModule(mod);
1511                 lex.eatLine();
1512         }
1513 }
1514
1515
1516 string const BufferParams::paperSizeName() const
1517 {
1518         char real_papersize = papersize;
1519         if (real_papersize == PAPER_DEFAULT)
1520                 real_papersize = lyxrc.default_papersize;
1521
1522         switch (real_papersize) {
1523         case PAPER_A3:
1524                 return "a3";
1525         case PAPER_A4:
1526                 return "a4";
1527         case PAPER_A5:
1528                 return "a5";
1529         case PAPER_B5:
1530                 return "b5";
1531         case PAPER_USEXECUTIVE:
1532                 return "foolscap";
1533         case PAPER_USLEGAL:
1534                 return "legal";
1535         case PAPER_USLETTER:
1536         default:
1537                 return "letter";
1538         }
1539 }
1540
1541
1542 string const BufferParams::dvips_options() const
1543 {
1544         string result;
1545
1546         if (use_geometry
1547             && papersize == PAPER_CUSTOM
1548             && !lyxrc.print_paper_dimension_flag.empty()
1549             && !paperwidth.empty()
1550             && !paperheight.empty()) {
1551                 // using a custom papersize
1552                 result = lyxrc.print_paper_dimension_flag;
1553                 result += ' ' + paperwidth;
1554                 result += ',' + paperheight;
1555         } else {
1556                 string const paper_option = paperSizeName();
1557                 if (paper_option != "letter" ||
1558                     orientation != ORIENTATION_LANDSCAPE) {
1559                         // dvips won't accept -t letter -t landscape.
1560                         // In all other cases, include the paper size
1561                         // explicitly.
1562                         result = lyxrc.print_paper_flag;
1563                         result += ' ' + paper_option;
1564                 }
1565         }
1566         if (orientation == ORIENTATION_LANDSCAPE &&
1567             papersize != PAPER_CUSTOM)
1568                 result += ' ' + lyxrc.print_landscape_flag;
1569         return result;
1570 }
1571
1572
1573 string const BufferParams::babelCall(string const & lang_opts) const
1574 {
1575         string lang_pack = lyxrc.language_package;
1576         if (lang_pack != "\\usepackage{babel}")
1577                 return lang_pack;
1578         // suppress the babel call when there is no babel language defined
1579         // for the document language in the lib/languages file and if no
1580         // other languages are used (lang_opts is then empty)
1581         if (lang_opts.empty())
1582                 return string();
1583         // when Vietnamese is used, babel must directly be loaded with the
1584         // language options, see
1585         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1586         size_t viet = lang_opts.find("vietnam");
1587         // viet = string::npos when not found
1588         if (!lyxrc.language_global_options || viet != string::npos)
1589                 return "\\usepackage[" + lang_opts + "]{babel}";
1590         return lang_pack;
1591 }
1592
1593
1594 void BufferParams::writeEncodingPreamble(odocstream & os,
1595                 LaTeXFeatures & features, TexRow & texrow) const
1596 {
1597         if (inputenc == "auto") {
1598                 string const doc_encoding =
1599                         language->encoding()->latexName();
1600                 Encoding::Package const package =
1601                         language->encoding()->package();
1602
1603                 // Create a list with all the input encodings used
1604                 // in the document
1605                 std::set<string> encodings =
1606                         features.getEncodingSet(doc_encoding);
1607
1608                 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1609                 // package inputenc must be omitted. Therefore set the encoding to empty.
1610                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1611                 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1612                         doc_encoding == "SJIS-plain")
1613                         encodings.clear();
1614
1615                 if (!encodings.empty() || package == Encoding::inputenc) {
1616                         os << "\\usepackage[";
1617                         std::set<string>::const_iterator it = encodings.begin();
1618                         std::set<string>::const_iterator const end = encodings.end();
1619                         if (it != end) {
1620                                 os << from_ascii(*it);
1621                                 ++it;
1622                         }
1623                         for (; it != end; ++it)
1624                                 os << ',' << from_ascii(*it);
1625                         if (package == Encoding::inputenc) {
1626                                 if (!encodings.empty())
1627                                         os << ',';
1628                                 os << from_ascii(doc_encoding);
1629                         }
1630                         os << "]{inputenc}\n";
1631                         texrow.newline();
1632                 }
1633                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1634                         os << "\\usepackage{CJK}\n";
1635                         texrow.newline();
1636                 }
1637         } else if (inputenc != "default") {
1638                 switch (encoding().package()) {
1639                 case Encoding::none:
1640                         break;
1641                 case Encoding::inputenc:
1642                         os << "\\usepackage[" << from_ascii(inputenc)
1643                            << "]{inputenc}\n";
1644                         texrow.newline();
1645                         break;
1646                 case Encoding::CJK:
1647                         os << "\\usepackage{CJK}\n";
1648                         texrow.newline();
1649                         break;
1650                 }
1651         }
1652
1653         // The encoding "armscii8" is only available when the package "armtex" is loaded.
1654         // armscii8 is used for Armenian.
1655         if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1656                 os << "\\usepackage{armtex}\n";
1657                 texrow.newline();
1658         }
1659 }
1660
1661
1662 string const BufferParams::loadFonts(string const & rm,
1663                                      string const & sf, string const & tt,
1664                                      bool const & sc, bool const & osf,
1665                                      int const & sfscale, int const & ttscale) const
1666 {
1667         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1668            several packages have been replaced by others, that might not
1669            be installed on every system. We have to take care for that
1670            (see psnfss.pdf). We try to support all psnfss fonts as well
1671            as the fonts that have become de facto standard in the LaTeX
1672            world (e.g. Latin Modern). We do not support obsolete fonts
1673            (like PSLatex). In general, it should be possible to mix any
1674            rm font with any sf or tt font, respectively. (JSpitzm)
1675            TODO:
1676                 -- separate math fonts.
1677         */
1678
1679         if (rm == "default" && sf == "default" && tt == "default")
1680                 //nothing to do
1681                 return string();
1682
1683         ostringstream os;
1684
1685         // ROMAN FONTS
1686         // Computer Modern (must be explicitely selectable -- there might be classes
1687         // that define a different default font!
1688         if (rm == "cmr") {
1689                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1690                 // osf for Computer Modern needs eco.sty
1691                 if (osf)
1692                         os << "\\usepackage{eco}\n";
1693         }
1694         // Latin Modern Roman
1695         else if (rm == "lmodern")
1696                 os << "\\usepackage{lmodern}\n";
1697         // AE
1698         else if (rm == "ae") {
1699                 // not needed when using OT1 font encoding.
1700                 if (lyxrc.fontenc != "default")
1701                         os << "\\usepackage{ae,aecompl}\n";
1702         }
1703         // Times
1704         else if (rm == "times") {
1705                 // try to load the best available package
1706                 if (LaTeXFeatures::isAvailable("mathptmx"))
1707                         os << "\\usepackage{mathptmx}\n";
1708                 else if (LaTeXFeatures::isAvailable("mathptm"))
1709                         os << "\\usepackage{mathptm}\n";
1710                 else
1711                         os << "\\usepackage{times}\n";
1712         }
1713         // Palatino
1714         else if (rm == "palatino") {
1715                 // try to load the best available package
1716                 if (LaTeXFeatures::isAvailable("mathpazo")) {
1717                         os << "\\usepackage";
1718                         if (osf || sc) {
1719                                 os << '[';
1720                                 if (!osf)
1721                                         os << "sc";
1722                                 else
1723                                         // "osf" includes "sc"!
1724                                         os << "osf";
1725                                 os << ']';
1726                         }
1727                         os << "{mathpazo}\n";
1728                 }
1729                 else if (LaTeXFeatures::isAvailable("mathpple"))
1730                         os << "\\usepackage{mathpple}\n";
1731                 else
1732                         os << "\\usepackage{palatino}\n";
1733         }
1734         // Utopia
1735         else if (rm == "utopia") {
1736                 // fourier supersedes utopia.sty, but does
1737                 // not work with OT1 encoding.
1738                 if (LaTeXFeatures::isAvailable("fourier")
1739                     && lyxrc.fontenc != "default") {
1740                         os << "\\usepackage";
1741                         if (osf || sc) {
1742                                 os << '[';
1743                                 if (sc)
1744                                         os << "expert";
1745                                 if (osf && sc)
1746                                         os << ',';
1747                                 if (osf)
1748                                         os << "oldstyle";
1749                                 os << ']';
1750                         }
1751                         os << "{fourier}\n";
1752                 }
1753                 else
1754                         os << "\\usepackage{utopia}\n";
1755         }
1756         // Bera (complete fontset)
1757         else if (rm == "bera" && sf == "default" && tt == "default")
1758                 os << "\\usepackage{bera}\n";
1759         // everything else
1760         else if (rm != "default")
1761                 os << "\\usepackage" << "{" << rm << "}\n";
1762
1763         // SANS SERIF
1764         // Helvetica, Bera Sans
1765         if (sf == "helvet" || sf == "berasans") {
1766                 if (sfscale != 100)
1767                         os << "\\usepackage[scaled=" << float(sfscale) / 100
1768                            << "]{" << sf << "}\n";
1769                 else
1770                         os << "\\usepackage{" << sf << "}\n";
1771         }
1772         // Avant Garde
1773         else if (sf == "avant")
1774                 os << "\\usepackage{" << sf << "}\n";
1775         // Computer Modern, Latin Modern, CM Bright
1776         else if (sf != "default")
1777                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1778
1779         // monospaced/typewriter
1780         // Courier, LuxiMono
1781         if (tt == "luximono" || tt == "beramono") {
1782                 if (ttscale != 100)
1783                         os << "\\usepackage[scaled=" << float(ttscale) / 100
1784                            << "]{" << tt << "}\n";
1785                 else
1786                         os << "\\usepackage{" << tt << "}\n";
1787         }
1788         // Courier
1789         else if (tt == "courier" )
1790                 os << "\\usepackage{" << tt << "}\n";
1791         // Computer Modern, Latin Modern, CM Bright
1792         else if  (tt != "default")
1793                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1794
1795         return os.str();
1796 }
1797
1798
1799 Encoding const & BufferParams::encoding() const
1800 {
1801         if (inputenc == "auto" || inputenc == "default")
1802                 return *(language->encoding());
1803         Encoding const * const enc =
1804                 encodings.getFromLaTeXName(inputenc);
1805         if (enc)
1806                 return *enc;
1807         lyxerr << "Unknown inputenc value `" << inputenc
1808                << "'. Using `auto' instead." << endl;
1809         return *(language->encoding());
1810 }
1811
1812
1813 biblio::CiteEngine BufferParams::getEngine() const
1814 {
1815         // FIXME the class should provide the numerical/
1816         // authoryear choice
1817         if (getTextClass().provides("natbib")
1818             && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1819                 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1820         return cite_engine_;
1821 }
1822
1823
1824 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1825 {
1826         cite_engine_ = cite_engine;
1827 }
1828
1829 } // namespace lyx