move LyXerr QString specialisation to support/qstring_helpers
[lyx.git] / src / BufferParams.cpp
blob9c6a0e2926450b60b35c1769799797fb37c45999
1 /**
2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
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
13 * Full author contact details are available in file CREDITS.
16 #include <config.h>
18 #include "BufferParams.h"
20 #include "Author.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
23 #include "buffer_funcs.h"
24 #include "Bullet.h"
25 #include "Color.h"
26 #include "Encoding.h"
27 #include "Language.h"
28 #include "LaTeXFeatures.h"
29 #include "ModuleList.h"
30 #include "Font.h"
31 #include "Lexer.h"
32 #include "LyXRC.h"
33 #include "OutputParams.h"
34 #include "Spacing.h"
35 #include "TexRow.h"
36 #include "VSpace.h"
37 #include "PDFOptions.h"
39 #include "frontends/alert.h"
41 #include "insets/InsetListingsParams.h"
43 #include "support/convert.h"
44 #include "support/debug.h"
45 #include "support/docstream.h"
46 #include "support/FileName.h"
47 #include "support/filetools.h"
48 #include "support/gettext.h"
49 #include "support/Messages.h"
50 #include "support/Translator.h"
51 #include "support/lstrings.h"
53 #include <algorithm>
54 #include <sstream>
56 using namespace std;
57 using namespace lyx::support;
60 static char const * const string_paragraph_separation[] = {
61 "indent", "skip", ""
65 static char const * const string_quotes_language[] = {
66 "english", "swedish", "german", "polish", "french", "danish", ""
70 static char const * const string_papersize[] = {
71 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
72 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
76 static char const * const string_orientation[] = {
77 "portrait", "landscape", ""
81 static char const * const string_footnotekinds[] = {
82 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
86 static char const * const tex_graphics[] = {
87 "default", "dvips", "dvitops", "emtex",
88 "ln", "oztex", "textures", "none", ""
92 namespace lyx {
94 // Local translators
95 namespace {
97 // Paragraph separation
98 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
101 ParSepTranslator const init_parseptranslator()
103 ParSepTranslator translator
104 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
105 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
106 return translator;
110 ParSepTranslator const & parseptranslator()
112 static ParSepTranslator translator = init_parseptranslator();
113 return translator;
117 // Quotes language
118 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
121 QuotesLangTranslator const init_quoteslangtranslator()
123 QuotesLangTranslator translator
124 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
125 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
126 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
127 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
128 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
129 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
130 return translator;
134 QuotesLangTranslator const & quoteslangtranslator()
136 static QuotesLangTranslator translator = init_quoteslangtranslator();
137 return translator;
141 // Paper size
142 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
145 static PaperSizeTranslator initPaperSizeTranslator()
147 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
148 translator.addPair(string_papersize[1], PAPER_CUSTOM);
149 translator.addPair(string_papersize[2], PAPER_USLETTER);
150 translator.addPair(string_papersize[3], PAPER_USLEGAL);
151 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
152 translator.addPair(string_papersize[5], PAPER_A3);
153 translator.addPair(string_papersize[6], PAPER_A4);
154 translator.addPair(string_papersize[7], PAPER_A5);
155 translator.addPair(string_papersize[8], PAPER_B3);
156 translator.addPair(string_papersize[9], PAPER_B4);
157 translator.addPair(string_papersize[10], PAPER_B5);
158 return translator;
162 PaperSizeTranslator const & papersizetranslator()
164 static PaperSizeTranslator translator = initPaperSizeTranslator();
165 return translator;
169 // Paper orientation
170 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
173 PaperOrientationTranslator const init_paperorientationtranslator()
175 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
176 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
177 return translator;
181 PaperOrientationTranslator const & paperorientationtranslator()
183 static PaperOrientationTranslator translator = init_paperorientationtranslator();
184 return translator;
188 // Page sides
189 typedef Translator<int, PageSides> SidesTranslator;
192 SidesTranslator const init_sidestranslator()
194 SidesTranslator translator(1, OneSide);
195 translator.addPair(2, TwoSides);
196 return translator;
200 SidesTranslator const & sidestranslator()
202 static SidesTranslator translator = init_sidestranslator();
203 return translator;
207 // LaTeX packages
208 typedef Translator<int, BufferParams::Package> PackageTranslator;
211 PackageTranslator const init_packagetranslator()
213 PackageTranslator translator(0, BufferParams::package_off);
214 translator.addPair(1, BufferParams::package_auto);
215 translator.addPair(2, BufferParams::package_on);
216 return translator;
220 PackageTranslator const & packagetranslator()
222 static PackageTranslator translator = init_packagetranslator();
223 return translator;
227 // Cite engine
228 typedef Translator<string, CiteEngine> CiteEngineTranslator;
231 CiteEngineTranslator const init_citeenginetranslator()
233 CiteEngineTranslator translator("basic", ENGINE_BASIC);
234 translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
235 translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
236 translator.addPair("jurabib", ENGINE_JURABIB);
237 return translator;
241 CiteEngineTranslator const & citeenginetranslator()
243 static CiteEngineTranslator translator = init_citeenginetranslator();
244 return translator;
248 // Spacing
249 typedef Translator<string, Spacing::Space> SpaceTranslator;
252 SpaceTranslator const init_spacetranslator()
254 SpaceTranslator translator("default", Spacing::Default);
255 translator.addPair("single", Spacing::Single);
256 translator.addPair("onehalf", Spacing::Onehalf);
257 translator.addPair("double", Spacing::Double);
258 translator.addPair("other", Spacing::Other);
259 return translator;
263 SpaceTranslator const & spacetranslator()
265 static SpaceTranslator translator = init_spacetranslator();
266 return translator;
270 } // anon namespace
273 class BufferParams::Impl
275 public:
276 Impl();
278 AuthorList authorlist;
279 BranchList branchlist;
280 Bullet temp_bullets[4];
281 Bullet user_defined_bullets[4];
282 Spacing spacing;
283 /** This is the amount of space used for paragraph_separation "skip",
284 * and for detached paragraphs in "indented" documents.
286 VSpace defskip;
287 PDFOptions pdfoptions;
288 LayoutFileIndex baseClass_;
292 BufferParams::Impl::Impl()
293 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
295 // set initial author
296 // FIXME UNICODE
297 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
301 BufferParams::Impl *
302 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
304 LASSERT(ptr, /**/);
306 return new BufferParams::Impl(*ptr);
310 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
312 delete ptr;
316 BufferParams::BufferParams()
317 : pimpl_(new Impl)
319 setBaseClass(defaultBaseclass());
320 makeDocumentClass();
321 paragraph_separation = ParagraphIndentSeparation;
322 quotes_language = InsetQuotes::EnglishQuotes;
323 fontsize = "default";
325 /* PaperLayout */
326 papersize = PAPER_DEFAULT;
327 orientation = ORIENTATION_PORTRAIT;
328 use_geometry = false;
329 use_amsmath = package_auto;
330 use_esint = package_auto;
331 cite_engine_ = ENGINE_BASIC;
332 use_bibtopic = false;
333 trackChanges = false;
334 outputChanges = false;
335 secnumdepth = 3;
336 tocdepth = 3;
337 language = default_language;
338 fontsRoman = "default";
339 fontsSans = "default";
340 fontsTypewriter = "default";
341 fontsDefaultFamily = "default";
342 fontsSC = false;
343 fontsOSF = false;
344 fontsSansScale = 100;
345 fontsTypewriterScale = 100;
346 inputenc = "auto";
347 graphicsDriver = "default";
348 sides = OneSide;
349 columns = 1;
350 listings_params = string();
351 pagestyle = "default";
352 compressed = false;
353 for (int iter = 0; iter < 4; ++iter) {
354 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
355 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
360 docstring BufferParams::B_(string const & l10n) const
362 LASSERT(language, /**/);
363 return getMessages(language->code()).get(l10n);
367 AuthorList & BufferParams::authors()
369 return pimpl_->authorlist;
373 AuthorList const & BufferParams::authors() const
375 return pimpl_->authorlist;
379 BranchList & BufferParams::branchlist()
381 return pimpl_->branchlist;
385 BranchList const & BufferParams::branchlist() const
387 return pimpl_->branchlist;
391 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
393 LASSERT(index < 4, /**/);
394 return pimpl_->temp_bullets[index];
398 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
400 LASSERT(index < 4, /**/);
401 return pimpl_->temp_bullets[index];
405 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
407 LASSERT(index < 4, /**/);
408 return pimpl_->user_defined_bullets[index];
412 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
414 LASSERT(index < 4, /**/);
415 return pimpl_->user_defined_bullets[index];
419 Spacing & BufferParams::spacing()
421 return pimpl_->spacing;
425 Spacing const & BufferParams::spacing() const
427 return pimpl_->spacing;
431 PDFOptions & BufferParams::pdfoptions()
433 return pimpl_->pdfoptions;
437 PDFOptions const & BufferParams::pdfoptions() const
439 return pimpl_->pdfoptions;
443 VSpace const & BufferParams::getDefSkip() const
445 return pimpl_->defskip;
449 void BufferParams::setDefSkip(VSpace const & vs)
451 pimpl_->defskip = vs;
455 string BufferParams::readToken(Lexer & lex, string const & token,
456 FileName const & filepath)
458 if (token == "\\textclass") {
459 lex.next();
460 string const classname = lex.getString();
461 // if there exists a local layout file, ignore the system one
462 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
463 string tcp;
464 LayoutFileList & bcl = LayoutFileList::get();
465 if (tcp.empty() && !filepath.empty())
466 tcp = bcl.addLocalLayout(classname, filepath.absFilename());
467 if (!tcp.empty())
468 setBaseClass(tcp);
469 else
470 setBaseClass(classname);
471 // We assume that a tex class exists for local or unknown layouts so this warning
472 // will only be given for system layouts.
473 if (!baseClass()->isTeXClassAvailable()) {
474 docstring const msg =
475 bformat(_("The layout file requested by this document,\n"
476 "%1$s.layout,\n"
477 "is not usable. This is probably because a LaTeX\n"
478 "class or style file required by it is not\n"
479 "available. See the Customization documentation\n"
480 "for more information.\n"), from_utf8(classname));
481 frontend::Alert::warning(_("Document class not available"),
482 msg + _("LyX will not be able to produce output."));
484 } else if (token == "\\begin_preamble") {
485 readPreamble(lex);
486 } else if (token == "\\begin_local_layout") {
487 readLocalLayout(lex);
488 } else if (token == "\\begin_modules") {
489 readModules(lex);
490 } else if (token == "\\options") {
491 lex.eatLine();
492 options = lex.getString();
493 } else if (token == "\\master") {
494 lex.eatLine();
495 master = lex.getString();
496 } else if (token == "\\language") {
497 readLanguage(lex);
498 } else if (token == "\\inputencoding") {
499 lex >> inputenc;
500 } else if (token == "\\graphics") {
501 readGraphicsDriver(lex);
502 } else if (token == "\\font_roman") {
503 lex >> fontsRoman;
504 } else if (token == "\\font_sans") {
505 lex >> fontsSans;
506 } else if (token == "\\font_typewriter") {
507 lex >> fontsTypewriter;
508 } else if (token == "\\font_default_family") {
509 lex >> fontsDefaultFamily;
510 } else if (token == "\\font_sc") {
511 lex >> fontsSC;
512 } else if (token == "\\font_osf") {
513 lex >> fontsOSF;
514 } else if (token == "\\font_sf_scale") {
515 lex >> fontsSansScale;
516 } else if (token == "\\font_tt_scale") {
517 lex >> fontsTypewriterScale;
518 } else if (token == "\\font_cjk") {
519 lex >> fontsCJK;
520 } else if (token == "\\paragraph_separation") {
521 string parsep;
522 lex >> parsep;
523 paragraph_separation = parseptranslator().find(parsep);
524 } else if (token == "\\defskip") {
525 lex.next();
526 string defskip = lex.getString();
527 if (defskip == "defskip")
528 // this is invalid
529 defskip = "medskip";
530 pimpl_->defskip = VSpace(defskip);
531 } else if (token == "\\quotes_language") {
532 string quotes_lang;
533 lex >> quotes_lang;
534 quotes_language = quoteslangtranslator().find(quotes_lang);
535 } else if (token == "\\papersize") {
536 string ppsize;
537 lex >> ppsize;
538 papersize = papersizetranslator().find(ppsize);
539 } else if (token == "\\use_geometry") {
540 lex >> use_geometry;
541 } else if (token == "\\use_amsmath") {
542 int use_ams;
543 lex >> use_ams;
544 use_amsmath = packagetranslator().find(use_ams);
545 } else if (token == "\\use_esint") {
546 int useesint;
547 lex >> useesint;
548 use_esint = packagetranslator().find(useesint);
549 } else if (token == "\\cite_engine") {
550 string engine;
551 lex >> engine;
552 cite_engine_ = citeenginetranslator().find(engine);
553 } else if (token == "\\use_bibtopic") {
554 lex >> use_bibtopic;
555 } else if (token == "\\tracking_changes") {
556 lex >> trackChanges;
557 } else if (token == "\\output_changes") {
558 lex >> outputChanges;
559 } else if (token == "\\branch") {
560 lex.next();
561 docstring branch = lex.getDocString();
562 branchlist().add(branch);
563 while (true) {
564 lex.next();
565 string const tok = lex.getString();
566 if (tok == "\\end_branch")
567 break;
568 Branch * branch_ptr = branchlist().find(branch);
569 if (tok == "\\selected") {
570 lex.next();
571 if (branch_ptr)
572 branch_ptr->setSelected(lex.getInteger());
574 // not yet operational
575 if (tok == "\\color") {
576 lex.eatLine();
577 string color = lex.getString();
578 if (branch_ptr)
579 branch_ptr->setColor(color);
580 // Update also the Color table:
581 if (color == "none")
582 color = lcolor.getX11Name(Color_background);
583 // FIXME UNICODE
584 lcolor.setColor(to_utf8(branch), color);
588 } else if (token == "\\author") {
589 lex.eatLine();
590 istringstream ss(lex.getString());
591 Author a;
592 ss >> a;
593 author_map.push_back(pimpl_->authorlist.record(a));
594 } else if (token == "\\paperorientation") {
595 string orient;
596 lex >> orient;
597 orientation = paperorientationtranslator().find(orient);
598 } else if (token == "\\paperwidth") {
599 lex >> paperwidth;
600 } else if (token == "\\paperheight") {
601 lex >> paperheight;
602 } else if (token == "\\leftmargin") {
603 lex >> leftmargin;
604 } else if (token == "\\topmargin") {
605 lex >> topmargin;
606 } else if (token == "\\rightmargin") {
607 lex >> rightmargin;
608 } else if (token == "\\bottommargin") {
609 lex >> bottommargin;
610 } else if (token == "\\headheight") {
611 lex >> headheight;
612 } else if (token == "\\headsep") {
613 lex >> headsep;
614 } else if (token == "\\footskip") {
615 lex >> footskip;
616 } else if (token == "\\columnsep") {
617 lex >> columnsep;
618 } else if (token == "\\paperfontsize") {
619 lex >> fontsize;
620 } else if (token == "\\papercolumns") {
621 lex >> columns;
622 } else if (token == "\\listings_params") {
623 string par;
624 lex >> par;
625 listings_params = InsetListingsParams(par).params();
626 } else if (token == "\\papersides") {
627 int psides;
628 lex >> psides;
629 sides = sidestranslator().find(psides);
630 } else if (token == "\\paperpagestyle") {
631 lex >> pagestyle;
632 } else if (token == "\\bullet") {
633 readBullets(lex);
634 } else if (token == "\\bulletLaTeX") {
635 readBulletsLaTeX(lex);
636 } else if (token == "\\secnumdepth") {
637 lex >> secnumdepth;
638 } else if (token == "\\tocdepth") {
639 lex >> tocdepth;
640 } else if (token == "\\spacing") {
641 string nspacing;
642 lex >> nspacing;
643 string tmp_val;
644 if (nspacing == "other") {
645 lex >> tmp_val;
647 spacing().set(spacetranslator().find(nspacing), tmp_val);
648 } else if (token == "\\float_placement") {
649 lex >> float_placement;
651 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
652 string toktmp = pdfoptions().readToken(lex, token);
653 if (!toktmp.empty()) {
654 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
655 toktmp << endl;
656 return toktmp;
658 } else {
659 lyxerr << "BufferParams::readToken(): Unknown token: " <<
660 token << endl;
661 return token;
664 return string();
668 void BufferParams::writeFile(ostream & os) const
670 // The top of the file is written by the buffer.
671 // Prints out the buffer info into the .lyx file given by file
673 // the textclass
674 os << "\\textclass " << baseClass()->name() << '\n';
676 // then the preamble
677 if (!preamble.empty()) {
678 // remove '\n' from the end of preamble
679 string const tmppreamble = rtrim(preamble, "\n");
680 os << "\\begin_preamble\n"
681 << tmppreamble
682 << "\n\\end_preamble\n";
685 // the options
686 if (!options.empty()) {
687 os << "\\options " << options << '\n';
690 // the master document
691 if (!master.empty()) {
692 os << "\\master " << master << '\n';
695 //the modules
696 if (!layoutModules_.empty()) {
697 os << "\\begin_modules" << '\n';
698 LayoutModuleList::const_iterator it = layoutModules_.begin();
699 for (; it != layoutModules_.end(); it++)
700 os << *it << '\n';
701 os << "\\end_modules" << '\n';
704 // local layout information
705 if (!local_layout.empty()) {
706 // remove '\n' from the end
707 string const tmplocal = rtrim(local_layout, "\n");
708 os << "\\begin_local_layout\n"
709 << tmplocal
710 << "\n\\end_local_layout\n";
713 // then the text parameters
714 if (language != ignore_language)
715 os << "\\language " << language->lang() << '\n';
716 os << "\\inputencoding " << inputenc
717 << "\n\\font_roman " << fontsRoman
718 << "\n\\font_sans " << fontsSans
719 << "\n\\font_typewriter " << fontsTypewriter
720 << "\n\\font_default_family " << fontsDefaultFamily
721 << "\n\\font_sc " << convert<string>(fontsSC)
722 << "\n\\font_osf " << convert<string>(fontsOSF)
723 << "\n\\font_sf_scale " << fontsSansScale
724 << "\n\\font_tt_scale " << fontsTypewriterScale
725 << '\n';
726 if (!fontsCJK.empty()) {
727 os << "\\font_cjk " << fontsCJK << '\n';
729 os << "\n\\graphics " << graphicsDriver << '\n';
731 if (!float_placement.empty()) {
732 os << "\\float_placement " << float_placement << '\n';
734 os << "\\paperfontsize " << fontsize << '\n';
736 spacing().writeFile(os);
737 pdfoptions().writeFile(os);
739 os << "\\papersize " << string_papersize[papersize]
740 << "\n\\use_geometry " << convert<string>(use_geometry)
741 << "\n\\use_amsmath " << use_amsmath
742 << "\n\\use_esint " << use_esint
743 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
744 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
745 << "\n\\paperorientation " << string_orientation[orientation]
746 << '\n';
748 BranchList::const_iterator it = branchlist().begin();
749 BranchList::const_iterator end = branchlist().end();
750 for (; it != end; ++it) {
751 os << "\\branch " << to_utf8(it->getBranch())
752 << "\n\\selected " << it->getSelected()
753 << "\n\\color " << lyx::X11hexname(it->getColor())
754 << "\n\\end_branch"
755 << "\n";
758 if (!paperwidth.empty())
759 os << "\\paperwidth "
760 << VSpace(paperwidth).asLyXCommand() << '\n';
761 if (!paperheight.empty())
762 os << "\\paperheight "
763 << VSpace(paperheight).asLyXCommand() << '\n';
764 if (!leftmargin.empty())
765 os << "\\leftmargin "
766 << VSpace(leftmargin).asLyXCommand() << '\n';
767 if (!topmargin.empty())
768 os << "\\topmargin "
769 << VSpace(topmargin).asLyXCommand() << '\n';
770 if (!rightmargin.empty())
771 os << "\\rightmargin "
772 << VSpace(rightmargin).asLyXCommand() << '\n';
773 if (!bottommargin.empty())
774 os << "\\bottommargin "
775 << VSpace(bottommargin).asLyXCommand() << '\n';
776 if (!headheight.empty())
777 os << "\\headheight "
778 << VSpace(headheight).asLyXCommand() << '\n';
779 if (!headsep.empty())
780 os << "\\headsep "
781 << VSpace(headsep).asLyXCommand() << '\n';
782 if (!footskip.empty())
783 os << "\\footskip "
784 << VSpace(footskip).asLyXCommand() << '\n';
785 if (!columnsep.empty())
786 os << "\\columnsep "
787 << VSpace(columnsep).asLyXCommand() << '\n';
788 os << "\\secnumdepth " << secnumdepth
789 << "\n\\tocdepth " << tocdepth
790 << "\n\\paragraph_separation "
791 << string_paragraph_separation[paragraph_separation]
792 << "\n\\defskip " << getDefSkip().asLyXCommand()
793 << "\n\\quotes_language "
794 << string_quotes_language[quotes_language]
795 << "\n\\papercolumns " << columns
796 << "\n\\papersides " << sides
797 << "\n\\paperpagestyle " << pagestyle << '\n';
798 if (!listings_params.empty())
799 os << "\\listings_params \"" <<
800 InsetListingsParams(listings_params).encodedString() << "\"\n";
801 for (int i = 0; i < 4; ++i) {
802 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
803 if (user_defined_bullet(i).getFont() != -1) {
804 os << "\\bullet " << i << " "
805 << user_defined_bullet(i).getFont() << " "
806 << user_defined_bullet(i).getCharacter() << " "
807 << user_defined_bullet(i).getSize() << "\n";
809 else {
810 // FIXME UNICODE
811 os << "\\bulletLaTeX " << i << " \""
812 << lyx::to_ascii(user_defined_bullet(i).getText())
813 << "\"\n";
818 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
819 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
821 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
822 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
823 for (; a_it != a_end; ++a_it) {
824 if (a_it->second.used())
825 os << "\\author " << a_it->second << "\n";
826 else
827 os << "\\author " << Author() << "\n";
832 void BufferParams::validate(LaTeXFeatures & features) const
834 features.require(documentClass().requires());
836 if (outputChanges) {
837 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
838 bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
839 LaTeXFeatures::isAvailable("xcolor");
841 switch (features.runparams().flavor) {
842 case OutputParams::LATEX:
843 if (dvipost) {
844 features.require("ct-dvipost");
845 features.require("dvipost");
846 } else if (xcolorsoul) {
847 features.require("ct-xcolor-soul");
848 features.require("soul");
849 features.require("xcolor");
850 } else {
851 features.require("ct-none");
853 break;
854 case OutputParams::PDFLATEX:
855 if (xcolorsoul) {
856 features.require("ct-xcolor-soul");
857 features.require("soul");
858 features.require("xcolor");
859 // improves color handling in PDF output
860 features.require("pdfcolmk");
861 } else {
862 features.require("ct-none");
864 break;
865 default:
866 break;
870 // Floats with 'Here definitely' as default setting.
871 if (float_placement.find('H') != string::npos)
872 features.require("float");
874 // AMS Style is at document level
875 if (use_amsmath == package_on
876 || documentClass().provides("amsmath"))
877 features.require("amsmath");
878 if (use_esint == package_on)
879 features.require("esint");
881 // Document-level line spacing
882 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
883 features.require("setspace");
885 // the bullet shapes are buffer level not paragraph level
886 // so they are tested here
887 for (int i = 0; i < 4; ++i) {
888 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
889 continue;
890 int const font = user_defined_bullet(i).getFont();
891 if (font == 0) {
892 int const c = user_defined_bullet(i).getCharacter();
893 if (c == 16
894 || c == 17
895 || c == 25
896 || c == 26
897 || c == 31) {
898 features.require("latexsym");
900 } else if (font == 1) {
901 features.require("amssymb");
902 } else if (font >= 2 && font <= 5) {
903 features.require("pifont");
907 if (pdfoptions().use_hyperref)
908 features.require("hyperref");
910 if (language->lang() == "vietnamese")
911 features.require("vietnamese");
912 else if (language->lang() == "japanese")
913 features.require("japanese");
917 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
918 TexRow & texrow) const
920 os << "\\documentclass";
922 DocumentClass const & tclass = documentClass();
924 ostringstream clsoptions; // the document class options.
926 if (tokenPos(tclass.opt_fontsize(),
927 '|', fontsize) >= 0) {
928 // only write if existing in list (and not default)
929 clsoptions << fontsize << "pt,";
932 // custom, A3, B3 and B4 paper sizes need geometry
933 bool nonstandard_papersize = papersize == PAPER_B3
934 || papersize == PAPER_B4
935 || papersize == PAPER_A3
936 || papersize == PAPER_CUSTOM;
938 if (!use_geometry) {
939 switch (papersize) {
940 case PAPER_A4:
941 clsoptions << "a4paper,";
942 break;
943 case PAPER_USLETTER:
944 clsoptions << "letterpaper,";
945 break;
946 case PAPER_A5:
947 clsoptions << "a5paper,";
948 break;
949 case PAPER_B5:
950 clsoptions << "b5paper,";
951 break;
952 case PAPER_USEXECUTIVE:
953 clsoptions << "executivepaper,";
954 break;
955 case PAPER_USLEGAL:
956 clsoptions << "legalpaper,";
957 break;
958 case PAPER_DEFAULT:
959 case PAPER_A3:
960 case PAPER_B3:
961 case PAPER_B4:
962 case PAPER_CUSTOM:
963 break;
967 // if needed
968 if (sides != tclass.sides()) {
969 switch (sides) {
970 case OneSide:
971 clsoptions << "oneside,";
972 break;
973 case TwoSides:
974 clsoptions << "twoside,";
975 break;
979 // if needed
980 if (columns != tclass.columns()) {
981 if (columns == 2)
982 clsoptions << "twocolumn,";
983 else
984 clsoptions << "onecolumn,";
987 if (!use_geometry
988 && orientation == ORIENTATION_LANDSCAPE)
989 clsoptions << "landscape,";
991 // language should be a parameter to \documentclass
992 if (language->babel() == "hebrew"
993 && default_language->babel() != "hebrew")
994 // This seems necessary
995 features.useLanguage(default_language);
997 ostringstream language_options;
998 bool const use_babel = features.useBabel();
999 if (use_babel) {
1000 language_options << features.getLanguages();
1001 if (!language->babel().empty()) {
1002 if (!language_options.str().empty())
1003 language_options << ',';
1004 language_options << language->babel();
1006 // if Vietnamese is used, babel must directly be loaded with the
1007 // language options, not in the class options, see
1008 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1009 size_t viet = language_options.str().find("vietnam");
1010 // viet = string::npos when not found
1011 // if Japanese is used, babel must directly be loaded with the
1012 // language options, not in the class options, see
1013 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1014 size_t japan = language_options.str().find("japanese");
1015 // japan = string::npos when not found
1016 if (lyxrc.language_global_options && !language_options.str().empty()
1017 && viet == string::npos && japan == string::npos)
1018 clsoptions << language_options.str() << ',';
1021 // the user-defined options
1022 if (!options.empty()) {
1023 clsoptions << options << ',';
1026 string strOptions(clsoptions.str());
1027 if (!strOptions.empty()) {
1028 strOptions = rtrim(strOptions, ",");
1029 // FIXME UNICODE
1030 os << '[' << from_utf8(strOptions) << ']';
1033 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1034 texrow.newline();
1035 // end of \documentclass defs
1037 // font selection must be done before loading fontenc.sty
1038 string const fonts =
1039 loadFonts(fontsRoman, fontsSans,
1040 fontsTypewriter, fontsSC, fontsOSF,
1041 fontsSansScale, fontsTypewriterScale);
1042 if (!fonts.empty()) {
1043 os << from_ascii(fonts);
1044 texrow.newline();
1046 if (fontsDefaultFamily != "default")
1047 os << "\\renewcommand{\\familydefault}{\\"
1048 << from_ascii(fontsDefaultFamily) << "}\n";
1050 // set font encoding
1051 // this one is not per buffer
1052 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
1053 if (lyxrc.fontenc != "default") {
1054 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
1055 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1056 << ",LFE,LAE]{fontenc}\n";
1057 texrow.newline();
1058 } else {
1059 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1060 << "]{fontenc}\n";
1061 texrow.newline();
1065 // handle inputenc etc.
1066 writeEncodingPreamble(os, features, texrow);
1068 if (!listings_params.empty()) {
1069 os << "\\usepackage{listings}\n";
1070 texrow.newline();
1071 os << "\\lstset{";
1072 // do not test validity because listings_params is supposed to be valid
1073 string par = InsetListingsParams(listings_params).separatedParams(true);
1074 os << from_ascii(par);
1075 // count the number of newlines
1076 for (size_t i = 0; i < par.size(); ++i)
1077 if (par[i] == '\n')
1078 texrow.newline();
1079 os << "}\n";
1080 texrow.newline();
1082 if (use_geometry || nonstandard_papersize) {
1083 os << "\\usepackage{geometry}\n";
1084 texrow.newline();
1085 os << "\\geometry{verbose";
1086 if (orientation == ORIENTATION_LANDSCAPE)
1087 os << ",landscape";
1088 switch (papersize) {
1089 case PAPER_CUSTOM:
1090 if (!paperwidth.empty())
1091 os << ",paperwidth="
1092 << from_ascii(paperwidth);
1093 if (!paperheight.empty())
1094 os << ",paperheight="
1095 << from_ascii(paperheight);
1096 break;
1097 case PAPER_USLETTER:
1098 os << ",letterpaper";
1099 break;
1100 case PAPER_USLEGAL:
1101 os << ",legalpaper";
1102 break;
1103 case PAPER_USEXECUTIVE:
1104 os << ",executivepaper";
1105 break;
1106 case PAPER_A3:
1107 os << ",a3paper";
1108 break;
1109 case PAPER_A4:
1110 os << ",a4paper";
1111 break;
1112 case PAPER_A5:
1113 os << ",a5paper";
1114 break;
1115 case PAPER_B3:
1116 os << ",b3paper";
1117 break;
1118 case PAPER_B4:
1119 os << ",b4paper";
1120 break;
1121 case PAPER_B5:
1122 os << ",b5paper";
1123 break;
1124 default:
1125 // default papersize ie PAPER_DEFAULT
1126 switch (lyxrc.default_papersize) {
1127 case PAPER_DEFAULT: // keep compiler happy
1128 case PAPER_USLETTER:
1129 os << ",letterpaper";
1130 break;
1131 case PAPER_USLEGAL:
1132 os << ",legalpaper";
1133 break;
1134 case PAPER_USEXECUTIVE:
1135 os << ",executivepaper";
1136 break;
1137 case PAPER_A3:
1138 os << ",a3paper";
1139 break;
1140 case PAPER_A4:
1141 os << ",a4paper";
1142 break;
1143 case PAPER_A5:
1144 os << ",a5paper";
1145 break;
1146 case PAPER_B5:
1147 os << ",b5paper";
1148 break;
1149 case PAPER_B3:
1150 case PAPER_B4:
1151 case PAPER_CUSTOM:
1152 break;
1155 if (!topmargin.empty())
1156 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1157 if (!bottommargin.empty())
1158 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1159 if (!leftmargin.empty())
1160 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1161 if (!rightmargin.empty())
1162 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1163 if (!headheight.empty())
1164 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1165 if (!headsep.empty())
1166 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1167 if (!footskip.empty())
1168 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1169 if (!columnsep.empty())
1170 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1171 os << "}\n";
1172 texrow.newline();
1173 } else if (orientation == ORIENTATION_LANDSCAPE) {
1174 features.require("papersize");
1177 if (tokenPos(tclass.opt_pagestyle(),
1178 '|', pagestyle) >= 0) {
1179 if (pagestyle == "fancy") {
1180 os << "\\usepackage{fancyhdr}\n";
1181 texrow.newline();
1183 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1184 texrow.newline();
1187 // Only if class has a ToC hierarchy
1188 if (tclass.hasTocLevels()) {
1189 if (secnumdepth != tclass.secnumdepth()) {
1190 os << "\\setcounter{secnumdepth}{"
1191 << secnumdepth
1192 << "}\n";
1193 texrow.newline();
1195 if (tocdepth != tclass.tocdepth()) {
1196 os << "\\setcounter{tocdepth}{"
1197 << tocdepth
1198 << "}\n";
1199 texrow.newline();
1203 if (paragraph_separation) {
1204 switch (getDefSkip().kind()) {
1205 case VSpace::SMALLSKIP:
1206 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1207 break;
1208 case VSpace::MEDSKIP:
1209 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1210 break;
1211 case VSpace::BIGSKIP:
1212 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1213 break;
1214 case VSpace::LENGTH:
1215 os << "\\setlength{\\parskip}{"
1216 << from_utf8(getDefSkip().length().asLatexString())
1217 << "}\n";
1218 break;
1219 default: // should never happen // Then delete it.
1220 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1221 break;
1223 texrow.newline();
1225 os << "\\setlength{\\parindent}{0pt}\n";
1226 texrow.newline();
1229 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel here.
1230 if (use_babel
1231 && (features.isRequired("jurabib")
1232 || features.isRequired("hyperref")
1233 || features.isRequired("vietnamese")
1234 || features.isRequired("japanese") ) ) {
1235 // FIXME UNICODE
1236 os << from_utf8(babelCall(language_options.str()))
1237 << '\n'
1238 << from_utf8(features.getBabelOptions());
1239 texrow.newline();
1242 // Now insert the LyX specific LaTeX commands...
1244 // The optional packages;
1245 docstring lyxpreamble(from_ascii(features.getPackages()));
1247 // Line spacing
1248 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1250 // PDF support.
1251 // * Hyperref manual: "Make sure it comes last of your loaded
1252 // packages, to give it a fighting chance of not being over-written,
1253 // since its job is to redefine many LATEX commands."
1254 // * Email from Heiko Oberdiek: "It is usually better to load babel
1255 // before hyperref. Then hyperref has a chance to detect babel.
1256 // * Has to be loaded before the "LyX specific LaTeX commands" to
1257 // avoid errors with algorithm floats.
1258 // use hyperref explicitely when it is required
1259 if (features.isRequired("hyperref")) {
1260 odocstringstream oss;
1261 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1262 lyxpreamble += oss.str();
1265 // Will be surrounded by \makeatletter and \makeatother when needed
1266 docstring atlyxpreamble;
1268 // Some macros LyX will need
1269 docstring tmppreamble(from_ascii(features.getMacros()));
1271 if (!tmppreamble.empty())
1272 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1273 "LyX specific LaTeX commands.\n"
1274 + tmppreamble + '\n';
1276 // the text class specific preamble
1277 tmppreamble = features.getTClassPreamble();
1278 if (!tmppreamble.empty())
1279 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1280 "Textclass specific LaTeX commands.\n"
1281 + tmppreamble + '\n';
1283 /* the user-defined preamble */
1284 if (!preamble.empty())
1285 // FIXME UNICODE
1286 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1287 "User specified LaTeX commands.\n"
1288 + from_utf8(preamble) + '\n';
1290 // subfig loads internally the LaTeX package "caption". As
1291 // caption is a very popular package, users will load it in
1292 // the preamble. Therefore we must load subfig behind the
1293 // user-defined preamble and check if the caption package was
1294 // loaded or not. For the case that caption is loaded before
1295 // subfig, there is the subfig option "caption=false". This
1296 // option also works when a koma-script class is used and
1297 // koma's own caption commands are used instead of caption. We
1298 // use \PassOptionsToPackage here because the user could have
1299 // already loaded subfig in the preamble.
1300 if (features.isRequired("subfig")) {
1301 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1302 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1303 "\\usepackage{subfig}\n";
1306 // Itemize bullet settings need to be last in case the user
1307 // defines their own bullets that use a package included
1308 // in the user-defined preamble -- ARRae
1309 // Actually it has to be done much later than that
1310 // since some packages like frenchb make modifications
1311 // at \begin{document} time -- JMarc
1312 docstring bullets_def;
1313 for (int i = 0; i < 4; ++i) {
1314 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1315 if (bullets_def.empty())
1316 bullets_def += "\\AtBeginDocument{\n";
1317 bullets_def += " \\def\\labelitemi";
1318 switch (i) {
1319 // `i' is one less than the item to modify
1320 case 0:
1321 break;
1322 case 1:
1323 bullets_def += 'i';
1324 break;
1325 case 2:
1326 bullets_def += "ii";
1327 break;
1328 case 3:
1329 bullets_def += 'v';
1330 break;
1332 bullets_def += '{' +
1333 user_defined_bullet(i).getText()
1334 + "}\n";
1338 if (!bullets_def.empty())
1339 atlyxpreamble += bullets_def + "}\n\n";
1341 if (atlyxpreamble.find(from_ascii("@")) != docstring::npos)
1342 lyxpreamble += "\n\\makeatletter\n"
1343 + atlyxpreamble + "\\makeatother\n\n";
1344 else
1345 lyxpreamble += '\n' + atlyxpreamble;
1347 // We try to load babel late, in case it interferes
1348 // with other packages.
1349 // Jurabib and Hyperref have to be called after babel, though.
1350 if (use_babel && !features.isRequired("jurabib")
1351 && !features.isRequired("hyperref")
1352 && !features.isRequired("vietnamese")
1353 && !features.isRequired("japanese")) {
1354 // FIXME UNICODE
1355 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1356 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1359 int const nlines =
1360 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1361 for (int j = 0; j != nlines; ++j) {
1362 texrow.newline();
1365 os << lyxpreamble;
1366 return use_babel;
1370 void BufferParams::useClassDefaults()
1372 DocumentClass const & tclass = documentClass();
1374 sides = tclass.sides();
1375 columns = tclass.columns();
1376 pagestyle = tclass.pagestyle();
1377 options = tclass.options();
1378 // Only if class has a ToC hierarchy
1379 if (tclass.hasTocLevels()) {
1380 secnumdepth = tclass.secnumdepth();
1381 tocdepth = tclass.tocdepth();
1386 bool BufferParams::hasClassDefaults() const
1388 DocumentClass const & tclass = documentClass();
1390 return sides == tclass.sides()
1391 && columns == tclass.columns()
1392 && pagestyle == tclass.pagestyle()
1393 && options == tclass.options()
1394 && secnumdepth == tclass.secnumdepth()
1395 && tocdepth == tclass.tocdepth();
1399 DocumentClass const & BufferParams::documentClass() const
1401 return *doc_class_;
1405 DocumentClass const * BufferParams::documentClassPtr() const {
1406 return doc_class_;
1410 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1411 // evil, but this function is evil
1412 doc_class_ = const_cast<DocumentClass *>(tc);
1416 bool BufferParams::setBaseClass(string const & classname)
1418 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1419 LayoutFileList & bcl = LayoutFileList::get();
1420 if (!bcl.haveClass(classname)) {
1421 docstring s =
1422 bformat(_("The document class %1$s could not be found. "
1423 "A default textclass with default layouts will be used. "
1424 "LyX might not be able to produce output unless a correct "
1425 "textclass is selected from the document settings dialog."),
1426 from_utf8(classname));
1427 frontend::Alert::error(_("Document class not found"), s);
1428 bcl.addEmptyClass(classname);
1431 if (bcl[classname].load()) {
1432 pimpl_->baseClass_ = classname;
1433 return true;
1436 docstring s =
1437 bformat(_("The document class %1$s could not be loaded."),
1438 from_utf8(classname));
1439 frontend::Alert::error(_("Could not load class"), s);
1440 return false;
1444 LayoutFile const * BufferParams::baseClass() const
1446 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1447 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1448 else
1449 return 0;
1453 LayoutFileIndex const & BufferParams::baseClassID() const
1455 return pimpl_->baseClass_;
1459 void BufferParams::makeDocumentClass()
1461 if (!baseClass())
1462 return;
1464 doc_class_ = &(DocumentClassBundle::get().newClass(*baseClass()));
1466 //FIXME It might be worth loading the children's modules here,
1467 //just as we load their bibliographies and such, instead of just
1468 //doing a check in InsetInclude.
1469 LayoutModuleList::const_iterator it = layoutModules_.begin();
1470 for (; it != layoutModules_.end(); it++) {
1471 string const modName = *it;
1472 LyXModule * lm = moduleList[modName];
1473 if (!lm) {
1474 docstring const msg =
1475 bformat(_("The module %1$s has been requested by\n"
1476 "this document but has not been found in the list of\n"
1477 "available modules. If you recently installed it, you\n"
1478 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1479 frontend::Alert::warning(_("Module not available"),
1480 msg + _("Some layouts may not be available."));
1481 LYXERR0("BufferParams::makeDocumentClass(): Module " <<
1482 modName << " requested but not found in module list.");
1483 continue;
1485 if (!lm->isAvailable()) {
1486 docstring const msg =
1487 bformat(_("The module %1$s requires a package that is\n"
1488 "not available in your LaTeX installation. LaTeX output\n"
1489 "may not be possible.\n"), from_utf8(modName));
1490 frontend::Alert::warning(_("Package not available"), msg);
1492 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1493 if (!doc_class_->read(layout_file, TextClass::MODULE)) {
1494 docstring const msg =
1495 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1496 frontend::Alert::warning(_("Read Error"), msg);
1499 if (!local_layout.empty()) {
1500 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1501 docstring const msg = _("Error reading internal layout information");
1502 frontend::Alert::warning(_("Read Error"), msg);
1508 vector<string> const & BufferParams::getModules() const
1510 return layoutModules_;
1515 bool BufferParams::addLayoutModule(string const & modName)
1517 LayoutModuleList::const_iterator it = layoutModules_.begin();
1518 LayoutModuleList::const_iterator end = layoutModules_.end();
1519 for (; it != end; it++)
1520 if (*it == modName)
1521 return false;
1522 layoutModules_.push_back(modName);
1523 return true;
1527 void BufferParams::clearLayoutModules()
1529 layoutModules_.clear();
1533 Font const BufferParams::getFont() const
1535 FontInfo f = documentClass().defaultfont();
1536 if (fontsDefaultFamily == "rmdefault")
1537 f.setFamily(ROMAN_FAMILY);
1538 else if (fontsDefaultFamily == "sfdefault")
1539 f.setFamily(SANS_FAMILY);
1540 else if (fontsDefaultFamily == "ttdefault")
1541 f.setFamily(TYPEWRITER_FAMILY);
1542 return Font(f, language);
1546 void BufferParams::readPreamble(Lexer & lex)
1548 if (lex.getString() != "\\begin_preamble")
1549 lyxerr << "Error (BufferParams::readPreamble):"
1550 "consistency check failed." << endl;
1552 preamble = lex.getLongString("\\end_preamble");
1556 void BufferParams::readLocalLayout(Lexer & lex)
1558 if (lex.getString() != "\\begin_local_layout")
1559 lyxerr << "Error (BufferParams::readLocalLayout):"
1560 "consistency check failed." << endl;
1562 local_layout = lex.getLongString("\\end_local_layout");
1566 void BufferParams::readLanguage(Lexer & lex)
1568 if (!lex.next()) return;
1570 string const tmptok = lex.getString();
1572 // check if tmptok is part of tex_babel in tex-defs.h
1573 language = languages.getLanguage(tmptok);
1574 if (!language) {
1575 // Language tmptok was not found
1576 language = default_language;
1577 lyxerr << "Warning: Setting language `"
1578 << tmptok << "' to `" << language->lang()
1579 << "'." << endl;
1584 void BufferParams::readGraphicsDriver(Lexer & lex)
1586 if (!lex.next())
1587 return;
1589 string const tmptok = lex.getString();
1590 // check if tmptok is part of tex_graphics in tex_defs.h
1591 int n = 0;
1592 while (true) {
1593 string const test = tex_graphics[n++];
1595 if (test == tmptok) {
1596 graphicsDriver = tmptok;
1597 break;
1599 if (test.empty()) {
1600 lex.printError(
1601 "Warning: graphics driver `$$Token' not recognized!\n"
1602 " Setting graphics driver to `default'.\n");
1603 graphicsDriver = "default";
1604 break;
1610 void BufferParams::readBullets(Lexer & lex)
1612 if (!lex.next())
1613 return;
1615 int const index = lex.getInteger();
1616 lex.next();
1617 int temp_int = lex.getInteger();
1618 user_defined_bullet(index).setFont(temp_int);
1619 temp_bullet(index).setFont(temp_int);
1620 lex >> temp_int;
1621 user_defined_bullet(index).setCharacter(temp_int);
1622 temp_bullet(index).setCharacter(temp_int);
1623 lex >> temp_int;
1624 user_defined_bullet(index).setSize(temp_int);
1625 temp_bullet(index).setSize(temp_int);
1629 void BufferParams::readBulletsLaTeX(Lexer & lex)
1631 // The bullet class should be able to read this.
1632 if (!lex.next())
1633 return;
1634 int const index = lex.getInteger();
1635 lex.next(true);
1636 docstring const temp_str = lex.getDocString();
1638 user_defined_bullet(index).setText(temp_str);
1639 temp_bullet(index).setText(temp_str);
1643 void BufferParams::readModules(Lexer & lex)
1645 if (!lex.eatLine()) {
1646 lyxerr << "Error (BufferParams::readModules):"
1647 "Unexpected end of input." << endl;
1648 return;
1650 while (true) {
1651 string mod = lex.getString();
1652 if (mod == "\\end_modules")
1653 break;
1654 addLayoutModule(mod);
1655 lex.eatLine();
1660 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1662 char real_papersize = papersize;
1663 if (real_papersize == PAPER_DEFAULT)
1664 real_papersize = lyxrc.default_papersize;
1666 switch (real_papersize) {
1667 case PAPER_DEFAULT:
1668 // could be anything, so don't guess
1669 return string();
1670 case PAPER_CUSTOM: {
1671 if (purpose == XDVI && !paperwidth.empty() &&
1672 !paperheight.empty()) {
1673 // heightxwidth<unit>
1674 string first = paperwidth;
1675 string second = paperheight;
1676 if (orientation == ORIENTATION_LANDSCAPE)
1677 first.swap(second);
1678 // cut off unit.
1679 return first.erase(first.length() - 2)
1680 + "x" + second;
1682 return string();
1684 case PAPER_A3:
1685 return "a3";
1686 case PAPER_A4:
1687 return "a4";
1688 case PAPER_A5:
1689 return "a5";
1690 case PAPER_B3:
1691 // dvips and dvipdfm do not know this
1692 if (purpose == DVIPS || purpose == DVIPDFM)
1693 return string();
1694 return "b3";
1695 case PAPER_B4:
1696 // dvipdfm does not know this
1697 if (purpose == DVIPDFM)
1698 return string();
1699 return "b4";
1700 case PAPER_B5:
1701 // dvipdfm does not know this
1702 if (purpose == DVIPDFM)
1703 return string();
1704 return "b5";
1705 case PAPER_USEXECUTIVE:
1706 // dvipdfm does not know this
1707 if (purpose == DVIPDFM)
1708 return string();
1709 return "foolscap";
1710 case PAPER_USLEGAL:
1711 return "legal";
1712 case PAPER_USLETTER:
1713 default:
1714 if (purpose == XDVI)
1715 return "us";
1716 return "letter";
1721 string const BufferParams::dvips_options() const
1723 string result;
1725 if (use_geometry
1726 && papersize == PAPER_CUSTOM
1727 && !lyxrc.print_paper_dimension_flag.empty()
1728 && !paperwidth.empty()
1729 && !paperheight.empty()) {
1730 // using a custom papersize
1731 result = lyxrc.print_paper_dimension_flag;
1732 result += ' ' + paperwidth;
1733 result += ',' + paperheight;
1734 } else {
1735 string const paper_option = paperSizeName(DVIPS);
1736 if (!paper_option.empty() && (paper_option != "letter" ||
1737 orientation != ORIENTATION_LANDSCAPE)) {
1738 // dvips won't accept -t letter -t landscape.
1739 // In all other cases, include the paper size
1740 // explicitly.
1741 result = lyxrc.print_paper_flag;
1742 result += ' ' + paper_option;
1745 if (orientation == ORIENTATION_LANDSCAPE &&
1746 papersize != PAPER_CUSTOM)
1747 result += ' ' + lyxrc.print_landscape_flag;
1748 return result;
1752 string BufferParams::babelCall(string const & lang_opts) const
1754 string lang_pack = lyxrc.language_package;
1755 if (lang_pack != "\\usepackage{babel}")
1756 return lang_pack;
1757 // suppress the babel call when there is no babel language defined
1758 // for the document language in the lib/languages file and if no
1759 // other languages are used (lang_opts is then empty)
1760 if (lang_opts.empty())
1761 return string();
1762 // If Vietnamese is used, babel must directly be loaded with the
1763 // language options, see
1764 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1765 size_t viet = lang_opts.find("vietnam");
1766 // viet = string::npos when not found
1767 // If Japanese is used, babel must directly be loaded with the
1768 // language options, see
1769 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1770 size_t japan = lang_opts.find("japanese");
1771 // japan = string::npos when not found
1772 if (!lyxrc.language_global_options || viet != string::npos || japan != string::npos)
1773 return "\\usepackage[" + lang_opts + "]{babel}";
1774 return lang_pack;
1778 void BufferParams::writeEncodingPreamble(odocstream & os,
1779 LaTeXFeatures & features, TexRow & texrow) const
1781 if (inputenc == "auto") {
1782 string const doc_encoding =
1783 language->encoding()->latexName();
1784 Encoding::Package const package =
1785 language->encoding()->package();
1787 // Create a list with all the input encodings used
1788 // in the document
1789 set<string> encodings =
1790 features.getEncodingSet(doc_encoding);
1792 // If the encodings EUC-JP-plain, JIS-plain, or SJIS-plain are used, the
1793 // package inputenc must be omitted. Therefore set the encoding to empty.
1794 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1795 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1796 doc_encoding == "SJIS-plain")
1797 encodings.clear();
1799 if (!encodings.empty() || package == Encoding::inputenc) {
1800 os << "\\usepackage[";
1801 set<string>::const_iterator it = encodings.begin();
1802 set<string>::const_iterator const end = encodings.end();
1803 if (it != end) {
1804 os << from_ascii(*it);
1805 ++it;
1807 for (; it != end; ++it)
1808 os << ',' << from_ascii(*it);
1809 if (package == Encoding::inputenc) {
1810 if (!encodings.empty())
1811 os << ',';
1812 os << from_ascii(doc_encoding);
1814 os << "]{inputenc}\n";
1815 texrow.newline();
1817 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1818 os << "\\usepackage{CJK}\n";
1819 texrow.newline();
1821 } else if (inputenc != "default") {
1822 switch (encoding().package()) {
1823 case Encoding::none:
1824 break;
1825 case Encoding::inputenc:
1826 os << "\\usepackage[" << from_ascii(inputenc)
1827 << "]{inputenc}\n";
1828 texrow.newline();
1829 break;
1830 case Encoding::CJK:
1831 os << "\\usepackage{CJK}\n";
1832 texrow.newline();
1833 break;
1837 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1838 // armscii8 is used for Armenian.
1839 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1840 os << "\\usepackage{armtex}\n";
1841 texrow.newline();
1846 string const BufferParams::loadFonts(string const & rm,
1847 string const & sf, string const & tt,
1848 bool const & sc, bool const & osf,
1849 int const & sfscale, int const & ttscale) const
1851 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1852 several packages have been replaced by others, that might not
1853 be installed on every system. We have to take care for that
1854 (see psnfss.pdf). We try to support all psnfss fonts as well
1855 as the fonts that have become de facto standard in the LaTeX
1856 world (e.g. Latin Modern). We do not support obsolete fonts
1857 (like PSLatex). In general, it should be possible to mix any
1858 rm font with any sf or tt font, respectively. (JSpitzm)
1859 TODO:
1860 -- separate math fonts.
1863 if (rm == "default" && sf == "default" && tt == "default")
1864 //nothing to do
1865 return string();
1867 ostringstream os;
1869 // ROMAN FONTS
1870 // Computer Modern (must be explicitely selectable -- there might be classes
1871 // that define a different default font!
1872 if (rm == "cmr") {
1873 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1874 // osf for Computer Modern needs eco.sty
1875 if (osf)
1876 os << "\\usepackage{eco}\n";
1878 // Latin Modern Roman
1879 else if (rm == "lmodern")
1880 os << "\\usepackage{lmodern}\n";
1881 // AE
1882 else if (rm == "ae") {
1883 // not needed when using OT1 font encoding.
1884 if (lyxrc.fontenc != "default")
1885 os << "\\usepackage{ae,aecompl}\n";
1887 // Times
1888 else if (rm == "times") {
1889 // try to load the best available package
1890 if (LaTeXFeatures::isAvailable("mathptmx"))
1891 os << "\\usepackage{mathptmx}\n";
1892 else if (LaTeXFeatures::isAvailable("mathptm"))
1893 os << "\\usepackage{mathptm}\n";
1894 else
1895 os << "\\usepackage{times}\n";
1897 // Palatino
1898 else if (rm == "palatino") {
1899 // try to load the best available package
1900 if (LaTeXFeatures::isAvailable("mathpazo")) {
1901 os << "\\usepackage";
1902 if (osf || sc) {
1903 os << '[';
1904 if (!osf)
1905 os << "sc";
1906 else
1907 // "osf" includes "sc"!
1908 os << "osf";
1909 os << ']';
1911 os << "{mathpazo}\n";
1913 else if (LaTeXFeatures::isAvailable("mathpple"))
1914 os << "\\usepackage{mathpple}\n";
1915 else
1916 os << "\\usepackage{palatino}\n";
1918 // Utopia
1919 else if (rm == "utopia") {
1920 // fourier supersedes utopia.sty, but does
1921 // not work with OT1 encoding.
1922 if (LaTeXFeatures::isAvailable("fourier")
1923 && lyxrc.fontenc != "default") {
1924 os << "\\usepackage";
1925 if (osf || sc) {
1926 os << '[';
1927 if (sc)
1928 os << "expert";
1929 if (osf && sc)
1930 os << ',';
1931 if (osf)
1932 os << "oldstyle";
1933 os << ']';
1935 os << "{fourier}\n";
1937 else
1938 os << "\\usepackage{utopia}\n";
1940 // Bera (complete fontset)
1941 else if (rm == "bera" && sf == "default" && tt == "default")
1942 os << "\\usepackage{bera}\n";
1943 // everything else
1944 else if (rm != "default")
1945 os << "\\usepackage" << "{" << rm << "}\n";
1947 // SANS SERIF
1948 // Helvetica, Bera Sans
1949 if (sf == "helvet" || sf == "berasans") {
1950 if (sfscale != 100)
1951 os << "\\usepackage[scaled=" << float(sfscale) / 100
1952 << "]{" << sf << "}\n";
1953 else
1954 os << "\\usepackage{" << sf << "}\n";
1956 // Avant Garde
1957 else if (sf == "avant")
1958 os << "\\usepackage{" << sf << "}\n";
1959 // Computer Modern, Latin Modern, CM Bright
1960 else if (sf != "default")
1961 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1963 // monospaced/typewriter
1964 // Courier, LuxiMono
1965 if (tt == "luximono" || tt == "beramono") {
1966 if (ttscale != 100)
1967 os << "\\usepackage[scaled=" << float(ttscale) / 100
1968 << "]{" << tt << "}\n";
1969 else
1970 os << "\\usepackage{" << tt << "}\n";
1972 // Courier
1973 else if (tt == "courier" )
1974 os << "\\usepackage{" << tt << "}\n";
1975 // Computer Modern, Latin Modern, CM Bright
1976 else if (tt != "default")
1977 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1979 return os.str();
1983 Encoding const & BufferParams::encoding() const
1985 if (inputenc == "auto" || inputenc == "default")
1986 return *language->encoding();
1987 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
1988 if (enc)
1989 return *enc;
1990 LYXERR0("Unknown inputenc value `" << inputenc
1991 << "'. Using `auto' instead.");
1992 return *language->encoding();
1996 CiteEngine BufferParams::citeEngine() const
1998 // FIXME the class should provide the numerical/
1999 // authoryear choice
2000 if (documentClass().provides("natbib")
2001 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2002 return ENGINE_NATBIB_AUTHORYEAR;
2003 return cite_engine_;
2007 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2009 cite_engine_ = cite_engine;
2012 } // namespace lyx