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