fix cmake
[lyx.git] / src / BufferParams.cpp
blob3f14e3a7b0f0c754c7453c3a32772da11523aff9
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", "executivepaper", "legalpaper",
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, biblio::CiteEngine> CiteEngineTranslator;
231 CiteEngineTranslator const init_citeenginetranslator()
233 CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
234 translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
235 translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
236 translator.addPair("jurabib", biblio::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 vector<string> extraEmbeddedFiles;
281 Bullet temp_bullets[4];
282 Bullet user_defined_bullets[4];
283 Spacing spacing;
284 /** This is the amount of space used for paragraph_separation "skip",
285 * and for detached paragraphs in "indented" documents.
287 VSpace defskip;
288 PDFOptions pdfoptions;
289 LayoutFileIndex baseClass_;
293 BufferParams::Impl::Impl()
294 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
296 // set initial author
297 // FIXME UNICODE
298 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
302 BufferParams::Impl *
303 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
305 BOOST_ASSERT(ptr);
307 return new BufferParams::Impl(*ptr);
311 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
313 delete ptr;
317 BufferParams::BufferParams()
318 : pimpl_(new Impl)
320 setBaseClass(defaultBaseclass());
321 makeDocumentClass();
322 paragraph_separation = ParagraphIndentSeparation;
323 quotes_language = InsetQuotes::EnglishQuotes;
324 fontsize = "default";
326 /* PaperLayout */
327 papersize = PAPER_DEFAULT;
328 orientation = ORIENTATION_PORTRAIT;
329 use_geometry = false;
330 use_amsmath = package_auto;
331 use_esint = package_auto;
332 cite_engine_ = biblio::ENGINE_BASIC;
333 use_bibtopic = false;
334 trackChanges = false;
335 outputChanges = false;
336 secnumdepth = 3;
337 tocdepth = 3;
338 language = default_language;
339 fontsRoman = "default";
340 fontsSans = "default";
341 fontsTypewriter = "default";
342 fontsDefaultFamily = "default";
343 fontsSC = false;
344 fontsOSF = false;
345 fontsSansScale = 100;
346 fontsTypewriterScale = 100;
347 inputenc = "auto";
348 graphicsDriver = "default";
349 sides = OneSide;
350 columns = 1;
351 listings_params = string();
352 pagestyle = "default";
353 compressed = false;
354 embedded = lyxrc.use_bundled_format;
355 for (int iter = 0; iter < 4; ++iter) {
356 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
357 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
362 docstring BufferParams::B_(string const & l10n) const
364 BOOST_ASSERT(language);
365 return getMessages(language->code()).get(l10n);
369 AuthorList & BufferParams::authors()
371 return pimpl_->authorlist;
375 AuthorList const & BufferParams::authors() const
377 return pimpl_->authorlist;
381 vector<string> & BufferParams::extraEmbeddedFiles()
383 return pimpl_->extraEmbeddedFiles;
387 vector<string> const & BufferParams::extraEmbeddedFiles() const
389 return pimpl_->extraEmbeddedFiles;
393 BranchList & BufferParams::branchlist()
395 return pimpl_->branchlist;
399 BranchList const & BufferParams::branchlist() const
401 return pimpl_->branchlist;
405 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
407 BOOST_ASSERT(index < 4);
408 return pimpl_->temp_bullets[index];
412 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
414 BOOST_ASSERT(index < 4);
415 return pimpl_->temp_bullets[index];
419 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
421 BOOST_ASSERT(index < 4);
422 return pimpl_->user_defined_bullets[index];
426 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
428 BOOST_ASSERT(index < 4);
429 return pimpl_->user_defined_bullets[index];
433 Spacing & BufferParams::spacing()
435 return pimpl_->spacing;
439 Spacing const & BufferParams::spacing() const
441 return pimpl_->spacing;
445 PDFOptions & BufferParams::pdfoptions()
447 return pimpl_->pdfoptions;
451 PDFOptions const & BufferParams::pdfoptions() const
453 return pimpl_->pdfoptions;
457 VSpace const & BufferParams::getDefSkip() const
459 return pimpl_->defskip;
463 void BufferParams::setDefSkip(VSpace const & vs)
465 pimpl_->defskip = vs;
469 string BufferParams::readToken(Lexer & lex, string const & token,
470 FileName const & filepath, FileName const & temppath)
472 if (token == "\\textclass") {
473 lex.next();
474 string const classname = lex.getString();
475 // if there exists a local layout file, ignore the system one
476 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
477 string tcp;
478 LayoutFileList & bcl = LayoutFileList::get();
479 if (!temppath.empty())
480 tcp = bcl.addLayoutFile(classname, temppath.absFilename(), LayoutFileList::Embedded);
481 if (tcp.empty() && !filepath.empty())
482 tcp = bcl.addLayoutFile(classname, filepath.absFilename(), LayoutFileList::Local);
483 if (!tcp.empty())
484 setBaseClass(tcp);
485 else if (bcl.haveClass(classname)) {
486 setBaseClass(classname);
487 } else {
488 // a warning will be given for unknown class
489 setBaseClass(defaultBaseclass());
490 return classname;
492 // FIXME: this warning will be given even if there exists a local .cls
493 // file. Even worse, the .lyx file can not be compiled or exported
494 // because the textclass is marked as unavilable.
495 if (!baseClass()->isTeXClassAvailable()) {
496 docstring const msg =
497 bformat(_("The layout file requested by this document,\n"
498 "%1$s.layout,\n"
499 "is not usable. This is probably because a LaTeX\n"
500 "class or style file required by it is not\n"
501 "available. See the Customization documentation\n"
502 "for more information.\n"), from_utf8(classname));
503 frontend::Alert::warning(_("Document class not available"),
504 msg + _("LyX will not be able to produce output."));
507 } else if (token == "\\begin_preamble") {
508 readPreamble(lex);
509 } else if (token == "\\begin_modules") {
510 readModules(lex);
511 } else if (token == "\\options") {
512 lex.eatLine();
513 options = lex.getString();
514 } else if (token == "\\language") {
515 readLanguage(lex);
516 } else if (token == "\\inputencoding") {
517 lex >> inputenc;
518 } else if (token == "\\graphics") {
519 readGraphicsDriver(lex);
520 } else if (token == "\\font_roman") {
521 lex >> fontsRoman;
522 } else if (token == "\\font_sans") {
523 lex >> fontsSans;
524 } else if (token == "\\font_typewriter") {
525 lex >> fontsTypewriter;
526 } else if (token == "\\font_default_family") {
527 lex >> fontsDefaultFamily;
528 } else if (token == "\\font_sc") {
529 lex >> fontsSC;
530 } else if (token == "\\font_osf") {
531 lex >> fontsOSF;
532 } else if (token == "\\font_sf_scale") {
533 lex >> fontsSansScale;
534 } else if (token == "\\font_tt_scale") {
535 lex >> fontsTypewriterScale;
536 } else if (token == "\\paragraph_separation") {
537 string parsep;
538 lex >> parsep;
539 paragraph_separation = parseptranslator().find(parsep);
540 } else if (token == "\\defskip") {
541 lex.next();
542 string defskip = lex.getString();
543 if (defskip == "defskip")
544 // this is invalid
545 defskip = "medskip";
546 pimpl_->defskip = VSpace(defskip);
547 } else if (token == "\\quotes_language") {
548 string quotes_lang;
549 lex >> quotes_lang;
550 quotes_language = quoteslangtranslator().find(quotes_lang);
551 } else if (token == "\\papersize") {
552 string ppsize;
553 lex >> ppsize;
554 papersize = papersizetranslator().find(ppsize);
555 } else if (token == "\\use_geometry") {
556 lex >> use_geometry;
557 } else if (token == "\\use_amsmath") {
558 int use_ams;
559 lex >> use_ams;
560 use_amsmath = packagetranslator().find(use_ams);
561 } else if (token == "\\use_esint") {
562 int useesint;
563 lex >> useesint;
564 use_esint = packagetranslator().find(useesint);
565 } else if (token == "\\cite_engine") {
566 string engine;
567 lex >> engine;
568 cite_engine_ = citeenginetranslator().find(engine);
569 } else if (token == "\\use_bibtopic") {
570 lex >> use_bibtopic;
571 } else if (token == "\\tracking_changes") {
572 lex >> trackChanges;
573 } else if (token == "\\output_changes") {
574 lex >> outputChanges;
575 } else if (token == "\\branch") {
576 lex.next();
577 docstring branch = lex.getDocString();
578 branchlist().add(branch);
579 while (true) {
580 lex.next();
581 string const tok = lex.getString();
582 if (tok == "\\end_branch")
583 break;
584 Branch * branch_ptr = branchlist().find(branch);
585 if (tok == "\\selected") {
586 lex.next();
587 if (branch_ptr)
588 branch_ptr->setSelected(lex.getInteger());
590 // not yet operational
591 if (tok == "\\color") {
592 lex.eatLine();
593 string color = lex.getString();
594 if (branch_ptr)
595 branch_ptr->setColor(color);
596 // Update also the Color table:
597 if (color == "none")
598 color = lcolor.getX11Name(Color_background);
599 // FIXME UNICODE
600 lcolor.setColor(to_utf8(branch), color);
604 } else if (token == "\\author") {
605 lex.eatLine();
606 istringstream ss(lex.getString());
607 Author a;
608 ss >> a;
609 author_map.push_back(pimpl_->authorlist.record(a));
610 } else if (token == "\\paperorientation") {
611 string orient;
612 lex >> orient;
613 orientation = paperorientationtranslator().find(orient);
614 } else if (token == "\\paperwidth") {
615 lex >> paperwidth;
616 } else if (token == "\\paperheight") {
617 lex >> paperheight;
618 } else if (token == "\\leftmargin") {
619 lex >> leftmargin;
620 } else if (token == "\\topmargin") {
621 lex >> topmargin;
622 } else if (token == "\\rightmargin") {
623 lex >> rightmargin;
624 } else if (token == "\\bottommargin") {
625 lex >> bottommargin;
626 } else if (token == "\\headheight") {
627 lex >> headheight;
628 } else if (token == "\\headsep") {
629 lex >> headsep;
630 } else if (token == "\\footskip") {
631 lex >> footskip;
632 } else if (token == "\\columnsep") {
633 lex >> columnsep;
634 } else if (token == "\\paperfontsize") {
635 lex >> fontsize;
636 } else if (token == "\\papercolumns") {
637 lex >> columns;
638 } else if (token == "\\listings_params") {
639 string par;
640 lex >> par;
641 listings_params = InsetListingsParams(par).params();
642 } else if (token == "\\papersides") {
643 int psides;
644 lex >> psides;
645 sides = sidestranslator().find(psides);
646 } else if (token == "\\paperpagestyle") {
647 lex >> pagestyle;
648 } else if (token == "\\bullet") {
649 readBullets(lex);
650 } else if (token == "\\bulletLaTeX") {
651 readBulletsLaTeX(lex);
652 } else if (token == "\\secnumdepth") {
653 lex >> secnumdepth;
654 } else if (token == "\\tocdepth") {
655 lex >> tocdepth;
656 } else if (token == "\\spacing") {
657 string nspacing;
658 lex >> nspacing;
659 string tmp_val;
660 if (nspacing == "other") {
661 lex >> tmp_val;
663 spacing().set(spacetranslator().find(nspacing), tmp_val);
664 } else if (token == "\\float_placement") {
665 lex >> float_placement;
667 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
668 string toktmp = pdfoptions().readToken(lex, token);
669 if (!toktmp.empty()) {
670 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
671 toktmp << endl;
672 return toktmp;
674 } else if (token == "\\extra_embedded_files") {
675 extraEmbeddedFiles().clear();
676 string par;
677 lex >> par;
678 string tmp;
679 par = split(par, tmp, ',');
680 while (!tmp.empty()) {
681 extraEmbeddedFiles().push_back(tmp);
682 par = split(par, tmp, ',');
684 } else {
685 lyxerr << "BufferParams::readToken(): Unknown token: " <<
686 token << endl;
687 return token;
690 return string();
694 void BufferParams::writeFile(ostream & os) const
696 // The top of the file is written by the buffer.
697 // Prints out the buffer info into the .lyx file given by file
699 // the textclass
700 os << "\\textclass " << baseClass()->name() << '\n';
702 // then the preamble
703 if (!preamble.empty()) {
704 // remove '\n' from the end of preamble
705 string const tmppreamble = rtrim(preamble, "\n");
706 os << "\\begin_preamble\n"
707 << tmppreamble
708 << "\n\\end_preamble\n";
711 // the options
712 if (!options.empty()) {
713 os << "\\options " << options << '\n';
716 //the modules
717 if (!layoutModules_.empty()) {
718 os << "\\begin_modules" << '\n';
719 LayoutModuleList::const_iterator it = layoutModules_.begin();
720 for (; it != layoutModules_.end(); it++)
721 os << *it << '\n';
722 os << "\\end_modules" << '\n';
725 // then the text parameters
726 if (language != ignore_language)
727 os << "\\language " << language->lang() << '\n';
728 os << "\\inputencoding " << inputenc
729 << "\n\\font_roman " << fontsRoman
730 << "\n\\font_sans " << fontsSans
731 << "\n\\font_typewriter " << fontsTypewriter
732 << "\n\\font_default_family " << fontsDefaultFamily
733 << "\n\\font_sc " << convert<string>(fontsSC)
734 << "\n\\font_osf " << convert<string>(fontsOSF)
735 << "\n\\font_sf_scale " << fontsSansScale
736 << "\n\\font_tt_scale " << fontsTypewriterScale
737 << "\n\\graphics " << graphicsDriver << '\n';
739 if (!float_placement.empty()) {
740 os << "\\float_placement " << float_placement << '\n';
742 os << "\\paperfontsize " << fontsize << '\n';
744 spacing().writeFile(os);
745 pdfoptions().writeFile(os);
747 os << "\\papersize " << string_papersize[papersize]
748 << "\n\\use_geometry " << convert<string>(use_geometry)
749 << "\n\\use_amsmath " << use_amsmath
750 << "\n\\use_esint " << use_esint
751 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
752 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
753 << "\n\\paperorientation " << string_orientation[orientation]
754 << '\n';
756 BranchList::const_iterator it = branchlist().begin();
757 BranchList::const_iterator end = branchlist().end();
758 for (; it != end; ++it) {
759 os << "\\branch " << to_utf8(it->getBranch())
760 << "\n\\selected " << it->getSelected()
761 << "\n\\color " << lyx::X11hexname(it->getColor())
762 << "\n\\end_branch"
763 << "\n";
766 if (!paperwidth.empty())
767 os << "\\paperwidth "
768 << VSpace(paperwidth).asLyXCommand() << '\n';
769 if (!paperheight.empty())
770 os << "\\paperheight "
771 << VSpace(paperheight).asLyXCommand() << '\n';
772 if (!leftmargin.empty())
773 os << "\\leftmargin "
774 << VSpace(leftmargin).asLyXCommand() << '\n';
775 if (!topmargin.empty())
776 os << "\\topmargin "
777 << VSpace(topmargin).asLyXCommand() << '\n';
778 if (!rightmargin.empty())
779 os << "\\rightmargin "
780 << VSpace(rightmargin).asLyXCommand() << '\n';
781 if (!bottommargin.empty())
782 os << "\\bottommargin "
783 << VSpace(bottommargin).asLyXCommand() << '\n';
784 if (!headheight.empty())
785 os << "\\headheight "
786 << VSpace(headheight).asLyXCommand() << '\n';
787 if (!headsep.empty())
788 os << "\\headsep "
789 << VSpace(headsep).asLyXCommand() << '\n';
790 if (!footskip.empty())
791 os << "\\footskip "
792 << VSpace(footskip).asLyXCommand() << '\n';
793 if (!columnsep.empty())
794 os << "\\columnsep "
795 << VSpace(columnsep).asLyXCommand() << '\n';
796 os << "\\secnumdepth " << secnumdepth
797 << "\n\\tocdepth " << tocdepth
798 << "\n\\paragraph_separation "
799 << string_paragraph_separation[paragraph_separation]
800 << "\n\\defskip " << getDefSkip().asLyXCommand()
801 << "\n\\quotes_language "
802 << string_quotes_language[quotes_language]
803 << "\n\\papercolumns " << columns
804 << "\n\\papersides " << sides
805 << "\n\\paperpagestyle " << pagestyle << '\n';
806 if (!listings_params.empty())
807 os << "\\listings_params \"" <<
808 InsetListingsParams(listings_params).encodedString() << "\"\n";
809 for (int i = 0; i < 4; ++i) {
810 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
811 if (user_defined_bullet(i).getFont() != -1) {
812 os << "\\bullet " << i << " "
813 << user_defined_bullet(i).getFont() << " "
814 << user_defined_bullet(i).getCharacter() << " "
815 << user_defined_bullet(i).getSize() << "\n";
817 else {
818 // FIXME UNICODE
819 os << "\\bulletLaTeX " << i << " \""
820 << lyx::to_ascii(user_defined_bullet(i).getText())
821 << "\"\n";
826 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
827 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
829 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
830 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
831 for (; a_it != a_end; ++a_it) {
832 if (a_it->second.used())
833 os << "\\author " << a_it->second << "\n";
834 else
835 os << "\\author " << Author() << "\n";
838 vector<string>::const_iterator e_it = extraEmbeddedFiles().begin();
839 vector<string>::const_iterator e_end = extraEmbeddedFiles().end();
840 os << "\\extra_embedded_files \"";
841 bool first = true;
842 for (; e_it != e_end; ++e_it) {
843 if (!first)
844 os << ",";
845 else
846 first = false;
847 os << *e_it;
849 os << "\"\n";
853 void BufferParams::validate(LaTeXFeatures & features) const
855 features.require(documentClass().requires());
857 if (outputChanges) {
858 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
859 bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
860 LaTeXFeatures::isAvailable("xcolor");
862 switch (features.runparams().flavor) {
863 case OutputParams::LATEX:
864 if (dvipost) {
865 features.require("ct-dvipost");
866 features.require("dvipost");
867 } else if (xcolorsoul) {
868 features.require("ct-xcolor-soul");
869 features.require("soul");
870 features.require("xcolor");
871 } else {
872 features.require("ct-none");
874 break;
875 case OutputParams::PDFLATEX:
876 if (xcolorsoul) {
877 features.require("ct-xcolor-soul");
878 features.require("soul");
879 features.require("xcolor");
880 // improves color handling in PDF output
881 features.require("pdfcolmk");
882 } else {
883 features.require("ct-none");
885 break;
886 default:
887 break;
891 // Floats with 'Here definitely' as default setting.
892 if (float_placement.find('H') != string::npos)
893 features.require("float");
895 // AMS Style is at document level
896 if (use_amsmath == package_on
897 || documentClass().provides("amsmath"))
898 features.require("amsmath");
899 if (use_esint == package_on)
900 features.require("esint");
902 // Document-level line spacing
903 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
904 features.require("setspace");
906 // the bullet shapes are buffer level not paragraph level
907 // so they are tested here
908 for (int i = 0; i < 4; ++i) {
909 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
910 continue;
911 int const font = user_defined_bullet(i).getFont();
912 if (font == 0) {
913 int const c = user_defined_bullet(i).getCharacter();
914 if (c == 16
915 || c == 17
916 || c == 25
917 || c == 26
918 || c == 31) {
919 features.require("latexsym");
921 } else if (font == 1) {
922 features.require("amssymb");
923 } else if (font >= 2 && font <= 5) {
924 features.require("pifont");
928 if (pdfoptions().use_hyperref)
929 features.require("hyperref");
933 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
934 TexRow & texrow) const
936 os << "\\documentclass";
938 DocumentClass const & tclass = documentClass();
940 ostringstream clsoptions; // the document class options.
942 if (tokenPos(tclass.opt_fontsize(),
943 '|', fontsize) >= 0) {
944 // only write if existing in list (and not default)
945 clsoptions << fontsize << "pt,";
948 // custom, A3, B3 and B4 paper sizes need geometry
949 bool nonstandard_papersize = papersize == PAPER_B3
950 || papersize == PAPER_B4
951 || papersize == PAPER_A3
952 || papersize == PAPER_CUSTOM;
954 if (!use_geometry) {
955 switch (papersize) {
956 case PAPER_A4:
957 clsoptions << "a4paper,";
958 break;
959 case PAPER_USLETTER:
960 clsoptions << "letterpaper,";
961 break;
962 case PAPER_A5:
963 clsoptions << "a5paper,";
964 break;
965 case PAPER_B5:
966 clsoptions << "b5paper,";
967 break;
968 case PAPER_USEXECUTIVE:
969 clsoptions << "executivepaper,";
970 break;
971 case PAPER_USLEGAL:
972 clsoptions << "legalpaper,";
973 break;
974 case PAPER_DEFAULT:
975 case PAPER_A3:
976 case PAPER_B3:
977 case PAPER_B4:
978 case PAPER_CUSTOM:
979 break;
983 // if needed
984 if (sides != tclass.sides()) {
985 switch (sides) {
986 case OneSide:
987 clsoptions << "oneside,";
988 break;
989 case TwoSides:
990 clsoptions << "twoside,";
991 break;
995 // if needed
996 if (columns != tclass.columns()) {
997 if (columns == 2)
998 clsoptions << "twocolumn,";
999 else
1000 clsoptions << "onecolumn,";
1003 if (!use_geometry
1004 && orientation == ORIENTATION_LANDSCAPE)
1005 clsoptions << "landscape,";
1007 // language should be a parameter to \documentclass
1008 if (language->babel() == "hebrew"
1009 && default_language->babel() != "hebrew")
1010 // This seems necessary
1011 features.useLanguage(default_language);
1013 ostringstream language_options;
1014 bool const use_babel = features.useBabel();
1015 if (use_babel) {
1016 language_options << features.getLanguages();
1017 if (!language->babel().empty()) {
1018 if (!language_options.str().empty())
1019 language_options << ',';
1020 language_options << language->babel();
1022 // when Vietnamese is used, babel must directly be loaded with the
1023 // language options, not in the class options, see
1024 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1025 size_t viet = language_options.str().find("vietnam");
1026 // viet = string::npos when not found
1027 if (lyxrc.language_global_options && !language_options.str().empty()
1028 && viet == string::npos)
1029 clsoptions << language_options.str() << ',';
1032 // the user-defined options
1033 if (!options.empty()) {
1034 clsoptions << options << ',';
1037 string strOptions(clsoptions.str());
1038 if (!strOptions.empty()) {
1039 strOptions = rtrim(strOptions, ",");
1040 // FIXME UNICODE
1041 os << '[' << from_utf8(strOptions) << ']';
1044 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1045 texrow.newline();
1046 // end of \documentclass defs
1048 // font selection must be done before loading fontenc.sty
1049 string const fonts =
1050 loadFonts(fontsRoman, fontsSans,
1051 fontsTypewriter, fontsSC, fontsOSF,
1052 fontsSansScale, fontsTypewriterScale);
1053 if (!fonts.empty()) {
1054 os << from_ascii(fonts);
1055 texrow.newline();
1057 if (fontsDefaultFamily != "default")
1058 os << "\\renewcommand{\\familydefault}{\\"
1059 << from_ascii(fontsDefaultFamily) << "}\n";
1061 // set font encoding
1062 // this one is not per buffer
1063 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
1064 if (lyxrc.fontenc != "default") {
1065 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
1066 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1067 << ",LFE,LAE]{fontenc}\n";
1068 texrow.newline();
1069 } else {
1070 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1071 << "]{fontenc}\n";
1072 texrow.newline();
1076 // handle inputenc etc.
1077 writeEncodingPreamble(os, features, texrow);
1079 if (!listings_params.empty()) {
1080 os << "\\usepackage{listings}\n";
1081 texrow.newline();
1082 os << "\\lstset{";
1083 // do not test validity because listings_params is supposed to be valid
1084 string par = InsetListingsParams(listings_params).separatedParams(true);
1085 os << from_ascii(par);
1086 // count the number of newlines
1087 for (size_t i = 0; i < par.size(); ++i)
1088 if (par[i] == '\n')
1089 texrow.newline();
1090 os << "}\n";
1091 texrow.newline();
1093 if (use_geometry || nonstandard_papersize) {
1094 os << "\\usepackage{geometry}\n";
1095 texrow.newline();
1096 os << "\\geometry{verbose";
1097 if (orientation == ORIENTATION_LANDSCAPE)
1098 os << ",landscape";
1099 switch (papersize) {
1100 case PAPER_CUSTOM:
1101 if (!paperwidth.empty())
1102 os << ",paperwidth="
1103 << from_ascii(paperwidth);
1104 if (!paperheight.empty())
1105 os << ",paperheight="
1106 << from_ascii(paperheight);
1107 break;
1108 case PAPER_USLETTER:
1109 os << ",letterpaper";
1110 break;
1111 case PAPER_USLEGAL:
1112 os << ",legalpaper";
1113 break;
1114 case PAPER_USEXECUTIVE:
1115 os << ",executivepaper";
1116 break;
1117 case PAPER_A3:
1118 os << ",a3paper";
1119 break;
1120 case PAPER_A4:
1121 os << ",a4paper";
1122 break;
1123 case PAPER_A5:
1124 os << ",a5paper";
1125 break;
1126 case PAPER_B3:
1127 os << ",b3paper";
1128 break;
1129 case PAPER_B4:
1130 os << ",b4paper";
1131 break;
1132 case PAPER_B5:
1133 os << ",b5paper";
1134 break;
1135 default:
1136 // default papersize ie PAPER_DEFAULT
1137 switch (lyxrc.default_papersize) {
1138 case PAPER_DEFAULT: // keep compiler happy
1139 case PAPER_USLETTER:
1140 os << ",letterpaper";
1141 break;
1142 case PAPER_USLEGAL:
1143 os << ",legalpaper";
1144 break;
1145 case PAPER_USEXECUTIVE:
1146 os << ",executivepaper";
1147 break;
1148 case PAPER_A3:
1149 os << ",a3paper";
1150 break;
1151 case PAPER_A4:
1152 os << ",a4paper";
1153 break;
1154 case PAPER_A5:
1155 os << ",a5paper";
1156 break;
1157 case PAPER_B5:
1158 os << ",b5paper";
1159 break;
1160 case PAPER_B3:
1161 case PAPER_B4:
1162 case PAPER_CUSTOM:
1163 break;
1166 if (!topmargin.empty())
1167 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1168 if (!bottommargin.empty())
1169 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1170 if (!leftmargin.empty())
1171 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1172 if (!rightmargin.empty())
1173 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1174 if (!headheight.empty())
1175 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1176 if (!headsep.empty())
1177 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1178 if (!footskip.empty())
1179 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1180 if (!columnsep.empty())
1181 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1182 os << "}\n";
1183 texrow.newline();
1186 if (tokenPos(tclass.opt_pagestyle(),
1187 '|', pagestyle) >= 0) {
1188 if (pagestyle == "fancy") {
1189 os << "\\usepackage{fancyhdr}\n";
1190 texrow.newline();
1192 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1193 texrow.newline();
1196 // Only if class has a ToC hierarchy
1197 if (tclass.hasTocLevels()) {
1198 if (secnumdepth != tclass.secnumdepth()) {
1199 os << "\\setcounter{secnumdepth}{"
1200 << secnumdepth
1201 << "}\n";
1202 texrow.newline();
1204 if (tocdepth != tclass.tocdepth()) {
1205 os << "\\setcounter{tocdepth}{"
1206 << tocdepth
1207 << "}\n";
1208 texrow.newline();
1212 if (paragraph_separation) {
1213 switch (getDefSkip().kind()) {
1214 case VSpace::SMALLSKIP:
1215 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1216 break;
1217 case VSpace::MEDSKIP:
1218 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1219 break;
1220 case VSpace::BIGSKIP:
1221 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1222 break;
1223 case VSpace::LENGTH:
1224 os << "\\setlength{\\parskip}{"
1225 << from_utf8(getDefSkip().length().asLatexString())
1226 << "}\n";
1227 break;
1228 default: // should never happen // Then delete it.
1229 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1230 break;
1232 texrow.newline();
1234 os << "\\setlength{\\parindent}{0pt}\n";
1235 texrow.newline();
1238 // If we use jurabib, we have to call babel here.
1239 if (use_babel && features.isRequired("jurabib")) {
1240 os << from_ascii(babelCall(language_options.str()))
1241 << '\n'
1242 << from_ascii(features.getBabelOptions());
1243 texrow.newline();
1246 // Now insert the LyX specific LaTeX commands...
1248 // The optional packages;
1249 docstring lyxpreamble(from_ascii(features.getPackages()));
1251 // Line spacing
1252 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1254 // We try to load babel late, in case it interferes
1255 // with other packages. But some packages also need babel to be loaded
1256 // before, e.g. jurabib has to be called after babel.
1257 // So load babel after the optional packages but before the user-defined
1258 // preamble. This allows the users to redefine babel commands, e.g. to
1259 // translate the word "Index" to the German "Stichwortverzeichnis".
1260 // For more infos why this place was chosen, see
1261 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1262 // If you encounter problems, you can shift babel to its old place behind
1263 // the user-defined preamble. But in this case you must change the Vietnamese
1264 // support from currently "\usepackage[vietnamese]{babel}" to:
1265 // \usepackage{vietnamese}
1266 // \usepackage{babel}
1267 // because vietnamese must be loaded before hyperref
1268 if (use_babel && !features.isRequired("jurabib")) {
1269 // FIXME UNICODE
1270 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1271 lyxpreamble += from_utf8(features.getBabelOptions());
1274 // When the language "japanese-plain" is used, the package "japanese" must
1275 // be loaded behind babel (it provides babel support for Japanese) but before
1276 // hyperref, see
1277 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1278 if (language->lang() == "japanese-plain" &&
1279 !documentClass().provides("japanese")) {
1280 //load babel in case it was not loaded due to an empty language list
1281 if (language_options.str().empty())
1282 lyxpreamble += "\\usepackage{babel}\n";
1283 lyxpreamble += "\\usepackage{japanese}\n";
1286 // PDF support.
1287 // * Hyperref manual: "Make sure it comes last of your loaded
1288 // packages, to give it a fighting chance of not being over-written,
1289 // since its job is to redefine many LATEX commands."
1290 // * Email from Heiko Oberdiek: "It is usually better to load babel
1291 // before hyperref. Then hyperref has a chance to detect babel.
1292 // * Has to be loaded before the "LyX specific LaTeX commands" to
1293 // avoid errors with algorithm floats.
1294 // use hyperref explicitely when it is required
1295 if (features.isRequired("hyperref")) {
1296 odocstringstream oss;
1297 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1298 lyxpreamble += oss.str();
1301 // this might be useful...
1302 lyxpreamble += "\n\\makeatletter\n";
1304 // Some macros LyX will need
1305 docstring tmppreamble(from_ascii(features.getMacros()));
1307 if (!tmppreamble.empty()) {
1308 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1309 "LyX specific LaTeX commands.\n"
1310 + tmppreamble + '\n';
1313 // the text class specific preamble
1314 tmppreamble = features.getTClassPreamble();
1315 if (!tmppreamble.empty()) {
1316 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1317 "Textclass specific LaTeX commands.\n"
1318 + tmppreamble + '\n';
1321 /* the user-defined preamble */
1322 if (!preamble.empty()) {
1323 // FIXME UNICODE
1324 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1325 "User specified LaTeX commands.\n"
1326 + from_utf8(preamble) + '\n';
1329 // Itemize bullet settings need to be last in case the user
1330 // defines their own bullets that use a package included
1331 // in the user-defined preamble -- ARRae
1332 // Actually it has to be done much later than that
1333 // since some packages like frenchb make modifications
1334 // at \begin{document} time -- JMarc
1335 docstring bullets_def;
1336 for (int i = 0; i < 4; ++i) {
1337 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1338 if (bullets_def.empty())
1339 bullets_def += "\\AtBeginDocument{\n";
1340 bullets_def += " \\def\\labelitemi";
1341 switch (i) {
1342 // `i' is one less than the item to modify
1343 case 0:
1344 break;
1345 case 1:
1346 bullets_def += 'i';
1347 break;
1348 case 2:
1349 bullets_def += "ii";
1350 break;
1351 case 3:
1352 bullets_def += 'v';
1353 break;
1355 bullets_def += '{' +
1356 user_defined_bullet(i).getText()
1357 + "}\n";
1361 if (!bullets_def.empty())
1362 lyxpreamble += bullets_def + "}\n\n";
1364 lyxpreamble += "\\makeatother\n\n";
1366 int const nlines =
1367 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1368 for (int j = 0; j != nlines; ++j) {
1369 texrow.newline();
1372 os << lyxpreamble;
1373 return use_babel;
1377 void BufferParams::useClassDefaults()
1379 DocumentClass const & tclass = documentClass();
1381 sides = tclass.sides();
1382 columns = tclass.columns();
1383 pagestyle = tclass.pagestyle();
1384 options = tclass.options();
1385 // Only if class has a ToC hierarchy
1386 if (tclass.hasTocLevels()) {
1387 secnumdepth = tclass.secnumdepth();
1388 tocdepth = tclass.tocdepth();
1393 bool BufferParams::hasClassDefaults() const
1395 DocumentClass const & tclass = documentClass();
1397 return sides == tclass.sides()
1398 && columns == tclass.columns()
1399 && pagestyle == tclass.pagestyle()
1400 && options == tclass.options()
1401 && secnumdepth == tclass.secnumdepth()
1402 && tocdepth == tclass.tocdepth();
1406 DocumentClass const & BufferParams::documentClass() const
1408 return *doc_class_;
1412 DocumentClass * BufferParams::documentClassPtr() const {
1413 return doc_class_;
1417 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1418 // evil, but this function is evil
1419 doc_class_ = const_cast<DocumentClass *>(tc);
1423 bool BufferParams::setBaseClass(string const & classname)
1425 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1426 LayoutFileList const & bcl = LayoutFileList::get();
1427 if (!bcl.haveClass(classname)) {
1428 docstring s =
1429 bformat(_("The document class %1$s could not be found."),
1430 from_utf8(classname));
1431 frontend::Alert::error(_("Class not found"), s);
1432 return false;
1435 if (bcl[classname].load()) {
1436 pimpl_->baseClass_ = classname;
1437 return true;
1440 docstring s =
1441 bformat(_("The document class %1$s could not be loaded."),
1442 from_utf8(classname));
1443 frontend::Alert::error(_("Could not load class"), s);
1444 return false;
1448 LayoutFile const * BufferParams::baseClass() const
1450 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1451 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1452 else
1453 return 0;
1457 LayoutFileIndex const & BufferParams::baseClassID() const
1459 return pimpl_->baseClass_;
1463 void BufferParams::makeDocumentClass()
1465 if (!baseClass())
1466 return;
1468 doc_class_ = &(DocumentClassBundle::get().newClass(*baseClass()));
1470 //FIXME It might be worth loading the children's modules here,
1471 //just as we load their bibliographies and such, instead of just
1472 //doing a check in InsetInclude.
1473 LayoutModuleList::const_iterator it = layoutModules_.begin();
1474 for (; it != layoutModules_.end(); it++) {
1475 string const modName = *it;
1476 LyXModule * lm = moduleList[modName];
1477 if (!lm) {
1478 docstring const msg =
1479 bformat(_("The module %1$s has been requested by\n"
1480 "this document but has not been found in the list of\n"
1481 "available modules. If you recently installed it, you\n"
1482 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1483 frontend::Alert::warning(_("Module not available"),
1484 msg + _("Some layouts may not be available."));
1485 lyxerr << "BufferParams::makeDocumentClass(): Module " <<
1486 modName << " requested but not found in module list." <<
1487 endl;
1488 continue;
1490 if (!lm->isAvailable()) {
1491 docstring const msg =
1492 bformat(_("The module %1$s requires a package that is\n"
1493 "not available in your LaTeX installation. LaTeX output\n"
1494 "may not be possible.\n"), from_utf8(modName));
1495 frontend::Alert::warning(_("Package not available"), msg);
1497 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1498 if (!doc_class_->read(layout_file, TextClass::MODULE)) {
1499 docstring const msg =
1500 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1501 frontend::Alert::warning(_("Read Error"), msg);
1507 vector<string> const & BufferParams::getModules() const
1509 return layoutModules_;
1514 bool BufferParams::addLayoutModule(string const & modName)
1516 LayoutModuleList::const_iterator it = layoutModules_.begin();
1517 LayoutModuleList::const_iterator end = layoutModules_.end();
1518 for (; it != end; it++) {
1519 if (*it == modName)
1520 break;
1522 if (it != layoutModules_.end())
1523 return false;
1524 layoutModules_.push_back(modName);
1525 return true;
1529 void BufferParams::clearLayoutModules()
1531 layoutModules_.clear();
1535 Font const BufferParams::getFont() const
1537 FontInfo f = documentClass().defaultfont();
1538 if (fontsDefaultFamily == "rmdefault")
1539 f.setFamily(ROMAN_FAMILY);
1540 else if (fontsDefaultFamily == "sfdefault")
1541 f.setFamily(SANS_FAMILY);
1542 else if (fontsDefaultFamily == "ttdefault")
1543 f.setFamily(TYPEWRITER_FAMILY);
1544 return Font(f, language);
1548 void BufferParams::readPreamble(Lexer & lex)
1550 if (lex.getString() != "\\begin_preamble")
1551 lyxerr << "Error (BufferParams::readPreamble):"
1552 "consistency check failed." << endl;
1554 preamble = lex.getLongString("\\end_preamble");
1558 void BufferParams::readLanguage(Lexer & lex)
1560 if (!lex.next()) return;
1562 string const tmptok = lex.getString();
1564 // check if tmptok is part of tex_babel in tex-defs.h
1565 language = languages.getLanguage(tmptok);
1566 if (!language) {
1567 // Language tmptok was not found
1568 language = default_language;
1569 lyxerr << "Warning: Setting language `"
1570 << tmptok << "' to `" << language->lang()
1571 << "'." << endl;
1576 void BufferParams::readGraphicsDriver(Lexer & lex)
1578 if (!lex.next())
1579 return;
1581 string const tmptok = lex.getString();
1582 // check if tmptok is part of tex_graphics in tex_defs.h
1583 int n = 0;
1584 while (true) {
1585 string const test = tex_graphics[n++];
1587 if (test == tmptok) {
1588 graphicsDriver = tmptok;
1589 break;
1590 } else if (test == "") {
1591 lex.printError(
1592 "Warning: graphics driver `$$Token' not recognized!\n"
1593 " Setting graphics driver to `default'.\n");
1594 graphicsDriver = "default";
1595 break;
1601 void BufferParams::readBullets(Lexer & lex)
1603 if (!lex.next())
1604 return;
1606 int const index = lex.getInteger();
1607 lex.next();
1608 int temp_int = lex.getInteger();
1609 user_defined_bullet(index).setFont(temp_int);
1610 temp_bullet(index).setFont(temp_int);
1611 lex >> temp_int;
1612 user_defined_bullet(index).setCharacter(temp_int);
1613 temp_bullet(index).setCharacter(temp_int);
1614 lex >> temp_int;
1615 user_defined_bullet(index).setSize(temp_int);
1616 temp_bullet(index).setSize(temp_int);
1620 void BufferParams::readBulletsLaTeX(Lexer & lex)
1622 // The bullet class should be able to read this.
1623 if (!lex.next())
1624 return;
1625 int const index = lex.getInteger();
1626 lex.next(true);
1627 docstring const temp_str = lex.getDocString();
1629 user_defined_bullet(index).setText(temp_str);
1630 temp_bullet(index).setText(temp_str);
1634 void BufferParams::readModules(Lexer & lex)
1636 if (!lex.eatLine()) {
1637 lyxerr << "Error (BufferParams::readModules):"
1638 "Unexpected end of input." << endl;
1639 return;
1641 while (true) {
1642 string mod = lex.getString();
1643 if (mod == "\\end_modules")
1644 break;
1645 addLayoutModule(mod);
1646 lex.eatLine();
1651 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1653 char real_papersize = papersize;
1654 if (real_papersize == PAPER_DEFAULT)
1655 real_papersize = lyxrc.default_papersize;
1657 switch (real_papersize) {
1658 case PAPER_DEFAULT:
1659 // could be anything, so don't guess
1660 return string();
1661 case PAPER_CUSTOM: {
1662 if (purpose == XDVI && !paperwidth.empty() &&
1663 !paperheight.empty()) {
1664 // heightxwidth<unit>
1665 string first = paperwidth;
1666 string second = paperheight;
1667 if (orientation == ORIENTATION_LANDSCAPE)
1668 first.swap(second);
1669 // cut off unit.
1670 return first.erase(first.length() - 2)
1671 + "x" + second;
1673 return string();
1675 case PAPER_A3:
1676 return "a3";
1677 case PAPER_A4:
1678 return "a4";
1679 case PAPER_A5:
1680 return "a5";
1681 case PAPER_B3:
1682 // dvips and dvipdfm do not know this
1683 if (purpose == DVIPS || purpose == DVIPDFM)
1684 return string();
1685 return "b3";
1686 case PAPER_B4:
1687 // dvipdfm does not know this
1688 if (purpose == DVIPDFM)
1689 return string();
1690 return "b4";
1691 case PAPER_B5:
1692 // dvipdfm does not know this
1693 if (purpose == DVIPDFM)
1694 return string();
1695 return "b5";
1696 case PAPER_USEXECUTIVE:
1697 // dvipdfm does not know this
1698 if (purpose == DVIPDFM)
1699 return string();
1700 return "foolscap";
1701 case PAPER_USLEGAL:
1702 return "legal";
1703 case PAPER_USLETTER:
1704 default:
1705 if (purpose == XDVI)
1706 return "us";
1707 return "letter";
1712 string const BufferParams::dvips_options() const
1714 string result;
1716 if (use_geometry
1717 && papersize == PAPER_CUSTOM
1718 && !lyxrc.print_paper_dimension_flag.empty()
1719 && !paperwidth.empty()
1720 && !paperheight.empty()) {
1721 // using a custom papersize
1722 result = lyxrc.print_paper_dimension_flag;
1723 result += ' ' + paperwidth;
1724 result += ',' + paperheight;
1725 } else {
1726 string const paper_option = paperSizeName(DVIPS);
1727 if (!paper_option.empty() && (paper_option != "letter" ||
1728 orientation != ORIENTATION_LANDSCAPE)) {
1729 // dvips won't accept -t letter -t landscape.
1730 // In all other cases, include the paper size
1731 // explicitly.
1732 result = lyxrc.print_paper_flag;
1733 result += ' ' + paper_option;
1736 if (orientation == ORIENTATION_LANDSCAPE &&
1737 papersize != PAPER_CUSTOM)
1738 result += ' ' + lyxrc.print_landscape_flag;
1739 return result;
1743 string BufferParams::babelCall(string const & lang_opts) const
1745 string lang_pack = lyxrc.language_package;
1746 if (lang_pack != "\\usepackage{babel}")
1747 return lang_pack;
1748 // suppress the babel call when there is no babel language defined
1749 // for the document language in the lib/languages file and if no
1750 // other languages are used (lang_opts is then empty)
1751 if (lang_opts.empty())
1752 return string();
1753 // when Vietnamese is used, babel must directly be loaded with the
1754 // language options, see
1755 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1756 size_t viet = lang_opts.find("vietnam");
1757 // viet = string::npos when not found
1758 if (!lyxrc.language_global_options || viet != string::npos)
1759 return "\\usepackage[" + lang_opts + "]{babel}";
1760 return lang_pack;
1764 void BufferParams::writeEncodingPreamble(odocstream & os,
1765 LaTeXFeatures & features, TexRow & texrow) const
1767 if (inputenc == "auto") {
1768 string const doc_encoding =
1769 language->encoding()->latexName();
1770 Encoding::Package const package =
1771 language->encoding()->package();
1773 // Create a list with all the input encodings used
1774 // in the document
1775 set<string> encodings =
1776 features.getEncodingSet(doc_encoding);
1778 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1779 // package inputenc must be omitted. Therefore set the encoding to empty.
1780 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1781 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1782 doc_encoding == "SJIS-plain")
1783 encodings.clear();
1785 if (!encodings.empty() || package == Encoding::inputenc) {
1786 os << "\\usepackage[";
1787 set<string>::const_iterator it = encodings.begin();
1788 set<string>::const_iterator const end = encodings.end();
1789 if (it != end) {
1790 os << from_ascii(*it);
1791 ++it;
1793 for (; it != end; ++it)
1794 os << ',' << from_ascii(*it);
1795 if (package == Encoding::inputenc) {
1796 if (!encodings.empty())
1797 os << ',';
1798 os << from_ascii(doc_encoding);
1800 os << "]{inputenc}\n";
1801 texrow.newline();
1803 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1804 os << "\\usepackage{CJK}\n";
1805 texrow.newline();
1807 } else if (inputenc != "default") {
1808 switch (encoding().package()) {
1809 case Encoding::none:
1810 break;
1811 case Encoding::inputenc:
1812 os << "\\usepackage[" << from_ascii(inputenc)
1813 << "]{inputenc}\n";
1814 texrow.newline();
1815 break;
1816 case Encoding::CJK:
1817 os << "\\usepackage{CJK}\n";
1818 texrow.newline();
1819 break;
1823 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1824 // armscii8 is used for Armenian.
1825 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1826 os << "\\usepackage{armtex}\n";
1827 texrow.newline();
1832 string const BufferParams::loadFonts(string const & rm,
1833 string const & sf, string const & tt,
1834 bool const & sc, bool const & osf,
1835 int const & sfscale, int const & ttscale) const
1837 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1838 several packages have been replaced by others, that might not
1839 be installed on every system. We have to take care for that
1840 (see psnfss.pdf). We try to support all psnfss fonts as well
1841 as the fonts that have become de facto standard in the LaTeX
1842 world (e.g. Latin Modern). We do not support obsolete fonts
1843 (like PSLatex). In general, it should be possible to mix any
1844 rm font with any sf or tt font, respectively. (JSpitzm)
1845 TODO:
1846 -- separate math fonts.
1849 if (rm == "default" && sf == "default" && tt == "default")
1850 //nothing to do
1851 return string();
1853 ostringstream os;
1855 // ROMAN FONTS
1856 // Computer Modern (must be explicitely selectable -- there might be classes
1857 // that define a different default font!
1858 if (rm == "cmr") {
1859 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1860 // osf for Computer Modern needs eco.sty
1861 if (osf)
1862 os << "\\usepackage{eco}\n";
1864 // Latin Modern Roman
1865 else if (rm == "lmodern")
1866 os << "\\usepackage{lmodern}\n";
1867 // AE
1868 else if (rm == "ae") {
1869 // not needed when using OT1 font encoding.
1870 if (lyxrc.fontenc != "default")
1871 os << "\\usepackage{ae,aecompl}\n";
1873 // Times
1874 else if (rm == "times") {
1875 // try to load the best available package
1876 if (LaTeXFeatures::isAvailable("mathptmx"))
1877 os << "\\usepackage{mathptmx}\n";
1878 else if (LaTeXFeatures::isAvailable("mathptm"))
1879 os << "\\usepackage{mathptm}\n";
1880 else
1881 os << "\\usepackage{times}\n";
1883 // Palatino
1884 else if (rm == "palatino") {
1885 // try to load the best available package
1886 if (LaTeXFeatures::isAvailable("mathpazo")) {
1887 os << "\\usepackage";
1888 if (osf || sc) {
1889 os << '[';
1890 if (!osf)
1891 os << "sc";
1892 else
1893 // "osf" includes "sc"!
1894 os << "osf";
1895 os << ']';
1897 os << "{mathpazo}\n";
1899 else if (LaTeXFeatures::isAvailable("mathpple"))
1900 os << "\\usepackage{mathpple}\n";
1901 else
1902 os << "\\usepackage{palatino}\n";
1904 // Utopia
1905 else if (rm == "utopia") {
1906 // fourier supersedes utopia.sty, but does
1907 // not work with OT1 encoding.
1908 if (LaTeXFeatures::isAvailable("fourier")
1909 && lyxrc.fontenc != "default") {
1910 os << "\\usepackage";
1911 if (osf || sc) {
1912 os << '[';
1913 if (sc)
1914 os << "expert";
1915 if (osf && sc)
1916 os << ',';
1917 if (osf)
1918 os << "oldstyle";
1919 os << ']';
1921 os << "{fourier}\n";
1923 else
1924 os << "\\usepackage{utopia}\n";
1926 // Bera (complete fontset)
1927 else if (rm == "bera" && sf == "default" && tt == "default")
1928 os << "\\usepackage{bera}\n";
1929 // everything else
1930 else if (rm != "default")
1931 os << "\\usepackage" << "{" << rm << "}\n";
1933 // SANS SERIF
1934 // Helvetica, Bera Sans
1935 if (sf == "helvet" || sf == "berasans") {
1936 if (sfscale != 100)
1937 os << "\\usepackage[scaled=" << float(sfscale) / 100
1938 << "]{" << sf << "}\n";
1939 else
1940 os << "\\usepackage{" << sf << "}\n";
1942 // Avant Garde
1943 else if (sf == "avant")
1944 os << "\\usepackage{" << sf << "}\n";
1945 // Computer Modern, Latin Modern, CM Bright
1946 else if (sf != "default")
1947 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1949 // monospaced/typewriter
1950 // Courier, LuxiMono
1951 if (tt == "luximono" || tt == "beramono") {
1952 if (ttscale != 100)
1953 os << "\\usepackage[scaled=" << float(ttscale) / 100
1954 << "]{" << tt << "}\n";
1955 else
1956 os << "\\usepackage{" << tt << "}\n";
1958 // Courier
1959 else if (tt == "courier" )
1960 os << "\\usepackage{" << tt << "}\n";
1961 // Computer Modern, Latin Modern, CM Bright
1962 else if (tt != "default")
1963 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1965 return os.str();
1969 Encoding const & BufferParams::encoding() const
1971 if (inputenc == "auto" || inputenc == "default")
1972 return *(language->encoding());
1973 Encoding const * const enc =
1974 encodings.getFromLaTeXName(inputenc);
1975 if (enc)
1976 return *enc;
1977 lyxerr << "Unknown inputenc value `" << inputenc
1978 << "'. Using `auto' instead." << endl;
1979 return *(language->encoding());
1983 biblio::CiteEngine BufferParams::citeEngine() const
1985 // FIXME the class should provide the numerical/
1986 // authoryear choice
1987 if (documentClass().provides("natbib")
1988 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1989 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1990 return cite_engine_;
1994 void BufferParams::setCiteEngine(biblio::CiteEngine cite_engine)
1996 cite_engine_ = cite_engine;
1999 } // namespace lyx