]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
946a781a0726a79ce5160d0d0a89f347887ab7ff
[lyx.git] / src / BufferParams.cpp
1 /**
2  * \file BufferParams.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  * \author André Pönitz
11  * \author Martin Vermeer
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "BufferParams.h"
19
20 #include "Author.h"
21 #include "BranchList.h"
22 #include "buffer_funcs.h"
23 #include "Bullet.h"
24 #include "Color.h"
25 #include "debug.h"
26 #include "Encoding.h"
27 #include "gettext.h"
28 #include "Language.h"
29 #include "LaTeXFeatures.h"
30 #include "Messages.h"
31 #include "ModuleList.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/docstream.h"
47 #include "support/FileName.h"
48 #include "support/filetools.h"
49 #include "support/Translator.h"
50 #include "support/lstrings.h"
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, PageSides> SidesTranslator;
200
201
202 SidesTranslator const init_sidestranslator()
203 {
204         SidesTranslator translator(1, OneSide);
205         translator.addPair(2, 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         Bullet temp_bullets[4];
291         Bullet user_defined_bullets[4];
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 = 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         FileName const & filepath)
470 {
471         if (token == "\\textclass") {
472                 lex.next();
473                 string const classname = lex.getString();
474                 // if there exists a local layout file, ignore the system one
475                 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
476                 pair<bool, lyx::textclass_type> pp = textclasslist.addTextClass(
477                         classname, filepath.absFilename());
478                 if (pp.first)
479                         setBaseClass(pp.second);
480                 else {
481                         pp = textclasslist.numberOfClass(classname);
482                         if (pp.first)
483                                 setBaseClass(pp.second);
484                         else {
485                                 // a warning will be given for unknown class
486                                 setBaseClass(defaultTextclass());
487                                 return classname;
488                         }
489                 }
490                 // FIXME: this warning will be given even if there exists a local .cls
491                 // file. Even worse, the .lyx file can not be compiled or exported
492                 // because the textclass is marked as unavilable.
493                 if (!getTextClass().isTeXClassAvailable()) {
494                         docstring const msg =
495                                 bformat(_("The layout file requested by this document,\n"
496                                                  "%1$s.layout,\n"
497                                                  "is not usable. This is probably because a LaTeX\n"
498                                                  "class or style file required by it is not\n"
499                                                  "available. See the Customization documentation\n"
500                                                  "for more information.\n"), from_utf8(classname));
501                         frontend::Alert::warning(_("Document class not available"),
502                                        msg + _("LyX will not be able to produce output."));
503                 } 
504                 
505         } else if (token == "\\begin_preamble") {
506                 readPreamble(lex);
507         } else if (token == "\\begin_modules") {
508                 readModules(lex);
509                 makeTextClass();
510         } else if (token == "\\options") {
511                 lex.eatLine();
512                 options = lex.getString();
513         } else if (token == "\\language") {
514                 readLanguage(lex);
515         } else if (token == "\\inputencoding") {
516                 lex >> inputenc;
517         } else if (token == "\\graphics") {
518                 readGraphicsDriver(lex);
519         } else if (token == "\\font_roman") {
520                 lex >> fontsRoman;
521         } else if (token == "\\font_sans") {
522                 lex >> fontsSans;
523         } else if (token == "\\font_typewriter") {
524                 lex >> fontsTypewriter;
525         } else if (token == "\\font_default_family") {
526                 lex >> fontsDefaultFamily;
527         } else if (token == "\\font_sc") {
528                 lex >> fontsSC;
529         } else if (token == "\\font_osf") {
530                 lex >> fontsOSF;
531         } else if (token == "\\font_sf_scale") {
532                 lex >> fontsSansScale;
533         } else if (token == "\\font_tt_scale") {
534                 lex >> fontsTypewriterScale;
535         } else if (token == "\\paragraph_separation") {
536                 string parsep;
537                 lex >> parsep;
538                 paragraph_separation = parseptranslator().find(parsep);
539         } else if (token == "\\defskip") {
540                 lex.next();
541                 pimpl_->defskip = VSpace(lex.getString());
542         } else if (token == "\\quotes_language") {
543                 string quotes_lang;
544                 lex >> quotes_lang;
545                 quotes_language = quoteslangtranslator().find(quotes_lang);
546         } else if (token == "\\papersize") {
547                 string ppsize;
548                 lex >> ppsize;
549                 papersize = papersizetranslator().find(ppsize);
550         } else if (token == "\\use_geometry") {
551                 lex >> use_geometry;
552         } else if (token == "\\use_amsmath") {
553                 int use_ams;
554                 lex >> use_ams;
555                 use_amsmath = packagetranslator().find(use_ams);
556         } else if (token == "\\use_esint") {
557                 int useesint;
558                 lex >> useesint;
559                 use_esint = packagetranslator().find(useesint);
560         } else if (token == "\\cite_engine") {
561                 string engine;
562                 lex >> engine;
563                 cite_engine_ = citeenginetranslator().find(engine);
564         } else if (token == "\\use_bibtopic") {
565                 lex >> use_bibtopic;
566         } else if (token == "\\tracking_changes") {
567                 lex >> trackChanges;
568         } else if (token == "\\output_changes") {
569                 lex >> outputChanges;
570         } else if (token == "\\branch") {
571                 lex.next();
572                 docstring branch = lex.getDocString();
573                 branchlist().add(branch);
574                 while (true) {
575                         lex.next();
576                         string const tok = lex.getString();
577                         if (tok == "\\end_branch")
578                                 break;
579                         Branch * branch_ptr = branchlist().find(branch);
580                         if (tok == "\\selected") {
581                                 lex.next();
582                                 if (branch_ptr)
583                                         branch_ptr->setSelected(lex.getInteger());
584                         }
585                         // not yet operational
586                         if (tok == "\\color") {
587                                 lex.eatLine();
588                                 string color = lex.getString();
589                                 if (branch_ptr)
590                                         branch_ptr->setColor(color);
591                                 // Update also the Color table:
592                                 if (color == "none")
593                                         color = lcolor.getX11Name(Color_background);
594                                 // FIXME UNICODE
595                                 lcolor.setColor(to_utf8(branch), color);
596
597                         }
598                 }
599         } else if (token == "\\author") {
600                 lex.eatLine();
601                 istringstream ss(lex.getString());
602                 Author a;
603                 ss >> a;
604                 author_map.push_back(pimpl_->authorlist.record(a));
605         } else if (token == "\\paperorientation") {
606                 string orient;
607                 lex >> orient;
608                 orientation = paperorientationtranslator().find(orient);
609         } else if (token == "\\paperwidth") {
610                 lex >> paperwidth;
611         } else if (token == "\\paperheight") {
612                 lex >> paperheight;
613         } else if (token == "\\leftmargin") {
614                 lex >> leftmargin;
615         } else if (token == "\\topmargin") {
616                 lex >> topmargin;
617         } else if (token == "\\rightmargin") {
618                 lex >> rightmargin;
619         } else if (token == "\\bottommargin") {
620                 lex >> bottommargin;
621         } else if (token == "\\headheight") {
622                 lex >> headheight;
623         } else if (token == "\\headsep") {
624                 lex >> headsep;
625         } else if (token == "\\footskip") {
626                 lex >> footskip;
627         } else if (token == "\\paperfontsize") {
628                 lex >> fontsize;
629         } else if (token == "\\papercolumns") {
630                 lex >> columns;
631         } else if (token == "\\listings_params") {
632                 string par;
633                 lex >> par;
634                 listings_params = InsetListingsParams(par).params();
635         } else if (token == "\\papersides") {
636                 int psides;
637                 lex >> psides;
638                 sides = sidestranslator().find(psides);
639         } else if (token == "\\paperpagestyle") {
640                 lex >> pagestyle;
641         } else if (token == "\\bullet") {
642                 readBullets(lex);
643         } else if (token == "\\bulletLaTeX") {
644                 readBulletsLaTeX(lex);
645         } else if (token == "\\secnumdepth") {
646                 lex >> secnumdepth;
647         } else if (token == "\\tocdepth") {
648                 lex >> tocdepth;
649         } else if (token == "\\spacing") {
650                 string nspacing;
651                 lex >> nspacing;
652                 string tmp_val;
653                 if (nspacing == "other") {
654                         lex >> tmp_val;
655                 }
656                 spacing().set(spacetranslator().find(nspacing), tmp_val);
657         } else if (token == "\\float_placement") {
658                 lex >> float_placement;
659
660         } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
661                 string toktmp = pdfoptions().readToken(lex, token);
662                 if (!toktmp.empty()) {
663                         lyxerr << "PDFOptions::readToken(): Unknown token: " <<
664                                 toktmp << endl;
665                         return toktmp;
666                 }
667         } else {
668                 lyxerr << "BufferParams::readToken(): Unknown token: " << 
669                         token << endl;
670                 return token;
671         }
672
673         return string();
674 }
675
676
677 void BufferParams::writeFile(ostream & os) const
678 {
679         // The top of the file is written by the buffer.
680         // Prints out the buffer info into the .lyx file given by file
681
682         // the textclass
683         os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
684
685         // then the preamble
686         if (!preamble.empty()) {
687                 // remove '\n' from the end of preamble
688                 string const tmppreamble = rtrim(preamble, "\n");
689                 os << "\\begin_preamble\n"
690                    << tmppreamble
691                    << "\n\\end_preamble\n";
692         }
693
694         // the options
695         if (!options.empty()) {
696                 os << "\\options " << options << '\n';
697         }
698         
699         //the modules
700         if (!layoutModules_.empty()) {
701                 os << "\\begin_modules" << '\n';
702                 LayoutModuleList::const_iterator it = layoutModules_.begin();
703                 for (; it != layoutModules_.end(); it++)
704                         os << *it << '\n';
705                 os << "\\end_modules" << '\n';
706         }
707
708         // then the text parameters
709         if (language != ignore_language)
710                 os << "\\language " << language->lang() << '\n';
711         os << "\\inputencoding " << inputenc
712            << "\n\\font_roman " << fontsRoman
713            << "\n\\font_sans " << fontsSans
714            << "\n\\font_typewriter " << fontsTypewriter
715            << "\n\\font_default_family " << fontsDefaultFamily
716            << "\n\\font_sc " << convert<string>(fontsSC)
717            << "\n\\font_osf " << convert<string>(fontsOSF)
718            << "\n\\font_sf_scale " << fontsSansScale
719            << "\n\\font_tt_scale " << fontsTypewriterScale
720            << "\n\\graphics " << graphicsDriver << '\n';
721
722         if (!float_placement.empty()) {
723                 os << "\\float_placement " << float_placement << '\n';
724         }
725         os << "\\paperfontsize " << fontsize << '\n';
726
727         spacing().writeFile(os);
728         pdfoptions().writeFile(os);
729
730         os << "\\papersize " << string_papersize[papersize]
731            << "\n\\use_geometry " << convert<string>(use_geometry)
732            << "\n\\use_amsmath " << use_amsmath
733            << "\n\\use_esint " << use_esint
734            << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
735            << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
736            << "\n\\paperorientation " << string_orientation[orientation]
737            << '\n';
738
739         BranchList::const_iterator it = branchlist().begin();
740         BranchList::const_iterator end = branchlist().end();
741         for (; it != end; ++it) {
742                 os << "\\branch " << to_utf8(it->getBranch())
743                    << "\n\\selected " << it->getSelected()
744                    << "\n\\color " << lyx::X11hexname(it->getColor())
745                    << "\n\\end_branch"
746                    << "\n";
747         }
748
749         if (!paperwidth.empty())
750                 os << "\\paperwidth "
751                    << VSpace(paperwidth).asLyXCommand() << '\n';
752         if (!paperheight.empty())
753                 os << "\\paperheight "
754                    << VSpace(paperheight).asLyXCommand() << '\n';
755         if (!leftmargin.empty())
756                 os << "\\leftmargin "
757                    << VSpace(leftmargin).asLyXCommand() << '\n';
758         if (!topmargin.empty())
759                 os << "\\topmargin "
760                    << VSpace(topmargin).asLyXCommand() << '\n';
761         if (!rightmargin.empty())
762                 os << "\\rightmargin "
763                    << VSpace(rightmargin).asLyXCommand() << '\n';
764         if (!bottommargin.empty())
765                 os << "\\bottommargin "
766                    << VSpace(bottommargin).asLyXCommand() << '\n';
767         if (!headheight.empty())
768                 os << "\\headheight "
769                    << VSpace(headheight).asLyXCommand() << '\n';
770         if (!headsep.empty())
771                 os << "\\headsep "
772                    << VSpace(headsep).asLyXCommand() << '\n';
773         if (!footskip.empty())
774                 os << "\\footskip "
775                    << VSpace(footskip).asLyXCommand() << '\n';
776         os << "\\secnumdepth " << secnumdepth
777            << "\n\\tocdepth " << tocdepth
778            << "\n\\paragraph_separation "
779            << string_paragraph_separation[paragraph_separation]
780            << "\n\\defskip " << getDefSkip().asLyXCommand()
781            << "\n\\quotes_language "
782            << string_quotes_language[quotes_language]
783            << "\n\\papercolumns " << columns
784            << "\n\\papersides " << sides
785            << "\n\\paperpagestyle " << pagestyle << '\n';
786         if (!listings_params.empty())
787                 os << "\\listings_params \"" <<
788                         InsetListingsParams(listings_params).encodedString() << "\"\n";
789         for (int i = 0; i < 4; ++i) {
790                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
791                         if (user_defined_bullet(i).getFont() != -1) {
792                                 os << "\\bullet " << i << " "
793                                    << user_defined_bullet(i).getFont() << " "
794                                    << user_defined_bullet(i).getCharacter() << " "
795                                    << user_defined_bullet(i).getSize() << "\n";
796                         }
797                         else {
798                                 // FIXME UNICODE
799                                 os << "\\bulletLaTeX " << i << " \""
800                                    << lyx::to_ascii(user_defined_bullet(i).getText())
801                                    << "\"\n";
802                         }
803                 }
804         }
805
806         os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
807         os << "\\output_changes " << convert<string>(outputChanges) << "\n";
808
809         AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
810         AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
811         for (; a_it != a_end; ++a_it) {
812                 if (a_it->second.used())
813                         os << "\\author " << a_it->second << "\n";
814                 else
815                         os << "\\author " << Author() << "\n";
816         }
817 }
818
819
820 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
821                               TexRow & texrow) const
822 {
823         os << "\\documentclass";
824
825         TextClass const & tclass = getTextClass();
826
827         ostringstream clsoptions; // the document class options.
828
829         if (tokenPos(tclass.opt_fontsize(),
830                      '|', fontsize) >= 0) {
831                 // only write if existing in list (and not default)
832                 clsoptions << fontsize << "pt,";
833         }
834
835         // custom, A3, B3 and B4 paper sizes need geometry
836         bool nonstandard_papersize = papersize == PAPER_B3
837                 || papersize == PAPER_B4
838                 || papersize == PAPER_A3
839                 || papersize == PAPER_CUSTOM;
840
841         if (!use_geometry) {
842                 switch (papersize) {
843                 case PAPER_A4:
844                         clsoptions << "a4paper,";
845                         break;
846                 case PAPER_USLETTER:
847                         clsoptions << "letterpaper,";
848                         break;
849                 case PAPER_A5:
850                         clsoptions << "a5paper,";
851                         break;
852                 case PAPER_B5:
853                         clsoptions << "b5paper,";
854                         break;
855                 case PAPER_USEXECUTIVE:
856                         clsoptions << "executivepaper,";
857                         break;
858                 case PAPER_USLEGAL:
859                         clsoptions << "legalpaper,";
860                         break;
861                 case PAPER_DEFAULT:
862                 case PAPER_A3:
863                 case PAPER_B3:
864                 case PAPER_B4:
865                 case PAPER_CUSTOM:
866                         break;
867                 }
868         }
869
870         // if needed
871         if (sides != tclass.sides()) {
872                 switch (sides) {
873                 case OneSide:
874                         clsoptions << "oneside,";
875                         break;
876                 case TwoSides:
877                         clsoptions << "twoside,";
878                         break;
879                 }
880         }
881
882         // if needed
883         if (columns != tclass.columns()) {
884                 if (columns == 2)
885                         clsoptions << "twocolumn,";
886                 else
887                         clsoptions << "onecolumn,";
888         }
889
890         if (!use_geometry
891             && orientation == ORIENTATION_LANDSCAPE)
892                 clsoptions << "landscape,";
893
894         // language should be a parameter to \documentclass
895         if (language->babel() == "hebrew"
896             && default_language->babel() != "hebrew")
897                 // This seems necessary
898                 features.useLanguage(default_language);
899
900         ostringstream language_options;
901         bool const use_babel = features.useBabel();
902         if (use_babel) {
903                 language_options << features.getLanguages();
904                 if (!language->babel().empty()) {
905                         if (!language_options.str().empty())
906                                 language_options << ',';
907                         language_options << language->babel();
908                 }
909                 // when Vietnamese is used, babel must directly be loaded with the
910                 // language options, not in the class options, see
911                 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
912                 size_t viet = language_options.str().find("vietnam");
913                 // viet = string::npos when not found
914                 if (lyxrc.language_global_options && !language_options.str().empty()
915                         && viet == string::npos)
916                         clsoptions << language_options.str() << ',';
917         }
918
919         // the user-defined options
920         if (!options.empty()) {
921                 clsoptions << options << ',';
922         }
923
924         string strOptions(clsoptions.str());
925         if (!strOptions.empty()) {
926                 strOptions = rtrim(strOptions, ",");
927                 // FIXME UNICODE
928                 os << '[' << from_utf8(strOptions) << ']';
929         }
930
931         os << '{' << from_ascii(tclass.latexname()) << "}\n";
932         texrow.newline();
933         // end of \documentclass defs
934
935         // font selection must be done before loading fontenc.sty
936         string const fonts =
937                 loadFonts(fontsRoman, fontsSans,
938                           fontsTypewriter, fontsSC, fontsOSF,
939                           fontsSansScale, fontsTypewriterScale);
940         if (!fonts.empty()) {
941                 os << from_ascii(fonts);
942                 texrow.newline();
943         }
944         if (fontsDefaultFamily != "default")
945                 os << "\\renewcommand{\\familydefault}{\\"
946                    << from_ascii(fontsDefaultFamily) << "}\n";
947
948         // set font encoding
949         // this one is not per buffer
950         // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
951         if (lyxrc.fontenc != "default") {
952                 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
953                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
954                            << ",LFE,LAE]{fontenc}\n";
955                         texrow.newline();
956                 } else {
957                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
958                            << "]{fontenc}\n";
959                         texrow.newline();
960                 }
961         }
962
963         // handle inputenc etc.
964         writeEncodingPreamble(os, features, texrow);
965
966         if (!listings_params.empty()) {
967                 os << "\\usepackage{listings}\n";
968                 texrow.newline();
969                 os << "\\lstset{";
970                 // do not test validity because listings_params is supposed to be valid
971                 string par = InsetListingsParams(listings_params).separatedParams(true);
972                 os << from_ascii(par);
973                 // count the number of newlines
974                 for (size_t i = 0; i < par.size(); ++i)
975                         if (par[i] == '\n')
976                                 texrow.newline();
977                 os << "}\n";
978                 texrow.newline();
979         }
980         if (use_geometry || nonstandard_papersize) {
981                 os << "\\usepackage{geometry}\n";
982                 texrow.newline();
983                 os << "\\geometry{verbose";
984                 if (orientation == ORIENTATION_LANDSCAPE)
985                         os << ",landscape";
986                 switch (papersize) {
987                 case PAPER_CUSTOM:
988                         if (!paperwidth.empty())
989                                 os << ",paperwidth="
990                                    << from_ascii(paperwidth);
991                         if (!paperheight.empty())
992                                 os << ",paperheight="
993                                    << from_ascii(paperheight);
994                         break;
995                 case PAPER_USLETTER:
996                         os << ",letterpaper";
997                         break;
998                 case PAPER_USLEGAL:
999                         os << ",legalpaper";
1000                         break;
1001                 case PAPER_USEXECUTIVE:
1002                         os << ",executivepaper";
1003                         break;
1004                 case PAPER_A3:
1005                         os << ",a3paper";
1006                         break;
1007                 case PAPER_A4:
1008                         os << ",a4paper";
1009                         break;
1010                 case PAPER_A5:
1011                         os << ",a5paper";
1012                         break;
1013                 case PAPER_B3:
1014                         os << ",b3paper";
1015                         break;
1016                 case PAPER_B4:
1017                         os << ",b4paper";
1018                         break;
1019                 case PAPER_B5:
1020                         os << ",b5paper";
1021                         break;
1022                 default:
1023                         // default papersize ie PAPER_DEFAULT
1024                         switch (lyxrc.default_papersize) {
1025                         case PAPER_DEFAULT: // keep compiler happy
1026                         case PAPER_USLETTER:
1027                                 os << ",letterpaper";
1028                                 break;
1029                         case PAPER_USLEGAL:
1030                                 os << ",legalpaper";
1031                                 break;
1032                         case PAPER_USEXECUTIVE:
1033                                 os << ",executivepaper";
1034                                 break;
1035                         case PAPER_A3:
1036                                 os << ",a3paper";
1037                                 break;
1038                         case PAPER_A4:
1039                                 os << ",a4paper";
1040                                 break;
1041                         case PAPER_A5:
1042                                 os << ",a5paper";
1043                                 break;
1044                         case PAPER_B5:
1045                                 os << ",b5paper";
1046                                 break;
1047                         case PAPER_B3:
1048                         case PAPER_B4:
1049                         case PAPER_CUSTOM:
1050                                 break;
1051                         }
1052                 }
1053                 if (!topmargin.empty())
1054                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1055                 if (!bottommargin.empty())
1056                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1057                 if (!leftmargin.empty())
1058                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1059                 if (!rightmargin.empty())
1060                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1061                 if (!headheight.empty())
1062                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1063                 if (!headsep.empty())
1064                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1065                 if (!footskip.empty())
1066                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1067                 os << "}\n";
1068                 texrow.newline();
1069         }
1070
1071         if (tokenPos(tclass.opt_pagestyle(),
1072                      '|', pagestyle) >= 0) {
1073                 if (pagestyle == "fancy") {
1074                         os << "\\usepackage{fancyhdr}\n";
1075                         texrow.newline();
1076                 }
1077                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1078                 texrow.newline();
1079         }
1080
1081         // Only if class has a ToC hierarchy
1082         if (tclass.hasTocLevels()) {
1083                 if (secnumdepth != tclass.secnumdepth()) {
1084                         os << "\\setcounter{secnumdepth}{"
1085                            << secnumdepth
1086                            << "}\n";
1087                         texrow.newline();
1088                 }
1089                 if (tocdepth != tclass.tocdepth()) {
1090                         os << "\\setcounter{tocdepth}{"
1091                            << tocdepth
1092                            << "}\n";
1093                         texrow.newline();
1094                 }
1095         }
1096
1097         if (paragraph_separation) {
1098                 switch (getDefSkip().kind()) {
1099                 case VSpace::SMALLSKIP:
1100                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1101                         break;
1102                 case VSpace::MEDSKIP:
1103                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1104                         break;
1105                 case VSpace::BIGSKIP:
1106                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1107                         break;
1108                 case VSpace::LENGTH:
1109                         os << "\\setlength{\\parskip}{"
1110                            << from_utf8(getDefSkip().length().asLatexString())
1111                            << "}\n";
1112                         break;
1113                 default: // should never happen // Then delete it.
1114                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1115                         break;
1116                 }
1117                 texrow.newline();
1118
1119                 os << "\\setlength{\\parindent}{0pt}\n";
1120                 texrow.newline();
1121         }
1122
1123         // If we use jurabib, we have to call babel here.
1124         if (use_babel && features.isRequired("jurabib")) {
1125                 os << from_ascii(babelCall(language_options.str()))
1126                    << '\n'
1127                    << from_ascii(features.getBabelOptions());
1128                 texrow.newline();
1129         }
1130
1131         // Now insert the LyX specific LaTeX commands...
1132
1133         // The optional packages;
1134         docstring lyxpreamble(from_ascii(features.getPackages()));
1135
1136         // We try to load babel late, in case it interferes
1137         // with other packages. But some packages also need babel to be loaded
1138         // before, e.g. jurabib has to be called after babel.
1139         // So load babel after the optional packages but before the user-defined
1140         // preamble. This allows the users to redefine babel commands, e.g. to
1141         // translate the word "Index" to the German "Stichwortverzeichnis".
1142         // For more infos why this place was chosen, see
1143         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1144         // If you encounter problems, you can shift babel to its old place behind
1145         // the user-defined preamble. But in this case you must change the Vietnamese
1146         // support from currently "\usepackage[vietnamese]{babel}" to:
1147         // \usepackage{vietnamese}
1148         // \usepackage{babel}
1149         // because vietnamese must be loaded before hyperref
1150         if (use_babel && !features.isRequired("jurabib")) {
1151                 // FIXME UNICODE
1152                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1153                 lyxpreamble += from_utf8(features.getBabelOptions());
1154         }
1155
1156         // When the language "japanese-plain" is used, the package "japanese" must
1157         // be loaded behind babel (it provides babel support for Japanese) but before
1158         // hyperref, see
1159         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1160         if (language->lang() == "japanese-plain" &&
1161                 !getTextClass().provides("japanese")) {
1162                 //load babel in case it was not loaded due to an empty language list
1163                 if (language_options.str().empty())
1164                         lyxpreamble += "\\usepackage{babel}\n";
1165                 lyxpreamble += "\\usepackage{japanese}\n";
1166         }
1167
1168         // PDF support.
1169         // * Hyperref manual: "Make sure it comes last of your loaded
1170         //   packages, to give it a fighting chance of not being over-written,
1171         //   since its job is to redefine many LATEX commands."
1172         // * Email from Heiko Oberdiek: "It is usually better to load babel
1173         //   before hyperref. Then hyperref has a chance to detect babel.
1174         // * Has to be loaded before the "LyX specific LaTeX commands" to
1175         //   avoid errors with algorithm floats.
1176         odocstringstream oss;
1177         // use hyperref explicitely when it is required
1178         pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1179         lyxpreamble += oss.str();
1180
1181         // this might be useful...
1182         lyxpreamble += "\n\\makeatletter\n";
1183
1184         // Some macros LyX will need
1185         docstring tmppreamble(from_ascii(features.getMacros()));
1186
1187         if (!tmppreamble.empty()) {
1188                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1189                         "LyX specific LaTeX commands.\n"
1190                         + tmppreamble + '\n';
1191         }
1192
1193         // the text class specific preamble
1194         tmppreamble = features.getTClassPreamble();
1195         if (!tmppreamble.empty()) {
1196                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1197                         "Textclass specific LaTeX commands.\n"
1198                         + tmppreamble + '\n';
1199         }
1200
1201         /* the user-defined preamble */
1202         if (!preamble.empty()) {
1203                 // FIXME UNICODE
1204                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1205                         "User specified LaTeX commands.\n"
1206                         + from_utf8(preamble) + '\n';
1207         }
1208
1209         // Itemize bullet settings need to be last in case the user
1210         // defines their own bullets that use a package included
1211         // in the user-defined preamble -- ARRae
1212         // Actually it has to be done much later than that
1213         // since some packages like frenchb make modifications
1214         // at \begin{document} time -- JMarc
1215         docstring bullets_def;
1216         for (int i = 0; i < 4; ++i) {
1217                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1218                         if (bullets_def.empty())
1219                                 bullets_def += "\\AtBeginDocument{\n";
1220                         bullets_def += "  \\def\\labelitemi";
1221                         switch (i) {
1222                                 // `i' is one less than the item to modify
1223                         case 0:
1224                                 break;
1225                         case 1:
1226                                 bullets_def += 'i';
1227                                 break;
1228                         case 2:
1229                                 bullets_def += "ii";
1230                                 break;
1231                         case 3:
1232                                 bullets_def += 'v';
1233                                 break;
1234                         }
1235                         bullets_def += '{' +
1236                                 user_defined_bullet(i).getText()
1237                                 + "}\n";
1238                 }
1239         }
1240
1241         if (!bullets_def.empty())
1242                 lyxpreamble += bullets_def + "}\n\n";
1243
1244         lyxpreamble += "\\makeatother\n\n";
1245
1246         int const nlines =
1247                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1248         for (int j = 0; j != nlines; ++j) {
1249                 texrow.newline();
1250         }
1251
1252         os << lyxpreamble;
1253         return use_babel;
1254 }
1255
1256
1257 void BufferParams::useClassDefaults()
1258 {
1259         TextClass const & tclass = textclasslist[baseClass_];
1260
1261         sides = tclass.sides();
1262         columns = tclass.columns();
1263         pagestyle = tclass.pagestyle();
1264         options = tclass.options();
1265         // Only if class has a ToC hierarchy
1266         if (tclass.hasTocLevels()) {
1267                 secnumdepth = tclass.secnumdepth();
1268                 tocdepth = tclass.tocdepth();
1269         }
1270 }
1271
1272
1273 bool BufferParams::hasClassDefaults() const
1274 {
1275         TextClass const & tclass = textclasslist[baseClass_];
1276
1277         return (sides == tclass.sides()
1278                 && columns == tclass.columns()
1279                 && pagestyle == tclass.pagestyle()
1280                 && options == tclass.options()
1281                 && secnumdepth == tclass.secnumdepth()
1282                 && tocdepth == tclass.tocdepth());
1283 }
1284
1285
1286 TextClass const & BufferParams::getTextClass() const
1287 {
1288         return *textClass_;
1289 }
1290
1291
1292 TextClassPtr BufferParams::getTextClassPtr() const {
1293         return textClass_;
1294 }
1295
1296
1297 void BufferParams::setTextClass(TextClassPtr tc) {
1298         textClass_ = tc;
1299 }
1300
1301
1302 bool BufferParams::setBaseClass(textclass_type tc)
1303 {
1304         bool retVal = true;
1305         if (textclasslist[tc].load())
1306                 baseClass_ = tc;
1307         else {
1308                 docstring s = 
1309                         bformat(_("The document class %1$s could not be loaded."),
1310                  from_utf8(textclasslist[tc].name()));
1311                 frontend::Alert::error(_("Could not load class"), s);
1312                 retVal = false;
1313         }
1314         makeTextClass();
1315         return retVal;
1316 }
1317
1318
1319 void BufferParams::setJustBaseClass(textclass_type tc)
1320
1321         baseClass_ = tc; 
1322 }
1323
1324
1325 textclass_type BufferParams::getBaseClass() const
1326 {
1327         return baseClass_;
1328 }
1329
1330
1331 void BufferParams::makeTextClass()
1332 {
1333         textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1334         //FIXME It might be worth loading the children's modules here,
1335         //just as we load their bibliographies and such, instead of just 
1336         //doing a check in InsetInclude.
1337         LayoutModuleList::const_iterator it = layoutModules_.begin();
1338         for (; it != layoutModules_.end(); it++) {
1339                 string const modName = *it;
1340                 LyXModule * lm = moduleList[modName];
1341                 if (!lm) {
1342                         docstring const msg =
1343                                 bformat(_("The module %1$s has been requested by\n"
1344                                         "this document but has not been found in the list of\n"
1345                                         "available modules. If you recently installed it, you\n"
1346                                         "probalby need to reconfigure LyX.\n"), from_utf8(modName));
1347                         frontend::Alert::warning(_("Module not available"),
1348                                         msg + _("Some layouts may not be available."));
1349                         lyxerr << "BufferParams::makeTextClass(): Module " <<
1350                                         modName << " requested but not found in module list." <<
1351                                         endl;
1352                         continue;
1353                 }
1354                 FileName layout_file = libFileSearch("layouts", lm->filename);
1355                 textClass_->read(layout_file, TextClass::MODULE);
1356         }
1357 }
1358
1359
1360 std::vector<string> const & BufferParams::getModules() const {
1361         return layoutModules_;
1362 }
1363
1364
1365
1366 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1367         LayoutModuleList::const_iterator it = layoutModules_.begin();
1368         LayoutModuleList::const_iterator end = layoutModules_.end();
1369         for (; it != end; it++) {
1370                 if (*it == modName) 
1371                         break;
1372         }
1373         if (it != layoutModules_.end())
1374                 return false;
1375         layoutModules_.push_back(modName);
1376         if (makeClass)
1377                 makeTextClass();
1378         return true;
1379 }
1380
1381
1382 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1383 {
1384         bool retval = true;
1385         std::vector<string>::const_iterator it = modNames.begin();
1386         std::vector<string>::const_iterator end = modNames.end();
1387         for (; it != end; ++it)
1388                 retval &= addLayoutModule(*it, false);
1389         makeTextClass();
1390         return retval;
1391 }
1392
1393
1394 void BufferParams::clearLayoutModules() {
1395         layoutModules_.clear();
1396         makeTextClass();
1397 }
1398
1399
1400 Font const BufferParams::getFont() const
1401 {
1402         FontInfo f = getTextClass().defaultfont();
1403         if (fontsDefaultFamily == "rmdefault")
1404                 f.setFamily(ROMAN_FAMILY);
1405         else if (fontsDefaultFamily == "sfdefault")
1406                 f.setFamily(SANS_FAMILY);
1407         else if (fontsDefaultFamily == "ttdefault")
1408                 f.setFamily(TYPEWRITER_FAMILY);
1409         return Font(f, language);
1410 }
1411
1412
1413 void BufferParams::readPreamble(Lexer & lex)
1414 {
1415         if (lex.getString() != "\\begin_preamble")
1416                 lyxerr << "Error (BufferParams::readPreamble):"
1417                         "consistency check failed." << endl;
1418
1419         preamble = lex.getLongString("\\end_preamble");
1420 }
1421
1422
1423 void BufferParams::readLanguage(Lexer & lex)
1424 {
1425         if (!lex.next()) return;
1426
1427         string const tmptok = lex.getString();
1428
1429         // check if tmptok is part of tex_babel in tex-defs.h
1430         language = languages.getLanguage(tmptok);
1431         if (!language) {
1432                 // Language tmptok was not found
1433                 language = default_language;
1434                 lyxerr << "Warning: Setting language `"
1435                        << tmptok << "' to `" << language->lang()
1436                        << "'." << endl;
1437         }
1438 }
1439
1440
1441 void BufferParams::readGraphicsDriver(Lexer & lex)
1442 {
1443         if (!lex.next()) return;
1444
1445         string const tmptok = lex.getString();
1446         // check if tmptok is part of tex_graphics in tex_defs.h
1447         int n = 0;
1448         while (true) {
1449                 string const test = tex_graphics[n++];
1450
1451                 if (test == tmptok) {
1452                         graphicsDriver = tmptok;
1453                         break;
1454                 } else if (test == "") {
1455                         lex.printError(
1456                                 "Warning: graphics driver `$$Token' not recognized!\n"
1457                                 "         Setting graphics driver to `default'.\n");
1458                         graphicsDriver = "default";
1459                         break;
1460                 }
1461         }
1462 }
1463
1464
1465 void BufferParams::readBullets(Lexer & lex)
1466 {
1467         if (!lex.next()) return;
1468
1469         int const index = lex.getInteger();
1470         lex.next();
1471         int temp_int = lex.getInteger();
1472         user_defined_bullet(index).setFont(temp_int);
1473         temp_bullet(index).setFont(temp_int);
1474         lex >> temp_int;
1475         user_defined_bullet(index).setCharacter(temp_int);
1476         temp_bullet(index).setCharacter(temp_int);
1477         lex >> temp_int;
1478         user_defined_bullet(index).setSize(temp_int);
1479         temp_bullet(index).setSize(temp_int);
1480 }
1481
1482
1483 void BufferParams::readBulletsLaTeX(Lexer & lex)
1484 {
1485         // The bullet class should be able to read this.
1486         if (!lex.next()) return;
1487         int const index = lex.getInteger();
1488         lex.next(true);
1489         docstring const temp_str = lex.getDocString();
1490
1491         user_defined_bullet(index).setText(temp_str);
1492         temp_bullet(index).setText(temp_str);
1493 }
1494
1495
1496 void BufferParams::readModules(Lexer & lex)
1497 {
1498         if (!lex.eatLine()) {
1499                 lyxerr << "Error (BufferParams::readModules):"
1500                                 "Unexpected end of input." << endl;
1501                 return;
1502         }
1503         while (true) {
1504                 string mod = lex.getString();
1505                 if (mod == "\\end_modules")
1506                         break;
1507                 addLayoutModule(mod);
1508                 lex.eatLine();
1509         }
1510 }
1511
1512
1513 string const BufferParams::paperSizeName() const
1514 {
1515         char real_papersize = papersize;
1516         if (real_papersize == PAPER_DEFAULT)
1517                 real_papersize = lyxrc.default_papersize;
1518
1519         switch (real_papersize) {
1520         case PAPER_A3:
1521                 return "a3";
1522         case PAPER_A4:
1523                 return "a4";
1524         case PAPER_A5:
1525                 return "a5";
1526         case PAPER_B5:
1527                 return "b5";
1528         case PAPER_USEXECUTIVE:
1529                 return "foolscap";
1530         case PAPER_USLEGAL:
1531                 return "legal";
1532         case PAPER_USLETTER:
1533         default:
1534                 return "letter";
1535         }
1536 }
1537
1538
1539 string const BufferParams::dvips_options() const
1540 {
1541         string result;
1542
1543         if (use_geometry
1544             && papersize == PAPER_CUSTOM
1545             && !lyxrc.print_paper_dimension_flag.empty()
1546             && !paperwidth.empty()
1547             && !paperheight.empty()) {
1548                 // using a custom papersize
1549                 result = lyxrc.print_paper_dimension_flag;
1550                 result += ' ' + paperwidth;
1551                 result += ',' + paperheight;
1552         } else {
1553                 string const paper_option = paperSizeName();
1554                 if (paper_option != "letter" ||
1555                     orientation != ORIENTATION_LANDSCAPE) {
1556                         // dvips won't accept -t letter -t landscape.
1557                         // In all other cases, include the paper size
1558                         // explicitly.
1559                         result = lyxrc.print_paper_flag;
1560                         result += ' ' + paper_option;
1561                 }
1562         }
1563         if (orientation == ORIENTATION_LANDSCAPE &&
1564             papersize != PAPER_CUSTOM)
1565                 result += ' ' + lyxrc.print_landscape_flag;
1566         return result;
1567 }
1568
1569
1570 string const BufferParams::babelCall(string const & lang_opts) const
1571 {
1572         string lang_pack = lyxrc.language_package;
1573         if (lang_pack != "\\usepackage{babel}")
1574                 return lang_pack;
1575         // suppress the babel call when there is no babel language defined
1576         // for the document language in the lib/languages file and if no
1577         // other languages are used (lang_opts is then empty)
1578         if (lang_opts.empty())
1579                 return string();
1580         // when Vietnamese is used, babel must directly be loaded with the
1581         // language options, see
1582         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1583         size_t viet = lang_opts.find("vietnam");
1584         // viet = string::npos when not found
1585         if (!lyxrc.language_global_options || viet != string::npos)
1586                 return "\\usepackage[" + lang_opts + "]{babel}";
1587         return lang_pack;
1588 }
1589
1590
1591 void BufferParams::writeEncodingPreamble(odocstream & os,
1592                 LaTeXFeatures & features, TexRow & texrow) const
1593 {
1594         if (inputenc == "auto") {
1595                 string const doc_encoding =
1596                         language->encoding()->latexName();
1597                 Encoding::Package const package =
1598                         language->encoding()->package();
1599
1600                 // Create a list with all the input encodings used
1601                 // in the document
1602                 std::set<string> encodings =
1603                         features.getEncodingSet(doc_encoding);
1604
1605                 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1606                 // package inputenc must be omitted. Therefore set the encoding to empty.
1607                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1608                 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1609                         doc_encoding == "SJIS-plain")
1610                         encodings.clear();
1611
1612                 if (!encodings.empty() || package == Encoding::inputenc) {
1613                         os << "\\usepackage[";
1614                         std::set<string>::const_iterator it = encodings.begin();
1615                         std::set<string>::const_iterator const end = encodings.end();
1616                         if (it != end) {
1617                                 os << from_ascii(*it);
1618                                 ++it;
1619                         }
1620                         for (; it != end; ++it)
1621                                 os << ',' << from_ascii(*it);
1622                         if (package == Encoding::inputenc) {
1623                                 if (!encodings.empty())
1624                                         os << ',';
1625                                 os << from_ascii(doc_encoding);
1626                         }
1627                         os << "]{inputenc}\n";
1628                         texrow.newline();
1629                 }
1630                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1631                         os << "\\usepackage{CJK}\n";
1632                         texrow.newline();
1633                 }
1634         } else if (inputenc != "default") {
1635                 switch (encoding().package()) {
1636                 case Encoding::none:
1637                         break;
1638                 case Encoding::inputenc:
1639                         os << "\\usepackage[" << from_ascii(inputenc)
1640                            << "]{inputenc}\n";
1641                         texrow.newline();
1642                         break;
1643                 case Encoding::CJK:
1644                         os << "\\usepackage{CJK}\n";
1645                         texrow.newline();
1646                         break;
1647                 }
1648         }
1649
1650         // The encoding "armscii8" is only available when the package "armtex" is loaded.
1651         // armscii8 is used for Armenian.
1652         if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1653                 os << "\\usepackage{armtex}\n";
1654                 texrow.newline();
1655         }
1656 }
1657
1658
1659 string const BufferParams::loadFonts(string const & rm,
1660                                      string const & sf, string const & tt,
1661                                      bool const & sc, bool const & osf,
1662                                      int const & sfscale, int const & ttscale) const
1663 {
1664         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1665            several packages have been replaced by others, that might not
1666            be installed on every system. We have to take care for that
1667            (see psnfss.pdf). We try to support all psnfss fonts as well
1668            as the fonts that have become de facto standard in the LaTeX
1669            world (e.g. Latin Modern). We do not support obsolete fonts
1670            (like PSLatex). In general, it should be possible to mix any
1671            rm font with any sf or tt font, respectively. (JSpitzm)
1672            TODO:
1673                 -- separate math fonts.
1674         */
1675
1676         if (rm == "default" && sf == "default" && tt == "default")
1677                 //nothing to do
1678                 return string();
1679
1680         ostringstream os;
1681
1682         // ROMAN FONTS
1683         // Computer Modern (must be explicitely selectable -- there might be classes
1684         // that define a different default font!
1685         if (rm == "cmr") {
1686                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1687                 // osf for Computer Modern needs eco.sty
1688                 if (osf)
1689                         os << "\\usepackage{eco}\n";
1690         }
1691         // Latin Modern Roman
1692         else if (rm == "lmodern")
1693                 os << "\\usepackage{lmodern}\n";
1694         // AE
1695         else if (rm == "ae") {
1696                 // not needed when using OT1 font encoding.
1697                 if (lyxrc.fontenc != "default")
1698                         os << "\\usepackage{ae,aecompl}\n";
1699         }
1700         // Times
1701         else if (rm == "times") {
1702                 // try to load the best available package
1703                 if (LaTeXFeatures::isAvailable("mathptmx"))
1704                         os << "\\usepackage{mathptmx}\n";
1705                 else if (LaTeXFeatures::isAvailable("mathptm"))
1706                         os << "\\usepackage{mathptm}\n";
1707                 else
1708                         os << "\\usepackage{times}\n";
1709         }
1710         // Palatino
1711         else if (rm == "palatino") {
1712                 // try to load the best available package
1713                 if (LaTeXFeatures::isAvailable("mathpazo")) {
1714                         os << "\\usepackage";
1715                         if (osf || sc) {
1716                                 os << '[';
1717                                 if (!osf)
1718                                         os << "sc";
1719                                 else
1720                                         // "osf" includes "sc"!
1721                                         os << "osf";
1722                                 os << ']';
1723                         }
1724                         os << "{mathpazo}\n";
1725                 }
1726                 else if (LaTeXFeatures::isAvailable("mathpple"))
1727                         os << "\\usepackage{mathpple}\n";
1728                 else
1729                         os << "\\usepackage{palatino}\n";
1730         }
1731         // Utopia
1732         else if (rm == "utopia") {
1733                 // fourier supersedes utopia.sty, but does
1734                 // not work with OT1 encoding.
1735                 if (LaTeXFeatures::isAvailable("fourier")
1736                     && lyxrc.fontenc != "default") {
1737                         os << "\\usepackage";
1738                         if (osf || sc) {
1739                                 os << '[';
1740                                 if (sc)
1741                                         os << "expert";
1742                                 if (osf && sc)
1743                                         os << ',';
1744                                 if (osf)
1745                                         os << "oldstyle";
1746                                 os << ']';
1747                         }
1748                         os << "{fourier}\n";
1749                 }
1750                 else
1751                         os << "\\usepackage{utopia}\n";
1752         }
1753         // Bera (complete fontset)
1754         else if (rm == "bera" && sf == "default" && tt == "default")
1755                 os << "\\usepackage{bera}\n";
1756         // everything else
1757         else if (rm != "default")
1758                 os << "\\usepackage" << "{" << rm << "}\n";
1759
1760         // SANS SERIF
1761         // Helvetica, Bera Sans
1762         if (sf == "helvet" || sf == "berasans") {
1763                 if (sfscale != 100)
1764                         os << "\\usepackage[scaled=" << float(sfscale) / 100
1765                            << "]{" << sf << "}\n";
1766                 else
1767                         os << "\\usepackage{" << sf << "}\n";
1768         }
1769         // Avant Garde
1770         else if (sf == "avant")
1771                 os << "\\usepackage{" << sf << "}\n";
1772         // Computer Modern, Latin Modern, CM Bright
1773         else if (sf != "default")
1774                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1775
1776         // monospaced/typewriter
1777         // Courier, LuxiMono
1778         if (tt == "luximono" || tt == "beramono") {
1779                 if (ttscale != 100)
1780                         os << "\\usepackage[scaled=" << float(ttscale) / 100
1781                            << "]{" << tt << "}\n";
1782                 else
1783                         os << "\\usepackage{" << tt << "}\n";
1784         }
1785         // Courier
1786         else if (tt == "courier" )
1787                 os << "\\usepackage{" << tt << "}\n";
1788         // Computer Modern, Latin Modern, CM Bright
1789         else if  (tt != "default")
1790                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1791
1792         return os.str();
1793 }
1794
1795
1796 Encoding const & BufferParams::encoding() const
1797 {
1798         if (inputenc == "auto" || inputenc == "default")
1799                 return *(language->encoding());
1800         Encoding const * const enc =
1801                 encodings.getFromLaTeXName(inputenc);
1802         if (enc)
1803                 return *enc;
1804         lyxerr << "Unknown inputenc value `" << inputenc
1805                << "'. Using `auto' instead." << endl;
1806         return *(language->encoding());
1807 }
1808
1809
1810 biblio::CiteEngine BufferParams::getEngine() const
1811 {
1812         // FIXME the class should provide the numerical/
1813         // authoryear choice
1814         if (getTextClass().provides("natbib")
1815             && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1816                 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1817         return cite_engine_;
1818 }
1819
1820
1821 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1822 {
1823         cite_engine_ = cite_engine;
1824 }
1825
1826 } // namespace lyx