]> git.lyx.org Git - lyx.git/blob - src/bufferparams.C
* languages: use nb_NO instead of no_NO for norwegian (bug 2850).
[lyx.git] / src / bufferparams.C
1 /**
2  * \file bufferparams.C
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 "Bullet.h"
23 #include "debug.h"
24 #include "encoding.h"
25 #include "gettext.h"
26 #include "language.h"
27 #include "LaTeXFeatures.h"
28 #include "LColor.h"
29 #include "lyxfont.h"
30 #include "lyxlex.h"
31 #include "lyxrc.h"
32 #include "lyxtextclasslist.h"
33 #include "outputparams.h"
34 #include "tex-strings.h"
35 #include "Spacing.h"
36 #include "texrow.h"
37 #include "vspace.h"
38
39 #include "frontends/Alert.h"
40
41 #include "support/lyxalgo.h" // for lyx::count
42 #include "support/convert.h"
43 #include "support/translator.h"
44
45 #include <boost/array.hpp>
46
47 #include <sstream>
48
49
50 namespace lyx {
51
52 using support::bformat;
53 using support::rtrim;
54 using support::tokenPos;
55
56 using std::endl;
57 using std::string;
58 using std::istringstream;
59 using std::ostream;
60 using std::ostringstream;
61 using std::pair;
62
63 namespace Alert = lyx::frontend::Alert;
64
65
66 // Local translators
67 namespace {
68
69 // Paragraph separation
70 typedef Translator<string, BufferParams::PARSEP> ParSepTranslator;
71
72
73 ParSepTranslator const init_parseptranslator()
74 {
75         ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
76         translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
77         return translator;
78 }
79
80
81 ParSepTranslator const & parseptranslator()
82 {
83         static ParSepTranslator translator = init_parseptranslator();
84         return translator;
85 }
86
87
88 // Quotes language
89 typedef Translator<string, InsetQuotes::quote_language> QuotesLangTranslator;
90
91
92 QuotesLangTranslator const init_quoteslangtranslator()
93 {
94         QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
95         translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
96         translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
97         translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
98         translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
99         translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
100         return translator;
101 }
102
103
104 QuotesLangTranslator const & quoteslangtranslator()
105 {
106         static QuotesLangTranslator translator = init_quoteslangtranslator();
107         return translator;
108 }
109
110
111 // Paper size
112 typedef Translator<std::string, PAPER_SIZE> PaperSizeTranslator;
113
114
115 PaperSizeTranslator const init_papersizetranslator()
116 {
117         PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
118         translator.addPair(string_papersize[1], PAPER_CUSTOM);
119         translator.addPair(string_papersize[2], PAPER_USLETTER);
120         translator.addPair(string_papersize[3], PAPER_USLEGAL);
121         translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
122         translator.addPair(string_papersize[5], PAPER_A3);
123         translator.addPair(string_papersize[6], PAPER_A4);
124         translator.addPair(string_papersize[7], PAPER_A5);
125         translator.addPair(string_papersize[8], PAPER_B3);
126         translator.addPair(string_papersize[9], PAPER_B4);
127         translator.addPair(string_papersize[10], PAPER_B5);
128         return translator;
129 }
130
131
132 PaperSizeTranslator const & papersizetranslator()
133 {
134         static PaperSizeTranslator translator = init_papersizetranslator();
135         return translator;
136 }
137
138
139 // Paper orientation
140 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
141
142
143 PaperOrientationTranslator const init_paperorientationtranslator()
144 {
145         PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
146         translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
147         return translator;
148 }
149
150
151 PaperOrientationTranslator const & paperorientationtranslator()
152 {
153         static PaperOrientationTranslator translator = init_paperorientationtranslator();
154         return translator;
155 }
156
157
158 // Page sides
159 typedef Translator<int, LyXTextClass::PageSides> SidesTranslator;
160
161
162 SidesTranslator const init_sidestranslator()
163 {
164         SidesTranslator translator(1, LyXTextClass::OneSide);
165         translator.addPair(2, LyXTextClass::TwoSides);
166         return translator;
167 }
168
169
170 SidesTranslator const & sidestranslator()
171 {
172         static SidesTranslator translator = init_sidestranslator();
173         return translator;
174 }
175
176
177 // LaTeX packages
178 typedef Translator<int, BufferParams::Package> PackageTranslator;
179
180
181 PackageTranslator const init_packagetranslator()
182 {
183         PackageTranslator translator(0, BufferParams::package_off);
184         translator.addPair(1, BufferParams::package_auto);
185         translator.addPair(2, BufferParams::package_on);
186         return translator;
187 }
188
189
190 PackageTranslator const & packagetranslator()
191 {
192         static PackageTranslator translator = init_packagetranslator();
193         return translator;
194 }
195
196
197 // Cite engine
198 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
199
200
201 CiteEngineTranslator const init_citeenginetranslator()
202 {
203         CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
204         translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
205         translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
206         translator.addPair("jurabib", biblio::ENGINE_JURABIB);
207         return translator;
208 }
209
210
211 CiteEngineTranslator const & citeenginetranslator()
212 {
213         static CiteEngineTranslator translator = init_citeenginetranslator();
214         return translator;
215 }
216
217
218 // Spacing
219 typedef Translator<string, Spacing::Space> SpaceTranslator;
220
221
222 SpaceTranslator const init_spacetranslator()
223 {
224         SpaceTranslator translator("default", Spacing::Default);
225         translator.addPair("single", Spacing::Single);
226         translator.addPair("onehalf", Spacing::Onehalf);
227         translator.addPair("double", Spacing::Double);
228         translator.addPair("other", Spacing::Other);
229         return translator;
230 }
231
232
233 SpaceTranslator const & spacetranslator()
234 {
235         static SpaceTranslator translator = init_spacetranslator();
236         return translator;
237 }
238
239 // ends annonym namespace
240 }
241
242
243 class BufferParams::Impl
244 {
245 public:
246         Impl();
247
248         AuthorList authorlist;
249         BranchList branchlist;
250         boost::array<Bullet, 4> temp_bullets;
251         boost::array<Bullet, 4> user_defined_bullets;
252         Spacing spacing;
253         /** This is the amount of space used for paragraph_separation "skip",
254          * and for detached paragraphs in "indented" documents.
255          */
256         VSpace defskip;
257 };
258
259
260 BufferParams::Impl::Impl()
261         : defskip(VSpace::MEDSKIP)
262 {
263         // set initial author
264         authorlist.record(Author(lyxrc.user_name, lyxrc.user_email));
265 }
266
267
268 BufferParams::Impl *
269 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
270 {
271         BOOST_ASSERT(ptr);
272
273         return new BufferParams::Impl(*ptr);
274 }
275
276
277 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
278 {
279         delete ptr;
280 }
281
282
283 BufferParams::BufferParams()
284         : // Initialize textclass to point to article. if `first' is
285           // true in the returned pair, then `second' is the textclass
286           // number; if it is false, second is 0. In both cases, second
287           // is what we want.
288         textclass(textclasslist.numberOfClass("article").second),
289         pimpl_(new Impl)
290 {
291         paragraph_separation = PARSEP_INDENT;
292         quotes_language = InsetQuotes::EnglishQ;
293         fontsize = "default";
294
295         /*  PaperLayout */
296         papersize = PAPER_DEFAULT;
297         orientation = ORIENTATION_PORTRAIT;
298         use_geometry = false;
299         use_amsmath = package_auto;
300         use_esint = package_auto;
301         cite_engine = biblio::ENGINE_BASIC;
302         use_bibtopic = false;
303         trackChanges = false;
304         outputChanges = false;
305         secnumdepth = 3;
306         tocdepth = 3;
307         language = default_language;
308         fontsRoman = "default";
309         fontsSans = "default";
310         fontsTypewriter = "default";
311         fontsDefaultFamily = "default";
312         fontsSC = false;
313         fontsOSF = false;
314         fontsSansScale = 100;
315         fontsTypewriterScale = 100;
316         inputenc = "auto";
317         graphicsDriver = "default";
318         sides = LyXTextClass::OneSide;
319         columns = 1;
320         pagestyle = "default";
321         compressed = false;
322         for (int iter = 0; iter < 4; ++iter) {
323                 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
324                 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
325         }
326 }
327
328
329 BufferParams::~BufferParams()
330 {}
331
332
333 AuthorList & BufferParams::authors()
334 {
335         return pimpl_->authorlist;
336 }
337
338
339 AuthorList const & BufferParams::authors() const
340 {
341         return pimpl_->authorlist;
342 }
343
344
345 BranchList & BufferParams::branchlist()
346 {
347         return pimpl_->branchlist;
348 }
349
350
351 BranchList const & BufferParams::branchlist() const
352 {
353         return pimpl_->branchlist;
354 }
355
356
357 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
358 {
359         BOOST_ASSERT(index < 4);
360         return pimpl_->temp_bullets[index];
361 }
362
363
364 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
365 {
366         BOOST_ASSERT(index < 4);
367         return pimpl_->temp_bullets[index];
368 }
369
370
371 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
372 {
373         BOOST_ASSERT(index < 4);
374         return pimpl_->user_defined_bullets[index];
375 }
376
377
378 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
379 {
380         BOOST_ASSERT(index < 4);
381         return pimpl_->user_defined_bullets[index];
382 }
383
384
385 Spacing & BufferParams::spacing()
386 {
387         return pimpl_->spacing;
388 }
389
390
391 Spacing const & BufferParams::spacing() const
392 {
393         return pimpl_->spacing;
394 }
395
396
397 VSpace const & BufferParams::getDefSkip() const
398 {
399         return pimpl_->defskip;
400 }
401
402
403 void BufferParams::setDefSkip(VSpace const & vs)
404 {
405         pimpl_->defskip = vs;
406 }
407
408
409 string const BufferParams::readToken(LyXLex & lex, string const & token)
410 {
411         if (token == "\\textclass") {
412                 lex.next();
413                 string const classname = lex.getString();
414                 pair<bool, lyx::textclass_type> pp =
415                         textclasslist.numberOfClass(classname);
416                 if (pp.first) {
417                         textclass = pp.second;
418                 } else {
419                         // if text class does not exist, try to load it from filepath
420                         pp = textclasslist.addTextClass(classname, filepath);
421                         if (pp.first) {
422                                 textclass = pp.second;
423                         } else {
424                                 textclass = 0;
425                                 return classname;
426                         }
427                 }
428                 // FIXME: isTeXClassAvailable will try to load the layout file, but will
429                 // fail because of the lack of path info. Warnings will be given although
430                 // the layout file will be correctly loaded later.
431                 if (!getLyXTextClass().isTeXClassAvailable()) {
432                         docstring const msg =
433                                 bformat(_("The document uses a missing "
434                                                        "TeX class \"%1$s\".\n"), from_utf8(classname));
435                         Alert::warning(_("Document class not available"),
436                                        msg + _("LyX will not be able to produce output."));
437                 }
438         } else if (token == "\\begin_preamble") {
439                 readPreamble(lex);
440         } else if (token == "\\options") {
441                 lex.eatLine();
442                 options = lex.getString();
443         } else if (token == "\\language") {
444                 readLanguage(lex);
445         } else if (token == "\\inputencoding") {
446                 lex >> inputenc;
447         } else if (token == "\\graphics") {
448                 readGraphicsDriver(lex);
449         } else if (token == "\\font_roman") {
450                 lex >> fontsRoman;
451         } else if (token == "\\font_sans") {
452                 lex >> fontsSans;
453         } else if (token == "\\font_typewriter") {
454                 lex >> fontsTypewriter;
455         } else if (token == "\\font_default_family") {
456                 lex >> fontsDefaultFamily;
457         } else if (token == "\\font_sc") {
458                 lex >> fontsSC;
459         } else if (token == "\\font_osf") {
460                 lex >> fontsOSF;
461         } else if (token == "\\font_sf_scale") {
462                 lex >> fontsSansScale;
463         } else if (token == "\\font_tt_scale") {
464                 lex >> fontsTypewriterScale;
465         } else if (token == "\\paragraph_separation") {
466                 string parsep;
467                 lex >> parsep;
468                 paragraph_separation = parseptranslator().find(parsep);
469         } else if (token == "\\defskip") {
470                 lex.next();
471                 pimpl_->defskip = VSpace(lex.getString());
472         } else if (token == "\\quotes_language") {
473                 string quotes_lang;
474                 lex >> quotes_lang;
475                 quotes_language = quoteslangtranslator().find(quotes_lang);
476         } else if (token == "\\papersize") {
477                 string ppsize;
478                 lex >> ppsize;
479                 papersize = papersizetranslator().find(ppsize);
480         } else if (token == "\\use_geometry") {
481                 lex >> use_geometry;
482         } else if (token == "\\use_amsmath") {
483                 int use_ams;
484                 lex >> use_ams;
485                 use_amsmath = packagetranslator().find(use_ams);
486         } else if (token == "\\use_esint") {
487                 int useesint;
488                 lex >> useesint;
489                 use_esint = packagetranslator().find(useesint);
490         } else if (token == "\\cite_engine") {
491                 string engine;
492                 lex >> engine;
493                 cite_engine = citeenginetranslator().find(engine);
494         } else if (token == "\\use_bibtopic") {
495                 lex >> use_bibtopic;
496         } else if (token == "\\tracking_changes") {
497                 lex >> trackChanges;
498         } else if (token == "\\output_changes") {
499                 lex >> outputChanges;
500         } else if (token == "\\branch") {
501                 lex.next();
502                 docstring branch = lex.getDocString();
503                 branchlist().add(branch);
504                 while (true) {
505                         lex.next();
506                         string const tok = lex.getString();
507                         if (tok == "\\end_branch")
508                                 break;
509                         Branch * branch_ptr = branchlist().find(branch);
510                         if (tok == "\\selected") {
511                                 lex.next();
512                                 if (branch_ptr)
513                                         branch_ptr->setSelected(lex.getInteger());
514                         }
515                         // not yet operational
516                         if (tok == "\\color") {
517                                 lex.eatLine();
518                                 string color = lex.getString();
519                                 if (branch_ptr)
520                                         branch_ptr->setColor(color);
521                                 // Update also the LColor table:
522                                 if (color == "none")
523                                         color = lcolor.getX11Name(LColor::background);
524                                 // FIXME UNICODE
525                                 lcolor.setColor(to_utf8(branch), color);
526
527                         }
528                 }
529         } else if (token == "\\author") {
530                 lex.eatLine();
531                 istringstream ss(lex.getString());
532                 Author a;
533                 ss >> a;
534                 author_map.push_back(pimpl_->authorlist.record(a));
535         } else if (token == "\\paperorientation") {
536                 string orient;
537                 lex >> orient;
538                 orientation = paperorientationtranslator().find(orient);
539         } else if (token == "\\paperwidth") {
540                 lex >> paperwidth;
541         } else if (token == "\\paperheight") {
542                 lex >> paperheight;
543         } else if (token == "\\leftmargin") {
544                 lex >> leftmargin;
545         } else if (token == "\\topmargin") {
546                 lex >> topmargin;
547         } else if (token == "\\rightmargin") {
548                 lex >> rightmargin;
549         } else if (token == "\\bottommargin") {
550                 lex >> bottommargin;
551         } else if (token == "\\headheight") {
552                 lex >> headheight;
553         } else if (token == "\\headsep") {
554                 lex >> headsep;
555         } else if (token == "\\footskip") {
556                 lex >> footskip;
557         } else if (token == "\\paperfontsize") {
558                 lex >> fontsize;
559         } else if (token == "\\papercolumns") {
560                 lex >> columns;
561         } else if (token == "\\papersides") {
562                 int psides;
563                 lex >> psides;
564                 sides = sidestranslator().find(psides);
565         } else if (token == "\\paperpagestyle") {
566                 lex >> pagestyle;
567         } else if (token == "\\bullet") {
568                 readBullets(lex);
569         } else if (token == "\\bulletLaTeX") {
570                 readBulletsLaTeX(lex);
571         } else if (token == "\\secnumdepth") {
572                 lex >> secnumdepth;
573         } else if (token == "\\tocdepth") {
574                 lex >> tocdepth;
575         } else if (token == "\\spacing") {
576                 string nspacing;
577                 lex >> nspacing;
578                 string tmp_val;
579                 if (nspacing == "other") {
580                         lex >> tmp_val;
581                 }
582                 spacing().set(spacetranslator().find(nspacing), tmp_val);
583         } else if (token == "\\float_placement") {
584                 lex >> float_placement;
585         } else {
586                 return token;
587         }
588
589         return string();
590 }
591
592
593 void BufferParams::writeFile(ostream & os) const
594 {
595         // The top of the file is written by the buffer.
596         // Prints out the buffer info into the .lyx file given by file
597
598         // the textclass
599         os << "\\textclass " << textclasslist[textclass].name() << '\n';
600
601         // then the the preamble
602         if (!preamble.empty()) {
603                 // remove '\n' from the end of preamble
604                 string const tmppreamble = rtrim(preamble, "\n");
605                 os << "\\begin_preamble\n"
606                    << tmppreamble
607                    << "\n\\end_preamble\n";
608         }
609
610         // the options
611         if (!options.empty()) {
612                 os << "\\options " << options << '\n';
613         }
614
615         // then the text parameters
616         if (language != ignore_language)
617                 os << "\\language " << language->lang() << '\n';
618         os << "\\inputencoding " << inputenc
619            << "\n\\font_roman " << fontsRoman
620            << "\n\\font_sans " << fontsSans
621            << "\n\\font_typewriter " << fontsTypewriter
622            << "\n\\font_default_family " << fontsDefaultFamily
623            << "\n\\font_sc " << convert<string>(fontsSC)
624            << "\n\\font_osf " << convert<string>(fontsOSF)
625            << "\n\\font_sf_scale " << fontsSansScale
626            << "\n\\font_tt_scale " << fontsTypewriterScale
627            << "\n\\graphics " << graphicsDriver << '\n';
628
629         if (!float_placement.empty()) {
630                 os << "\\float_placement " << float_placement << '\n';
631         }
632         os << "\\paperfontsize " << fontsize << '\n';
633
634         spacing().writeFile(os);
635
636         os << "\\papersize " << string_papersize[papersize]
637            << "\n\\use_geometry " << convert<string>(use_geometry)
638            << "\n\\use_amsmath " << use_amsmath
639            << "\n\\use_esint " << use_esint
640            << "\n\\cite_engine " << citeenginetranslator().find(cite_engine)
641            << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
642            << "\n\\paperorientation " << string_orientation[orientation]
643            << '\n';
644
645         BranchList::const_iterator it = branchlist().begin();
646         BranchList::const_iterator end = branchlist().end();
647         for (; it != end; ++it) {
648                 os << "\\branch " << to_utf8(it->getBranch())
649                    << "\n\\selected " << it->getSelected()
650                    << "\n\\color " << lyx::X11hexname(it->getColor())
651                    << "\n\\end_branch"
652                    << "\n";
653         }
654
655         if (!paperwidth.empty())
656                 os << "\\paperwidth "
657                    << VSpace(paperwidth).asLyXCommand() << '\n';
658         if (!paperheight.empty())
659                 os << "\\paperheight "
660                    << VSpace(paperheight).asLyXCommand() << '\n';
661         if (!leftmargin.empty())
662                 os << "\\leftmargin "
663                    << VSpace(leftmargin).asLyXCommand() << '\n';
664         if (!topmargin.empty())
665                 os << "\\topmargin "
666                    << VSpace(topmargin).asLyXCommand() << '\n';
667         if (!rightmargin.empty())
668                 os << "\\rightmargin "
669                    << VSpace(rightmargin).asLyXCommand() << '\n';
670         if (!bottommargin.empty())
671                 os << "\\bottommargin "
672                    << VSpace(bottommargin).asLyXCommand() << '\n';
673         if (!headheight.empty())
674                 os << "\\headheight "
675                    << VSpace(headheight).asLyXCommand() << '\n';
676         if (!headsep.empty())
677                 os << "\\headsep "
678                    << VSpace(headsep).asLyXCommand() << '\n';
679         if (!footskip.empty())
680                 os << "\\footskip "
681                    << VSpace(footskip).asLyXCommand() << '\n';
682         os << "\\secnumdepth " << secnumdepth
683            << "\n\\tocdepth " << tocdepth
684            << "\n\\paragraph_separation "
685            << string_paragraph_separation[paragraph_separation]
686            << "\n\\defskip " << getDefSkip().asLyXCommand()
687            << "\n\\quotes_language "
688            << string_quotes_language[quotes_language]
689            << "\n\\papercolumns " << columns
690            << "\n\\papersides " << sides
691            << "\n\\paperpagestyle " << pagestyle << '\n';
692         for (int i = 0; i < 4; ++i) {
693                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
694                         if (user_defined_bullet(i).getFont() != -1) {
695                                 os << "\\bullet " << i << " "
696                                    << user_defined_bullet(i).getFont() << " "
697                                    << user_defined_bullet(i).getCharacter() << " "
698                                    << user_defined_bullet(i).getSize() << "\n";
699                         }
700                         else {
701                                 // FIXME UNICODE
702                                 os << "\\bulletLaTeX " << i << " \""
703                                    << lyx::to_ascii(user_defined_bullet(i).getText())
704                                    << "\"\n";
705                         }
706                 }
707         }
708
709         os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
710         os << "\\output_changes " << convert<string>(outputChanges) << "\n";
711
712         AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
713         AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
714         for (; a_it != a_end; ++a_it) {
715                 os << "\\author " << a_it->second << "\n";
716         }
717 }
718
719
720 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
721                               TexRow & texrow) const
722 {
723         os << "\\documentclass";
724
725         LyXTextClass const & tclass = getLyXTextClass();
726
727         ostringstream clsoptions; // the document class options.
728
729         if (tokenPos(tclass.opt_fontsize(),
730                      '|', fontsize) >= 0) {
731                 // only write if existing in list (and not default)
732                 clsoptions << fontsize << "pt,";
733         }
734
735         // custom, A3, B3 and B4 paper sizes need geometry
736         bool nonstandard_papersize = papersize == PAPER_B3 
737                 || papersize == PAPER_B4
738                 || papersize == PAPER_A3
739                 || papersize == PAPER_CUSTOM;
740
741         if (!use_geometry) {
742                 switch (papersize) {
743                 case PAPER_A4:
744                         clsoptions << "a4paper,";
745                         break;
746                 case PAPER_USLETTER:
747                         clsoptions << "letterpaper,";
748                         break;
749                 case PAPER_A5:
750                         clsoptions << "a5paper,";
751                         break;
752                 case PAPER_B5:
753                         clsoptions << "b5paper,";
754                         break;
755                 case PAPER_USEXECUTIVE:
756                         clsoptions << "executivepaper,";
757                         break;
758                 case PAPER_USLEGAL:
759                         clsoptions << "legalpaper,";
760                         break;
761                 case PAPER_DEFAULT:
762                 case PAPER_A3:
763                 case PAPER_B3:
764                 case PAPER_B4:
765                 case PAPER_CUSTOM:
766                         break;
767                 }
768         }
769
770         // if needed
771         if (sides != tclass.sides()) {
772                 switch (sides) {
773                 case LyXTextClass::OneSide:
774                         clsoptions << "oneside,";
775                         break;
776                 case LyXTextClass::TwoSides:
777                         clsoptions << "twoside,";
778                         break;
779                 }
780         }
781
782         // if needed
783         if (columns != tclass.columns()) {
784                 if (columns == 2)
785                         clsoptions << "twocolumn,";
786                 else
787                         clsoptions << "onecolumn,";
788         }
789
790         if (!use_geometry
791             && orientation == ORIENTATION_LANDSCAPE)
792                 clsoptions << "landscape,";
793
794         // language should be a parameter to \documentclass
795         if (language->babel() == "hebrew"
796             && default_language->babel() != "hebrew")
797                 // This seems necessary
798                 features.useLanguage(default_language);
799
800         ostringstream language_options;
801         bool const use_babel = features.useBabel();
802         if (use_babel) {
803                 language_options << features.getLanguages();
804                 language_options << language->babel();
805                 if (lyxrc.language_global_options)
806                         clsoptions << language_options.str() << ',';
807         }
808
809         // the user-defined options
810         if (!options.empty()) {
811                 clsoptions << options << ',';
812         }
813
814         string strOptions(clsoptions.str());
815         if (!strOptions.empty()) {
816                 strOptions = rtrim(strOptions, ",");
817                 // FIXME UNICODE
818                 os << '[' << from_utf8(strOptions) << ']';
819         }
820
821         os << '{' << from_ascii(tclass.latexname()) << "}\n";
822         texrow.newline();
823         // end of \documentclass defs
824
825         // font selection must be done before loading fontenc.sty
826         string const fonts =
827                 loadFonts(features, fontsRoman, fontsSans,
828                           fontsTypewriter, fontsSC, fontsOSF,
829                           fontsSansScale, fontsTypewriterScale);
830         if (!fonts.empty()) {
831                 os << from_ascii(fonts);
832                 texrow.newline();
833         }
834         if (fontsDefaultFamily != "default")
835                 os << "\\renewcommand{\\familydefault}{\\"
836                    << from_ascii(fontsDefaultFamily) << "}\n";
837         // this one is not per buffer
838         if (lyxrc.fontenc != "default") {
839                 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
840                    << "]{fontenc}\n";
841                 texrow.newline();
842         }
843
844         if (inputenc == "auto") {
845                 string const doc_encoding =
846                         language->encoding()->latexName();
847
848                 // Create a list with all the input encodings used
849                 // in the document
850                 std::set<string> encodings =
851                         features.getEncodingSet(doc_encoding);
852
853                 os << "\\usepackage[";
854                 std::set<string>::const_iterator it = encodings.begin();
855                 std::set<string>::const_iterator const end = encodings.end();
856                 for (; it != end; ++it)
857                         os << from_ascii(*it) << ',';
858                 os << from_ascii(doc_encoding) << "]{inputenc}\n";
859                 texrow.newline();
860         } else if (inputenc != "default") {
861                 os << "\\usepackage[" << from_ascii(inputenc)
862                    << "]{inputenc}\n";
863                 texrow.newline();
864         }
865
866         if (use_geometry || nonstandard_papersize) {
867                 os << "\\usepackage{geometry}\n";
868                 texrow.newline();
869                 os << "\\geometry{verbose";
870                 if (orientation == ORIENTATION_LANDSCAPE)
871                         os << ",landscape";
872                 switch (papersize) {
873                 case PAPER_CUSTOM:
874                         if (!paperwidth.empty())
875                                 os << ",paperwidth="
876                                    << from_ascii(paperwidth);
877                         if (!paperheight.empty())
878                                 os << ",paperheight="
879                                    << from_ascii(paperheight);
880                         break;
881                 case PAPER_USLETTER:
882                         os << ",letterpaper";
883                         break;
884                 case PAPER_USLEGAL:
885                         os << ",legalpaper";
886                         break;
887                 case PAPER_USEXECUTIVE:
888                         os << ",executivepaper";
889                         break;
890                 case PAPER_A3:
891                         os << ",a3paper";
892                         break;
893                 case PAPER_A4:
894                         os << ",a4paper";
895                         break;
896                 case PAPER_A5:
897                         os << ",a5paper";
898                         break;
899                 case PAPER_B3:
900                         os << ",b3paper";
901                         break;
902                 case PAPER_B4:
903                         os << ",b4paper";
904                         break;
905                 case PAPER_B5:
906                         os << ",b5paper";
907                         break;
908                 default:
909                         // default papersize ie PAPER_DEFAULT
910                         switch (lyxrc.default_papersize) {
911                         case PAPER_DEFAULT: // keep compiler happy
912                         case PAPER_USLETTER:
913                                 os << ",letterpaper";
914                                 break;
915                         case PAPER_USLEGAL:
916                                 os << ",legalpaper";
917                                 break;
918                         case PAPER_USEXECUTIVE:
919                                 os << ",executivepaper";
920                                 break;
921                         case PAPER_A3:
922                                 os << ",a3paper";
923                                 break;
924                         case PAPER_A4:
925                                 os << ",a4paper";
926                                 break;
927                         case PAPER_A5:
928                                 os << ",a5paper";
929                                 break;
930                         case PAPER_B5:
931                                 os << ",b5paper";
932                                 break;
933                         case PAPER_B3:
934                         case PAPER_B4:
935                         case PAPER_CUSTOM:
936                                 break;
937                         }
938                 }
939                 if (!topmargin.empty())
940                         os << ",tmargin=" << from_ascii(topmargin);
941                 if (!bottommargin.empty())
942                         os << ",bmargin=" << from_ascii(bottommargin);
943                 if (!leftmargin.empty())
944                         os << ",lmargin=" << from_ascii(leftmargin);
945                 if (!rightmargin.empty())
946                         os << ",rmargin=" << from_ascii(rightmargin);
947                 if (!headheight.empty())
948                         os << ",headheight=" << from_ascii(headheight);
949                 if (!headsep.empty())
950                         os << ",headsep=" << from_ascii(headsep);
951                 if (!footskip.empty())
952                         os << ",footskip=" << from_ascii(footskip);
953                 os << "}\n";
954                 texrow.newline();
955         }
956
957         if (tokenPos(tclass.opt_pagestyle(),
958                      '|', pagestyle) >= 0) {
959                 if (pagestyle == "fancy") {
960                         os << "\\usepackage{fancyhdr}\n";
961                         texrow.newline();
962                 }
963                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
964                 texrow.newline();
965         }
966
967         // Only if class has a ToC hierarchy
968         if (tclass.hasTocLevels()) {
969                 if (secnumdepth != tclass.secnumdepth()) {
970                         os << "\\setcounter{secnumdepth}{"
971                            << secnumdepth
972                            << "}\n";
973                         texrow.newline();
974                 }
975                 if (tocdepth != tclass.tocdepth()) {
976                         os << "\\setcounter{tocdepth}{"
977                            << tocdepth
978                            << "}\n";
979                         texrow.newline();
980                 }
981         }
982
983         if (paragraph_separation) {
984                 switch (getDefSkip().kind()) {
985                 case VSpace::SMALLSKIP:
986                         os << "\\setlength\\parskip{\\smallskipamount}\n";
987                         break;
988                 case VSpace::MEDSKIP:
989                         os << "\\setlength\\parskip{\\medskipamount}\n";
990                         break;
991                 case VSpace::BIGSKIP:
992                         os << "\\setlength\\parskip{\\bigskipamount}\n";
993                         break;
994                 case VSpace::LENGTH:
995                         os << "\\setlength\\parskip{"
996                            << from_utf8(getDefSkip().length().asLatexString())
997                            << "}\n";
998                         break;
999                 default: // should never happen // Then delete it.
1000                         os << "\\setlength\\parskip{\\medskipamount}\n";
1001                         break;
1002                 }
1003                 texrow.newline();
1004
1005                 os << "\\setlength\\parindent{0pt}\n";
1006                 texrow.newline();
1007         }
1008
1009         // If we use jurabib, we have to call babel here.
1010         if (use_babel && features.isRequired("jurabib")) {
1011                 os << from_ascii(babelCall(language_options.str()))
1012                    << '\n'
1013                    << from_ascii(features.getBabelOptions());
1014                 texrow.newline();
1015         }
1016
1017         // Now insert the LyX specific LaTeX commands...
1018
1019         // The optional packages;
1020         docstring lyxpreamble(from_ascii(features.getPackages()));
1021
1022         // this might be useful...
1023         lyxpreamble += "\n\\makeatletter\n";
1024
1025         // Some macros LyX will need
1026         docstring tmppreamble(from_ascii(features.getMacros()));
1027
1028         if (!tmppreamble.empty()) {
1029                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1030                         "LyX specific LaTeX commands.\n"
1031                         + tmppreamble + '\n';
1032         }
1033
1034         // the text class specific preamble
1035         tmppreamble = features.getTClassPreamble();
1036         if (!tmppreamble.empty()) {
1037                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1038                         "Textclass specific LaTeX commands.\n"
1039                         + tmppreamble + '\n';
1040         }
1041
1042         /* the user-defined preamble */
1043         if (!preamble.empty()) {
1044                 // FIXME UNICODE
1045                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1046                         "User specified LaTeX commands.\n"
1047                         + from_utf8(preamble) + '\n';
1048         }
1049
1050         // Itemize bullet settings need to be last in case the user
1051         // defines their own bullets that use a package included
1052         // in the user-defined preamble -- ARRae
1053         // Actually it has to be done much later than that
1054         // since some packages like frenchb make modifications
1055         // at \begin{document} time -- JMarc
1056         docstring bullets_def;
1057         for (int i = 0; i < 4; ++i) {
1058                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1059                         if (bullets_def.empty())
1060                                 bullets_def += "\\AtBeginDocument{\n";
1061                         bullets_def += "  \\def\\labelitemi";
1062                         switch (i) {
1063                                 // `i' is one less than the item to modify
1064                         case 0:
1065                                 break;
1066                         case 1:
1067                                 bullets_def += 'i';
1068                                 break;
1069                         case 2:
1070                                 bullets_def += "ii";
1071                                 break;
1072                         case 3:
1073                                 bullets_def += 'v';
1074                                 break;
1075                         }
1076                         bullets_def += '{' +
1077                                 user_defined_bullet(i).getText()
1078                                 + "}\n";
1079                 }
1080         }
1081
1082         if (!bullets_def.empty())
1083                 lyxpreamble += bullets_def + "}\n\n";
1084
1085         // We try to load babel late, in case it interferes
1086         // with other packages.
1087         // Jurabib has to be called after babel, though.
1088         if (use_babel && !features.isRequired("jurabib")) {
1089                 // FIXME UNICODE
1090                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1091                 lyxpreamble += from_utf8(features.getBabelOptions());
1092         }
1093
1094         lyxpreamble += "\\makeatother\n";
1095
1096         // dvipost settings come after everything else
1097         if (features.isAvailable("dvipost") && outputChanges) {
1098                 lyxpreamble +=
1099                         "\\dvipostlayout\n"
1100                         "\\dvipost{osstart color push Red}\n"
1101                         "\\dvipost{osend color pop}\n"
1102                         "\\dvipost{cbstart color push Blue}\n"
1103                         "\\dvipost{cbend color pop}\n";
1104         }
1105
1106         int const nlines =
1107                 int(lyx::count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1108         for (int j = 0; j != nlines; ++j) {
1109                 texrow.newline();
1110         }
1111
1112         os << lyxpreamble;
1113         return use_babel;
1114 }
1115
1116
1117 void BufferParams::useClassDefaults()
1118 {
1119         LyXTextClass const & tclass = textclasslist[textclass];
1120
1121         sides = tclass.sides();
1122         columns = tclass.columns();
1123         pagestyle = tclass.pagestyle();
1124         options = tclass.options();
1125         // Only if class has a ToC hierarchy
1126         if (tclass.hasTocLevels()) {
1127                 secnumdepth = tclass.secnumdepth();
1128                 tocdepth = tclass.tocdepth();
1129         }
1130 }
1131
1132
1133 bool BufferParams::hasClassDefaults() const
1134 {
1135         LyXTextClass const & tclass = textclasslist[textclass];
1136
1137         return (sides == tclass.sides()
1138                 && columns == tclass.columns()
1139                 && pagestyle == tclass.pagestyle()
1140                 && options == tclass.options()
1141                 && secnumdepth == tclass.secnumdepth()
1142                 && tocdepth == tclass.tocdepth());
1143 }
1144
1145
1146 LyXTextClass const & BufferParams::getLyXTextClass() const
1147 {
1148         return textclasslist[textclass];
1149 }
1150
1151
1152 LyXFont const BufferParams::getFont() const
1153 {
1154         LyXFont f = getLyXTextClass().defaultfont();
1155         f.setLanguage(language);
1156         if (fontsDefaultFamily == "rmdefault")
1157                 f.setFamily(LyXFont::ROMAN_FAMILY);
1158         else if (fontsDefaultFamily == "sfdefault")
1159                 f.setFamily(LyXFont::SANS_FAMILY);
1160         else if (fontsDefaultFamily == "ttdefault")
1161                 f.setFamily(LyXFont::TYPEWRITER_FAMILY);
1162         return f;
1163 }
1164
1165
1166 void BufferParams::readPreamble(LyXLex & lex)
1167 {
1168         if (lex.getString() != "\\begin_preamble")
1169                 lyxerr << "Error (BufferParams::readPreamble):"
1170                         "consistency check failed." << endl;
1171
1172         preamble = lex.getLongString("\\end_preamble");
1173 }
1174
1175
1176 void BufferParams::readLanguage(LyXLex & lex)
1177 {
1178         if (!lex.next()) return;
1179
1180         string const tmptok = lex.getString();
1181
1182         // check if tmptok is part of tex_babel in tex-defs.h
1183         language = languages.getLanguage(tmptok);
1184         if (!language) {
1185                 // Language tmptok was not found
1186                 language = default_language;
1187                 lyxerr << "Warning: Setting language `"
1188                        << tmptok << "' to `" << language->lang()
1189                        << "'." << endl;
1190         }
1191 }
1192
1193
1194 void BufferParams::readGraphicsDriver(LyXLex & lex)
1195 {
1196         if (!lex.next()) return;
1197
1198         string const tmptok = lex.getString();
1199         // check if tmptok is part of tex_graphics in tex_defs.h
1200         int n = 0;
1201         while (true) {
1202                 string const test = tex_graphics[n++];
1203
1204                 if (test == tmptok) {
1205                         graphicsDriver = tmptok;
1206                         break;
1207                 } else if (test == "") {
1208                         lex.printError(
1209                                 "Warning: graphics driver `$$Token' not recognized!\n"
1210                                 "         Setting graphics driver to `default'.\n");
1211                         graphicsDriver = "default";
1212                         break;
1213                 }
1214         }
1215 }
1216
1217
1218 void BufferParams::readBullets(LyXLex & lex)
1219 {
1220         if (!lex.next()) return;
1221
1222         int const index = lex.getInteger();
1223         lex.next();
1224         int temp_int = lex.getInteger();
1225         user_defined_bullet(index).setFont(temp_int);
1226         temp_bullet(index).setFont(temp_int);
1227         lex >> temp_int;
1228         user_defined_bullet(index).setCharacter(temp_int);
1229         temp_bullet(index).setCharacter(temp_int);
1230         lex >> temp_int;
1231         user_defined_bullet(index).setSize(temp_int);
1232         temp_bullet(index).setSize(temp_int);
1233 }
1234
1235
1236 void BufferParams::readBulletsLaTeX(LyXLex & lex)
1237 {
1238         // The bullet class should be able to read this.
1239         if (!lex.next()) return;
1240         int const index = lex.getInteger();
1241         lex.next(true);
1242         docstring const temp_str = lex.getDocString();
1243
1244         user_defined_bullet(index).setText(temp_str);
1245         temp_bullet(index).setText(temp_str);
1246 }
1247
1248
1249 string const BufferParams::paperSizeName() const
1250 {
1251         char real_papersize = papersize;
1252         if (real_papersize == PAPER_DEFAULT)
1253                 real_papersize = lyxrc.default_papersize;
1254
1255         switch (real_papersize) {
1256         case PAPER_A3:
1257                 return "a3";
1258         case PAPER_A4:
1259                 return "a4";
1260         case PAPER_A5:
1261                 return "a5";
1262         case PAPER_B5:
1263                 return "b5";
1264         case PAPER_USEXECUTIVE:
1265                 return "foolscap";
1266         case PAPER_USLEGAL:
1267                 return "legal";
1268         case PAPER_USLETTER:
1269         default:
1270                 return "letter";
1271         }
1272 }
1273
1274
1275 string const BufferParams::dvips_options() const
1276 {
1277         string result;
1278
1279         if (use_geometry
1280             && papersize == PAPER_CUSTOM
1281             && !lyxrc.print_paper_dimension_flag.empty()
1282             && !paperwidth.empty()
1283             && !paperheight.empty()) {
1284                 // using a custom papersize
1285                 result = lyxrc.print_paper_dimension_flag;
1286                 result += ' ' + paperwidth;
1287                 result += ',' + paperheight;
1288         } else {
1289                 string const paper_option = paperSizeName();
1290                 if (paper_option != "letter" ||
1291                     orientation != ORIENTATION_LANDSCAPE) {
1292                         // dvips won't accept -t letter -t landscape.
1293                         // In all other cases, include the paper size
1294                         // explicitly.
1295                         result = lyxrc.print_paper_flag;
1296                         result += ' ' + paper_option;
1297                 }
1298         }
1299         if (orientation == ORIENTATION_LANDSCAPE &&
1300             papersize != PAPER_CUSTOM)
1301                 result += ' ' + lyxrc.print_landscape_flag;
1302         return result;
1303 }
1304
1305
1306 string const BufferParams::babelCall(string const & lang_opts) const
1307 {
1308         string tmp = lyxrc.language_package;
1309         if (!lyxrc.language_global_options && tmp == "\\usepackage{babel}")
1310                 tmp = string("\\usepackage[") + lang_opts + "]{babel}";
1311         return tmp;
1312 }
1313
1314
1315 string const BufferParams::loadFonts(LaTeXFeatures & features, string const & rm,
1316                                      string const & sf, string const & tt,
1317                                      bool const & sc, bool const & osf,
1318                                      int const & sfscale, int const & ttscale) const
1319 {
1320         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1321            several packages have been replaced by others, that might not
1322            be installed on every system. We have to take care for that
1323            (see psnfss.pdf). We try to support all psnfss fonts as well
1324            as the fonts that have become de facto standard in the LaTeX
1325            world (e.g. Latin Modern). We do not support obsolete fonts
1326            (like PSLatex). In general, it should be possible to mix any
1327            rm font with any sf or tt font, respectively. (JSpitzm)
1328            TODO:
1329                 -- separate math fonts.
1330         */
1331
1332         if (rm == "default" && sf == "default" && tt == "default")
1333                 //nothing to do
1334                 return string();
1335
1336         ostringstream os;
1337
1338         // ROMAN FONTS
1339         // Computer Modern (must be explicitely selectable -- there might be classes
1340         // that define a different default font!
1341         if (rm == "cmr") {
1342                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1343                 // osf for Computer Modern needs eco.sty
1344                 if (osf)
1345                         os << "\\usepackage{eco}\n";
1346         }
1347         // Latin Modern Roman
1348         else if (rm == "lmodern")
1349                 os << "\\usepackage{lmodern}\n";
1350         // AE
1351         else if (rm == "ae") {
1352                 // not needed when using OT1 font encoding.
1353                 if (lyxrc.fontenc != "default")
1354                         os << "\\usepackage{ae,aecompl}\n";
1355         }
1356         // Times
1357         else if (rm == "times") {
1358                 // try to load the best available package
1359                 if (features.isAvailable("mathptmx"))
1360                         os << "\\usepackage{mathptmx}\n";
1361                 else if (features.isAvailable("mathptm"))
1362                         os << "\\usepackage{mathptm}\n";
1363                 else
1364                         os << "\\usepackage{times}\n";
1365         }
1366         // Palatino
1367         else if (rm == "palatino") {
1368                 // try to load the best available package
1369                 if (features.isAvailable("mathpazo")) {
1370                         os << "\\usepackage";
1371                         if (osf || sc) {
1372                                 os << '[';
1373                                 if (!osf)
1374                                         os << "sc";
1375                                 else
1376                                         // "osf" includes "sc"!
1377                                         os << "osf";
1378                                 os << ']';
1379                         }
1380                         os << "{mathpazo}\n";
1381                 }
1382                 else if (features.isAvailable("mathpple"))
1383                         os << "\\usepackage{mathpple}\n";
1384                 else
1385                         os << "\\usepackage{palatino}\n";
1386         }
1387         // Utopia
1388         else if (rm == "utopia") {
1389                 // fourier supersedes utopia.sty, but does
1390                 // not work with OT1 encoding.
1391                 if (features.isAvailable("fourier")
1392                     && lyxrc.fontenc != "default") {
1393                         os << "\\usepackage";
1394                         if (osf || sc) {
1395                                 os << '[';
1396                                 if (sc)
1397                                         os << "expert";
1398                                 if (osf && sc)
1399                                         os << ',';
1400                                 if (osf)
1401                                         os << "oldstyle";
1402                                 os << ']';
1403                         }
1404                         os << "{fourier}\n";
1405                 }
1406                 else
1407                         os << "\\usepackage{utopia}\n";
1408         }
1409         // Bera (complete fontset)
1410         else if (rm == "bera" && sf == "default" && tt == "default")
1411                 os << "\\usepackage{bera}\n";
1412         // everything else
1413         else if (rm != "default")
1414                 os << "\\usepackage" << "{" << rm << "}\n";
1415
1416         // SANS SERIF
1417         // Helvetica, Bera Sans
1418         if (sf == "helvet" || sf == "berasans") {
1419                 if (sfscale != 100)
1420                         os << "\\usepackage[scaled=" << float(sfscale) / 100
1421                            << "]{" << sf << "}\n";
1422                 else
1423                         os << "\\usepackage{" << sf << "}\n";
1424         }
1425         // Avant Garde
1426         else if (sf == "avant")
1427                 os << "\\usepackage{" << sf << "}\n";
1428         // Computer Modern, Latin Modern, CM Bright
1429         else if (sf != "default")
1430                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1431
1432         // monospaced/typewriter
1433         // Courier, LuxiMono
1434         if (tt == "luximono" || tt == "beramono") {
1435                 if (ttscale != 100)
1436                         os << "\\usepackage[scaled=" << float(ttscale) / 100
1437                            << "]{" << tt << "}\n";
1438                 else
1439                         os << "\\usepackage{" << tt << "}\n";
1440         }
1441         // Courier
1442         else if (tt == "courier" )
1443                 os << "\\usepackage{" << tt << "}\n";
1444         // Computer Modern, Latin Modern, CM Bright
1445         else if  (tt != "default")
1446                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1447
1448         return os.str();
1449 }
1450
1451
1452 } // namespace lyx