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