]> git.lyx.org Git - lyx.git/blob - src/bufferparams.C
Fix problem with non-ascii branch names by converting more stuff to
[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
178 // AMS
179 typedef Translator<int, BufferParams::AMS> AMSTranslator;
180
181
182 AMSTranslator const init_amstranslator()
183 {
184         AMSTranslator translator(0, BufferParams::AMS_OFF);
185         translator.addPair(1, BufferParams::AMS_AUTO);
186         translator.addPair(2, BufferParams::AMS_ON);
187         return translator;
188 }
189
190
191 AMSTranslator const & amstranslator()
192 {
193         static AMSTranslator translator = init_amstranslator();
194         return translator;
195 }
196
197
198 // Cite engine
199 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
200
201
202 CiteEngineTranslator const init_citeenginetranslator()
203 {
204         CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
205         translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
206         translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
207         translator.addPair("jurabib", biblio::ENGINE_JURABIB);
208         return translator;
209 }
210
211
212 CiteEngineTranslator const & citeenginetranslator()
213 {
214         static CiteEngineTranslator translator = init_citeenginetranslator();
215         return translator;
216 }
217
218
219 // Spacing
220 typedef Translator<string, Spacing::Space> SpaceTranslator;
221
222
223 SpaceTranslator const init_spacetranslator()
224 {
225         SpaceTranslator translator("default", Spacing::Default);
226         translator.addPair("single", Spacing::Single);
227         translator.addPair("onehalf", Spacing::Onehalf);
228         translator.addPair("double", Spacing::Double);
229         translator.addPair("other", Spacing::Other);
230         return translator;
231 }
232
233
234 SpaceTranslator const & spacetranslator()
235 {
236         static SpaceTranslator translator = init_spacetranslator();
237         return translator;
238 }
239
240 // ends annonym namespace
241 }
242
243
244 class BufferParams::Impl
245 {
246 public:
247         Impl();
248
249         AuthorList authorlist;
250         BranchList branchlist;
251         boost::array<Bullet, 4> temp_bullets;
252         boost::array<Bullet, 4> user_defined_bullets;
253         Spacing spacing;
254         /** This is the amount of space used for paragraph_separation "skip",
255          * and for detached paragraphs in "indented" documents.
256          */
257         VSpace defskip;
258 };
259
260
261 BufferParams::Impl::Impl()
262         : defskip(VSpace::MEDSKIP)
263 {
264         // set initial author
265         authorlist.record(Author(lyxrc.user_name, lyxrc.user_email));
266 }
267
268
269 BufferParams::Impl *
270 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
271 {
272         BOOST_ASSERT(ptr);
273
274         return new BufferParams::Impl(*ptr);
275 }
276
277
278 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
279 {
280         delete ptr;
281 }
282
283
284 BufferParams::BufferParams()
285         : // Initialize textclass to point to article. if `first' is
286           // true in the returned pair, then `second' is the textclass
287           // number; if it is false, second is 0. In both cases, second
288           // is what we want.
289         textclass(textclasslist.numberOfClass("article").second),
290         pimpl_(new Impl)
291 {
292         paragraph_separation = PARSEP_INDENT;
293         quotes_language = InsetQuotes::EnglishQ;
294         fontsize = "default";
295
296         /*  PaperLayout */
297         papersize = PAPER_DEFAULT;
298         orientation = ORIENTATION_PORTRAIT;
299         use_geometry = false;
300         use_amsmath = AMS_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 = amstranslator().find(use_ams);
486         } else if (token == "\\cite_engine") {
487                 string engine;
488                 lex >> engine;
489                 cite_engine = citeenginetranslator().find(engine);
490         } else if (token == "\\use_bibtopic") {
491                 lex >> use_bibtopic;
492         } else if (token == "\\tracking_changes") {
493                 lex >> trackChanges;
494         } else if (token == "\\output_changes") {
495                 lex >> outputChanges;
496         } else if (token == "\\branch") {
497                 lex.next();
498                 docstring branch = lex.getDocString();
499                 branchlist().add(branch);
500                 while (true) {
501                         lex.next();
502                         string const tok = lex.getString();
503                         if (tok == "\\end_branch")
504                                 break;
505                         Branch * branch_ptr = branchlist().find(branch);
506                         if (tok == "\\selected") {
507                                 lex.next();
508                                 if (branch_ptr)
509                                         branch_ptr->setSelected(lex.getInteger());
510                         }
511                         // not yet operational
512                         if (tok == "\\color") {
513                                 lex.eatLine();
514                                 string color = lex.getString();
515                                 if (branch_ptr)
516                                         branch_ptr->setColor(color);
517                                 // Update also the LColor table:
518                                 if (color == "none")
519                                         color = lcolor.getX11Name(LColor::background);
520                                 // FIXME UNICODE
521                                 lcolor.setColor(to_utf8(branch), color);
522
523                         }
524                 }
525         } else if (token == "\\author") {
526                 lex.eatLine();
527                 istringstream ss(lex.getString());
528                 Author a;
529                 ss >> a;
530                 author_map.push_back(pimpl_->authorlist.record(a));
531         } else if (token == "\\paperorientation") {
532                 string orient;
533                 lex >> orient;
534                 orientation = paperorientationtranslator().find(orient);
535         } else if (token == "\\paperwidth") {
536                 lex >> paperwidth;
537         } else if (token == "\\paperheight") {
538                 lex >> paperheight;
539         } else if (token == "\\leftmargin") {
540                 lex >> leftmargin;
541         } else if (token == "\\topmargin") {
542                 lex >> topmargin;
543         } else if (token == "\\rightmargin") {
544                 lex >> rightmargin;
545         } else if (token == "\\bottommargin") {
546                 lex >> bottommargin;
547         } else if (token == "\\headheight") {
548                 lex >> headheight;
549         } else if (token == "\\headsep") {
550                 lex >> headsep;
551         } else if (token == "\\footskip") {
552                 lex >> footskip;
553         } else if (token == "\\paperfontsize") {
554                 lex >> fontsize;
555         } else if (token == "\\papercolumns") {
556                 lex >> columns;
557         } else if (token == "\\papersides") {
558                 int psides;
559                 lex >> psides;
560                 sides = sidestranslator().find(psides);
561         } else if (token == "\\paperpagestyle") {
562                 lex >> pagestyle;
563         } else if (token == "\\bullet") {
564                 readBullets(lex);
565         } else if (token == "\\bulletLaTeX") {
566                 readBulletsLaTeX(lex);
567         } else if (token == "\\secnumdepth") {
568                 lex >> secnumdepth;
569         } else if (token == "\\tocdepth") {
570                 lex >> tocdepth;
571         } else if (token == "\\spacing") {
572                 string nspacing;
573                 lex >> nspacing;
574                 string tmp_val;
575                 if (nspacing == "other") {
576                         lex >> tmp_val;
577                 }
578                 spacing().set(spacetranslator().find(nspacing), tmp_val);
579         } else if (token == "\\float_placement") {
580                 lex >> float_placement;
581         } else {
582                 return token;
583         }
584
585         return string();
586 }
587
588
589 void BufferParams::writeFile(ostream & os) const
590 {
591         // The top of the file is written by the buffer.
592         // Prints out the buffer info into the .lyx file given by file
593
594         // the textclass
595         os << "\\textclass " << textclasslist[textclass].name() << '\n';
596
597         // then the the preamble
598         if (!preamble.empty()) {
599                 // remove '\n' from the end of preamble
600                 string const tmppreamble = rtrim(preamble, "\n");
601                 os << "\\begin_preamble\n"
602                    << tmppreamble
603                    << "\n\\end_preamble\n";
604         }
605
606         // the options
607         if (!options.empty()) {
608                 os << "\\options " << options << '\n';
609         }
610
611         // then the text parameters
612         if (language != ignore_language)
613                 os << "\\language " << language->lang() << '\n';
614         os << "\\inputencoding " << inputenc
615            << "\n\\font_roman " << fontsRoman
616            << "\n\\font_sans " << fontsSans
617            << "\n\\font_typewriter " << fontsTypewriter
618            << "\n\\font_default_family " << fontsDefaultFamily
619            << "\n\\font_sc " << convert<string>(fontsSC)
620            << "\n\\font_osf " << convert<string>(fontsOSF)
621            << "\n\\font_sf_scale " << fontsSansScale
622            << "\n\\font_tt_scale " << fontsTypewriterScale
623            << "\n\\graphics " << graphicsDriver << '\n';
624
625         if (!float_placement.empty()) {
626                 os << "\\float_placement " << float_placement << '\n';
627         }
628         os << "\\paperfontsize " << fontsize << '\n';
629
630         spacing().writeFile(os);
631
632         os << "\\papersize " << string_papersize[papersize]
633            << "\n\\use_geometry " << convert<string>(use_geometry)
634            << "\n\\use_amsmath " << use_amsmath
635            << "\n\\cite_engine " << citeenginetranslator().find(cite_engine)
636            << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
637            << "\n\\paperorientation " << string_orientation[orientation]
638            << '\n';
639
640         BranchList::const_iterator it = branchlist().begin();
641         BranchList::const_iterator end = branchlist().end();
642         for (; it != end; ++it) {
643                 os << "\\branch " << to_utf8(it->getBranch())
644                    << "\n\\selected " << it->getSelected()
645                    << "\n\\color " << lyx::X11hexname(it->getColor())
646                    << "\n\\end_branch"
647                    << "\n";
648         }
649
650         if (!paperwidth.empty())
651                 os << "\\paperwidth "
652                    << VSpace(paperwidth).asLyXCommand() << '\n';
653         if (!paperheight.empty())
654                 os << "\\paperheight "
655                    << VSpace(paperheight).asLyXCommand() << '\n';
656         if (!leftmargin.empty())
657                 os << "\\leftmargin "
658                    << VSpace(leftmargin).asLyXCommand() << '\n';
659         if (!topmargin.empty())
660                 os << "\\topmargin "
661                    << VSpace(topmargin).asLyXCommand() << '\n';
662         if (!rightmargin.empty())
663                 os << "\\rightmargin "
664                    << VSpace(rightmargin).asLyXCommand() << '\n';
665         if (!bottommargin.empty())
666                 os << "\\bottommargin "
667                    << VSpace(bottommargin).asLyXCommand() << '\n';
668         if (!headheight.empty())
669                 os << "\\headheight "
670                    << VSpace(headheight).asLyXCommand() << '\n';
671         if (!headsep.empty())
672                 os << "\\headsep "
673                    << VSpace(headsep).asLyXCommand() << '\n';
674         if (!footskip.empty())
675                 os << "\\footskip "
676                    << VSpace(footskip).asLyXCommand() << '\n';
677         os << "\\secnumdepth " << secnumdepth
678            << "\n\\tocdepth " << tocdepth
679            << "\n\\paragraph_separation "
680            << string_paragraph_separation[paragraph_separation]
681            << "\n\\defskip " << getDefSkip().asLyXCommand()
682            << "\n\\quotes_language "
683            << string_quotes_language[quotes_language]
684            << "\n\\papercolumns " << columns
685            << "\n\\papersides " << sides
686            << "\n\\paperpagestyle " << pagestyle << '\n';
687         for (int i = 0; i < 4; ++i) {
688                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
689                         if (user_defined_bullet(i).getFont() != -1) {
690                                 os << "\\bullet " << i << " "
691                                    << user_defined_bullet(i).getFont() << " "
692                                    << user_defined_bullet(i).getCharacter() << " "
693                                    << user_defined_bullet(i).getSize() << "\n";
694                         }
695                         else {
696                                 // FIXME UNICODE
697                                 os << "\\bulletLaTeX " << i << " \""
698                                    << lyx::to_ascii(user_defined_bullet(i).getText())
699                                    << "\"\n";
700                         }
701                 }
702         }
703
704         os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
705         os << "\\output_changes " << convert<string>(outputChanges) << "\n";
706
707         AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
708         AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
709         for (; a_it != a_end; ++a_it) {
710                 os << "\\author " << a_it->second << "\n";
711         }
712 }
713
714
715 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
716                               TexRow & texrow) const
717 {
718         os << "\\documentclass";
719
720         LyXTextClass const & tclass = getLyXTextClass();
721
722         ostringstream clsoptions; // the document class options.
723
724         if (tokenPos(tclass.opt_fontsize(),
725                      '|', fontsize) >= 0) {
726                 // only write if existing in list (and not default)
727                 clsoptions << fontsize << "pt,";
728         }
729
730         // custom, A3, B3 and B4 paper sizes need geometry
731         bool nonstandard_papersize = papersize == PAPER_B3 
732                 || papersize == PAPER_B4
733                 || papersize == PAPER_A3
734                 || papersize == PAPER_CUSTOM;
735
736         if (!use_geometry) {
737                 switch (papersize) {
738                 case PAPER_A4:
739                         clsoptions << "a4paper,";
740                         break;
741                 case PAPER_USLETTER:
742                         clsoptions << "letterpaper,";
743                         break;
744                 case PAPER_A5:
745                         clsoptions << "a5paper,";
746                         break;
747                 case PAPER_B5:
748                         clsoptions << "b5paper,";
749                         break;
750                 case PAPER_USEXECUTIVE:
751                         clsoptions << "executivepaper,";
752                         break;
753                 case PAPER_USLEGAL:
754                         clsoptions << "legalpaper,";
755                         break;
756                 case PAPER_DEFAULT:
757                 case PAPER_A3:
758                 case PAPER_B3:
759                 case PAPER_B4:
760                 case PAPER_CUSTOM:
761                         break;
762                 }
763         }
764
765         // if needed
766         if (sides != tclass.sides()) {
767                 switch (sides) {
768                 case LyXTextClass::OneSide:
769                         clsoptions << "oneside,";
770                         break;
771                 case LyXTextClass::TwoSides:
772                         clsoptions << "twoside,";
773                         break;
774                 }
775         }
776
777         // if needed
778         if (columns != tclass.columns()) {
779                 if (columns == 2)
780                         clsoptions << "twocolumn,";
781                 else
782                         clsoptions << "onecolumn,";
783         }
784
785         if (!use_geometry
786             && orientation == ORIENTATION_LANDSCAPE)
787                 clsoptions << "landscape,";
788
789         // language should be a parameter to \documentclass
790         if (language->babel() == "hebrew"
791             && default_language->babel() != "hebrew")
792                 // This seems necessary
793                 features.useLanguage(default_language);
794
795         ostringstream language_options;
796         bool const use_babel = features.useBabel();
797         if (use_babel) {
798                 language_options << features.getLanguages();
799                 language_options << language->babel();
800                 if (lyxrc.language_global_options)
801                         clsoptions << language_options.str() << ',';
802         }
803
804         // the user-defined options
805         if (!options.empty()) {
806                 clsoptions << options << ',';
807         }
808
809         string strOptions(clsoptions.str());
810         if (!strOptions.empty()) {
811                 strOptions = rtrim(strOptions, ",");
812                 // FIXME UNICODE
813                 os << '[' << from_utf8(strOptions) << ']';
814         }
815
816         os << '{' << from_ascii(tclass.latexname()) << "}\n";
817         texrow.newline();
818         // end of \documentclass defs
819
820         // font selection must be done before loading fontenc.sty
821         string const fonts =
822                 loadFonts(features, fontsRoman, fontsSans,
823                           fontsTypewriter, fontsSC, fontsOSF,
824                           fontsSansScale, fontsTypewriterScale);
825         if (!fonts.empty()) {
826                 os << from_ascii(fonts);
827                 texrow.newline();
828         }
829         if (fontsDefaultFamily != "default")
830                 os << "\\renewcommand{\\familydefault}{\\"
831                    << from_ascii(fontsDefaultFamily) << "}\n";
832         // this one is not per buffer
833         if (lyxrc.fontenc != "default") {
834                 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
835                    << "]{fontenc}\n";
836                 texrow.newline();
837         }
838
839         if (inputenc == "auto") {
840                 string const doc_encoding =
841                         language->encoding()->latexName();
842
843                 // Create a list with all the input encodings used
844                 // in the document
845                 std::set<string> encodings =
846                         features.getEncodingSet(doc_encoding);
847
848                 os << "\\usepackage[";
849                 std::set<string>::const_iterator it = encodings.begin();
850                 std::set<string>::const_iterator const end = encodings.end();
851                 for (; it != end; ++it)
852                         os << from_ascii(*it) << ',';
853                 os << from_ascii(doc_encoding) << "]{inputenc}\n";
854                 texrow.newline();
855         } else if (inputenc != "default") {
856                 os << "\\usepackage[" << from_ascii(inputenc)
857                    << "]{inputenc}\n";
858                 texrow.newline();
859         }
860
861         if (use_geometry || nonstandard_papersize) {
862                 os << "\\usepackage{geometry}\n";
863                 texrow.newline();
864                 os << "\\geometry{verbose";
865                 if (orientation == ORIENTATION_LANDSCAPE)
866                         os << ",landscape";
867                 switch (papersize) {
868                 case PAPER_CUSTOM:
869                         if (!paperwidth.empty())
870                                 os << ",paperwidth="
871                                    << from_ascii(paperwidth);
872                         if (!paperheight.empty())
873                                 os << ",paperheight="
874                                    << from_ascii(paperheight);
875                         break;
876                 case PAPER_USLETTER:
877                         os << ",letterpaper";
878                         break;
879                 case PAPER_USLEGAL:
880                         os << ",legalpaper";
881                         break;
882                 case PAPER_USEXECUTIVE:
883                         os << ",executivepaper";
884                         break;
885                 case PAPER_A3:
886                         os << ",a3paper";
887                         break;
888                 case PAPER_A4:
889                         os << ",a4paper";
890                         break;
891                 case PAPER_A5:
892                         os << ",a5paper";
893                         break;
894                 case PAPER_B3:
895                         os << ",b3paper";
896                         break;
897                 case PAPER_B4:
898                         os << ",b4paper";
899                         break;
900                 case PAPER_B5:
901                         os << ",b5paper";
902                         break;
903                 default:
904                         // default papersize ie PAPER_DEFAULT
905                         switch (lyxrc.default_papersize) {
906                         case PAPER_DEFAULT: // keep compiler happy
907                         case PAPER_USLETTER:
908                                 os << ",letterpaper";
909                                 break;
910                         case PAPER_USLEGAL:
911                                 os << ",legalpaper";
912                                 break;
913                         case PAPER_USEXECUTIVE:
914                                 os << ",executivepaper";
915                                 break;
916                         case PAPER_A3:
917                                 os << ",a3paper";
918                                 break;
919                         case PAPER_A4:
920                                 os << ",a4paper";
921                                 break;
922                         case PAPER_A5:
923                                 os << ",a5paper";
924                                 break;
925                         case PAPER_B5:
926                                 os << ",b5paper";
927                                 break;
928                         case PAPER_B3:
929                         case PAPER_B4:
930                         case PAPER_CUSTOM:
931                                 break;
932                         }
933                 }
934                 if (!topmargin.empty())
935                         os << ",tmargin=" << from_ascii(topmargin);
936                 if (!bottommargin.empty())
937                         os << ",bmargin=" << from_ascii(bottommargin);
938                 if (!leftmargin.empty())
939                         os << ",lmargin=" << from_ascii(leftmargin);
940                 if (!rightmargin.empty())
941                         os << ",rmargin=" << from_ascii(rightmargin);
942                 if (!headheight.empty())
943                         os << ",headheight=" << from_ascii(headheight);
944                 if (!headsep.empty())
945                         os << ",headsep=" << from_ascii(headsep);
946                 if (!footskip.empty())
947                         os << ",footskip=" << from_ascii(footskip);
948                 os << "}\n";
949                 texrow.newline();
950         }
951
952         if (tokenPos(tclass.opt_pagestyle(),
953                      '|', pagestyle) >= 0) {
954                 if (pagestyle == "fancy") {
955                         os << "\\usepackage{fancyhdr}\n";
956                         texrow.newline();
957                 }
958                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
959                 texrow.newline();
960         }
961
962         // Only if class has a ToC hierarchy
963         if (tclass.hasTocLevels()) {
964                 if (secnumdepth != tclass.secnumdepth()) {
965                         os << "\\setcounter{secnumdepth}{"
966                            << secnumdepth
967                            << "}\n";
968                         texrow.newline();
969                 }
970                 if (tocdepth != tclass.tocdepth()) {
971                         os << "\\setcounter{tocdepth}{"
972                            << tocdepth
973                            << "}\n";
974                         texrow.newline();
975                 }
976         }
977
978         if (paragraph_separation) {
979                 switch (getDefSkip().kind()) {
980                 case VSpace::SMALLSKIP:
981                         os << "\\setlength\\parskip{\\smallskipamount}\n";
982                         break;
983                 case VSpace::MEDSKIP:
984                         os << "\\setlength\\parskip{\\medskipamount}\n";
985                         break;
986                 case VSpace::BIGSKIP:
987                         os << "\\setlength\\parskip{\\bigskipamount}\n";
988                         break;
989                 case VSpace::LENGTH:
990                         os << "\\setlength\\parskip{"
991                            << from_utf8(getDefSkip().length().asLatexString())
992                            << "}\n";
993                         break;
994                 default: // should never happen // Then delete it.
995                         os << "\\setlength\\parskip{\\medskipamount}\n";
996                         break;
997                 }
998                 texrow.newline();
999
1000                 os << "\\setlength\\parindent{0pt}\n";
1001                 texrow.newline();
1002         }
1003
1004         // If we use jurabib, we have to call babel here.
1005         if (use_babel && features.isRequired("jurabib")) {
1006                 os << from_ascii(babelCall(language_options.str()))
1007                    << '\n'
1008                    << from_ascii(features.getBabelOptions());
1009                 texrow.newline();
1010         }
1011
1012         // Now insert the LyX specific LaTeX commands...
1013
1014         // The optional packages;
1015         string lyxpreamble(features.getPackages());
1016
1017         // this might be useful...
1018         lyxpreamble += "\n\\makeatletter\n";
1019
1020         // Some macros LyX will need
1021         string tmppreamble(features.getMacros());
1022
1023         if (!tmppreamble.empty()) {
1024                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1025                         "LyX specific LaTeX commands.\n"
1026                         + tmppreamble + '\n';
1027         }
1028
1029         // the text class specific preamble
1030         tmppreamble = features.getTClassPreamble();
1031         if (!tmppreamble.empty()) {
1032                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1033                         "Textclass specific LaTeX commands.\n"
1034                         + tmppreamble + '\n';
1035         }
1036
1037         /* the user-defined preamble */
1038         if (!preamble.empty()) {
1039                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1040                         "User specified LaTeX commands.\n"
1041                         + preamble + '\n';
1042         }
1043
1044         // Itemize bullet settings need to be last in case the user
1045         // defines their own bullets that use a package included
1046         // in the user-defined preamble -- ARRae
1047         // Actually it has to be done much later than that
1048         // since some packages like frenchb make modifications
1049         // at \begin{document} time -- JMarc
1050         string bullets_def;
1051         for (int i = 0; i < 4; ++i) {
1052                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1053                         if (bullets_def.empty())
1054                                 bullets_def="\\AtBeginDocument{\n";
1055                         bullets_def += "  \\def\\labelitemi";
1056                         switch (i) {
1057                                 // `i' is one less than the item to modify
1058                         case 0:
1059                                 break;
1060                         case 1:
1061                                 bullets_def += 'i';
1062                                 break;
1063                         case 2:
1064                                 bullets_def += "ii";
1065                                 break;
1066                         case 3:
1067                                 bullets_def += 'v';
1068                                 break;
1069                         }
1070                         // FIXME UNICODE
1071                         bullets_def += '{' +
1072                                 lyx::to_ascii(user_defined_bullet(i).getText())
1073                                 + "}\n";
1074                 }
1075         }
1076
1077         if (!bullets_def.empty())
1078                 lyxpreamble += bullets_def + "}\n\n";
1079
1080         // We try to load babel late, in case it interferes
1081         // with other packages.
1082         // Jurabib has to be called after babel, though.
1083         if (use_babel && !features.isRequired("jurabib")) {
1084                 lyxpreamble += babelCall(language_options.str()) + '\n';
1085                 lyxpreamble += features.getBabelOptions();
1086         }
1087
1088         lyxpreamble += "\\makeatother\n";
1089
1090         // dvipost settings come after everything else
1091         if (features.isAvailable("dvipost") && outputChanges) {
1092                 lyxpreamble +=
1093                         "\\dvipostlayout\n"
1094                         "\\dvipost{osstart color push Red}\n"
1095                         "\\dvipost{osend color pop}\n"
1096                         "\\dvipost{cbstart color push Blue}\n"
1097                         "\\dvipost{cbend color pop}\n";
1098         }
1099
1100         int const nlines =
1101                 int(lyx::count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1102         for (int j = 0; j != nlines; ++j) {
1103                 texrow.newline();
1104         }
1105
1106         // FIXME UNICODE
1107         os << from_utf8(lyxpreamble);
1108         return use_babel;
1109 }
1110
1111
1112 void BufferParams::useClassDefaults()
1113 {
1114         LyXTextClass const & tclass = textclasslist[textclass];
1115
1116         sides = tclass.sides();
1117         columns = tclass.columns();
1118         pagestyle = tclass.pagestyle();
1119         options = tclass.options();
1120         // Only if class has a ToC hierarchy
1121         if (tclass.hasTocLevels()) {
1122                 secnumdepth = tclass.secnumdepth();
1123                 tocdepth = tclass.tocdepth();
1124         }
1125 }
1126
1127
1128 bool BufferParams::hasClassDefaults() const
1129 {
1130         LyXTextClass const & tclass = textclasslist[textclass];
1131
1132         return (sides == tclass.sides()
1133                 && columns == tclass.columns()
1134                 && pagestyle == tclass.pagestyle()
1135                 && options == tclass.options()
1136                 && secnumdepth == tclass.secnumdepth()
1137                 && tocdepth == tclass.tocdepth());
1138 }
1139
1140
1141 LyXTextClass const & BufferParams::getLyXTextClass() const
1142 {
1143         return textclasslist[textclass];
1144 }
1145
1146
1147 LyXFont const BufferParams::getFont() const
1148 {
1149         LyXFont f = getLyXTextClass().defaultfont();
1150         f.setLanguage(language);
1151         if (fontsDefaultFamily == "rmdefault")
1152                 f.setFamily(LyXFont::ROMAN_FAMILY);
1153         else if (fontsDefaultFamily == "sfdefault")
1154                 f.setFamily(LyXFont::SANS_FAMILY);
1155         else if (fontsDefaultFamily == "ttdefault")
1156                 f.setFamily(LyXFont::TYPEWRITER_FAMILY);
1157         return f;
1158 }
1159
1160
1161 void BufferParams::readPreamble(LyXLex & lex)
1162 {
1163         if (lex.getString() != "\\begin_preamble")
1164                 lyxerr << "Error (BufferParams::readPreamble):"
1165                         "consistency check failed." << endl;
1166
1167         preamble = lex.getLongString("\\end_preamble");
1168 }
1169
1170
1171 void BufferParams::readLanguage(LyXLex & lex)
1172 {
1173         if (!lex.next()) return;
1174
1175         string const tmptok = lex.getString();
1176
1177         // check if tmptok is part of tex_babel in tex-defs.h
1178         language = languages.getLanguage(tmptok);
1179         if (!language) {
1180                 // Language tmptok was not found
1181                 language = default_language;
1182                 lyxerr << "Warning: Setting language `"
1183                        << tmptok << "' to `" << language->lang()
1184                        << "'." << endl;
1185         }
1186 }
1187
1188
1189 void BufferParams::readGraphicsDriver(LyXLex & lex)
1190 {
1191         if (!lex.next()) return;
1192
1193         string const tmptok = lex.getString();
1194         // check if tmptok is part of tex_graphics in tex_defs.h
1195         int n = 0;
1196         while (true) {
1197                 string const test = tex_graphics[n++];
1198
1199                 if (test == tmptok) {
1200                         graphicsDriver = tmptok;
1201                         break;
1202                 } else if (test == "") {
1203                         lex.printError(
1204                                 "Warning: graphics driver `$$Token' not recognized!\n"
1205                                 "         Setting graphics driver to `default'.\n");
1206                         graphicsDriver = "default";
1207                         break;
1208                 }
1209         }
1210 }
1211
1212
1213 void BufferParams::readBullets(LyXLex & lex)
1214 {
1215         if (!lex.next()) return;
1216
1217         int const index = lex.getInteger();
1218         lex.next();
1219         int temp_int = lex.getInteger();
1220         user_defined_bullet(index).setFont(temp_int);
1221         temp_bullet(index).setFont(temp_int);
1222         lex >> temp_int;
1223         user_defined_bullet(index).setCharacter(temp_int);
1224         temp_bullet(index).setCharacter(temp_int);
1225         lex >> temp_int;
1226         user_defined_bullet(index).setSize(temp_int);
1227         temp_bullet(index).setSize(temp_int);
1228 }
1229
1230
1231 void BufferParams::readBulletsLaTeX(LyXLex & lex)
1232 {
1233         // The bullet class should be able to read this.
1234         if (!lex.next()) return;
1235         int const index = lex.getInteger();
1236         lex.next(true);
1237         docstring const temp_str = lex.getDocString();
1238
1239         user_defined_bullet(index).setText(temp_str);
1240         temp_bullet(index).setText(temp_str);
1241 }
1242
1243
1244 string const BufferParams::paperSizeName() const
1245 {
1246         char real_papersize = papersize;
1247         if (real_papersize == PAPER_DEFAULT)
1248                 real_papersize = lyxrc.default_papersize;
1249
1250         switch (real_papersize) {
1251         case PAPER_A3:
1252                 return "a3";
1253         case PAPER_A4:
1254                 return "a4";
1255         case PAPER_A5:
1256                 return "a5";
1257         case PAPER_B5:
1258                 return "b5";
1259         case PAPER_USEXECUTIVE:
1260                 return "foolscap";
1261         case PAPER_USLEGAL:
1262                 return "legal";
1263         case PAPER_USLETTER:
1264         default:
1265                 return "letter";
1266         }
1267 }
1268
1269
1270 string const BufferParams::dvips_options() const
1271 {
1272         string result;
1273
1274         if (use_geometry
1275             && papersize == PAPER_CUSTOM
1276             && !lyxrc.print_paper_dimension_flag.empty()
1277             && !paperwidth.empty()
1278             && !paperheight.empty()) {
1279                 // using a custom papersize
1280                 result = lyxrc.print_paper_dimension_flag;
1281                 result += ' ' + paperwidth;
1282                 result += ',' + paperheight;
1283         } else {
1284                 string const paper_option = paperSizeName();
1285                 if (paper_option != "letter" ||
1286                     orientation != ORIENTATION_LANDSCAPE) {
1287                         // dvips won't accept -t letter -t landscape.
1288                         // In all other cases, include the paper size
1289                         // explicitly.
1290                         result = lyxrc.print_paper_flag;
1291                         result += ' ' + paper_option;
1292                 }
1293         }
1294         if (orientation == ORIENTATION_LANDSCAPE &&
1295             papersize != PAPER_CUSTOM)
1296                 result += ' ' + lyxrc.print_landscape_flag;
1297         return result;
1298 }
1299
1300
1301 string const BufferParams::babelCall(string const & lang_opts) const
1302 {
1303         string tmp = lyxrc.language_package;
1304         if (!lyxrc.language_global_options && tmp == "\\usepackage{babel}")
1305                 tmp = string("\\usepackage[") + lang_opts + "]{babel}";
1306         return tmp;
1307 }
1308
1309
1310 string const BufferParams::loadFonts(LaTeXFeatures & features, string const & rm,
1311                                      string const & sf, string const & tt,
1312                                      bool const & sc, bool const & osf,
1313                                      int const & sfscale, int const & ttscale) const
1314 {
1315         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1316            several packages have been replaced by others, that might not
1317            be installed on every system. We have to take care for that
1318            (see psnfss.pdf). We try to support all psnfss fonts as well
1319            as the fonts that have become de facto standard in the LaTeX
1320            world (e.g. Latin Modern). We do not support obsolete fonts
1321            (like PSLatex). In general, it should be possible to mix any
1322            rm font with any sf or tt font, respectively. (JSpitzm)
1323            TODO:
1324                 -- separate math fonts.
1325         */
1326
1327         if (rm == "default" && sf == "default" && tt == "default")
1328                 //nothing to do
1329                 return string();
1330
1331         ostringstream os;
1332
1333         // ROMAN FONTS
1334         // Computer Modern (must be explicitely selectable -- there might be classes
1335         // that define a different default font!
1336         if (rm == "cmr") {
1337                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1338                 // osf for Computer Modern needs eco.sty
1339                 if (osf)
1340                         os << "\\usepackage{eco}\n";
1341         }
1342         // Latin Modern Roman
1343         else if (rm == "lmodern")
1344                 os << "\\usepackage{lmodern}\n";
1345         // AE
1346         else if (rm == "ae") {
1347                 // not needed when using OT1 font encoding.
1348                 if (lyxrc.fontenc != "default")
1349                         os << "\\usepackage{ae,aecompl}\n";
1350         }
1351         // Times
1352         else if (rm == "times") {
1353                 // try to load the best available package
1354                 if (features.isAvailable("mathptmx"))
1355                         os << "\\usepackage{mathptmx}\n";
1356                 else if (features.isAvailable("mathptm"))
1357                         os << "\\usepackage{mathptm}\n";
1358                 else
1359                         os << "\\usepackage{times}\n";
1360         }
1361         // Palatino
1362         else if (rm == "palatino") {
1363                 // try to load the best available package
1364                 if (features.isAvailable("mathpazo")) {
1365                         os << "\\usepackage";
1366                         if (osf || sc) {
1367                                 os << '[';
1368                                 if (!osf)
1369                                         os << "sc";
1370                                 else
1371                                         // "osf" includes "sc"!
1372                                         os << "osf";
1373                                 os << ']';
1374                         }
1375                         os << "{mathpazo}\n";
1376                 }
1377                 else if (features.isAvailable("mathpple"))
1378                         os << "\\usepackage{mathpple}\n";
1379                 else
1380                         os << "\\usepackage{palatino}\n";
1381         }
1382         // Utopia
1383         else if (rm == "utopia") {
1384                 // fourier supersedes utopia.sty, but does
1385                 // not work with OT1 encoding.
1386                 if (features.isAvailable("fourier")
1387                     && lyxrc.fontenc != "default") {
1388                         os << "\\usepackage";
1389                         if (osf || sc) {
1390                                 os << '[';
1391                                 if (sc)
1392                                         os << "expert";
1393                                 if (osf && sc)
1394                                         os << ',';
1395                                 if (osf)
1396                                         os << "oldstyle";
1397                                 os << ']';
1398                         }
1399                         os << "{fourier}\n";
1400                 }
1401                 else
1402                         os << "\\usepackage{utopia}\n";
1403         }
1404         // Bera (complete fontset)
1405         else if (rm == "bera" && sf == "default" && tt == "default")
1406                 os << "\\usepackage{bera}\n";
1407         // everything else
1408         else if (rm != "default")
1409                 os << "\\usepackage" << "{" << rm << "}\n";
1410
1411         // SANS SERIF
1412         // Helvetica, Bera Sans
1413         if (sf == "helvet" || sf == "berasans") {
1414                 if (sfscale != 100)
1415                         os << "\\usepackage[scaled=" << float(sfscale) / 100
1416                            << "]{" << sf << "}\n";
1417                 else
1418                         os << "\\usepackage{" << sf << "}\n";
1419         }
1420         // Avant Garde
1421         else if (sf == "avant")
1422                 os << "\\usepackage{" << sf << "}\n";
1423         // Computer Modern, Latin Modern, CM Bright
1424         else if (sf != "default")
1425                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1426
1427         // monospaced/typewriter
1428         // Courier, LuxiMono
1429         if (tt == "luximono" || tt == "beramono") {
1430                 if (ttscale != 100)
1431                         os << "\\usepackage[scaled=" << float(ttscale) / 100
1432                            << "]{" << tt << "}\n";
1433                 else
1434                         os << "\\usepackage{" << tt << "}\n";
1435         }
1436         // Courier
1437         else if (tt == "courier" )
1438                 os << "\\usepackage{" << tt << "}\n";
1439         // Computer Modern, Latin Modern, CM Bright
1440         else if  (tt != "default")
1441                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1442
1443         return os.str();
1444 }
1445
1446
1447 } // namespace lyx