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