1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2001 The LyX Team.
9 * ======================================================
15 #pragma implementation
18 #include "lyxtextclass.h"
23 #include "support/lstrings.h"
24 #include "support/LAssert.h"
25 #include "support/lyxfunctional.h"
26 #include "support/filetools.h"
38 compare_name(string const & name)
41 bool operator()(C & c) {
42 return c->name() == name_;
50 LyXTextClass::LyXTextClass(string const & fn, string const & cln,
52 : name_(fn), latexname_(cln), description_(desc), ctrs_(new Counters)
59 pagestyle_ = "default";
60 maxcounter_ = LABEL_COUNTER_CHAPTER;
61 defaultfont_ = LyXFont(LyXFont::ALL_SANE);
62 opt_fontsize_ = "10|11|12";
63 opt_pagestyle_ = "empty|plain|headings|fancy";
69 bool LyXTextClass::do_readStyle(LyXLex & lexrc, LyXLayout & lay)
71 lyxerr[Debug::TCLASS] << "Reading style " << lay.name() << endl;
72 if (!lay.Read(lexrc, *this)) {
74 lay.resfont = lay.font;
75 #ifndef INHERIT_LANGUAGE
76 lay.resfont.realize(defaultfont());
77 lay.reslabelfont = lay.labelfont;
78 lay.reslabelfont.realize(defaultfont());
80 lay.resfont.realize(defaultfont(), default_language);
81 lay.reslabelfont = lay.labelfont;
82 lay.reslabelfont.realize(defaultfont(), default_language);
84 return false; // no errors
86 lyxerr << "Error parsing style `" << lay.name() << "'" << endl;
117 // Reads a textclass structure from file.
118 bool LyXTextClass::Read(string const & filename, bool merge)
120 keyword_item textClassTags[] = {
121 { "classoptions", TC_CLASSOPTIONS },
122 { "columns", TC_COLUMNS },
123 { "counter", TC_COUNTER },
124 { "defaultfont", TC_DEFAULTFONT },
125 { "defaultstyle", TC_DEFAULTSTYLE },
126 { "float", TC_FLOAT },
127 { "input", TC_INPUT },
128 { "leftmargin", TC_LEFTMARGIN },
129 { "maxcounter", TC_MAXCOUNTER },
130 { "nostyle", TC_NOSTYLE },
131 { "outputtype", TC_OUTPUTTYPE },
132 { "pagestyle", TC_PAGESTYLE },
133 { "preamble", TC_PREAMBLE },
134 { "providesamsmath", TC_PROVIDESAMSMATH },
135 { "providesmakeidx", TC_PROVIDESMAKEIDX },
136 { "providesnatbib", TC_PROVIDESNATBIB },
137 { "providesurl", TC_PROVIDESURL },
138 { "rightmargin", TC_RIGHTMARGIN },
139 { "secnumdepth", TC_SECNUMDEPTH },
140 { "sides", TC_SIDES },
141 { "style", TC_STYLE },
142 { "tocdepth", TC_TOCDEPTH }
146 lyxerr[Debug::TCLASS] << "Reading textclass "
147 << MakeDisplayPath(filename)
150 lyxerr[Debug::TCLASS] << "Reading input file "
151 << MakeDisplayPath(filename)
154 LyXLex lexrc(textClassTags, TC_COUNTER);
157 lexrc.setFile(filename);
158 if (!lexrc.isOK()) error = true;
161 while (lexrc.isOK() && !error) {
162 int le = lexrc.lex();
164 case LyXLex::LEX_FEOF:
167 case LyXLex::LEX_UNDEF:
168 lexrc.printError("Unknown TextClass tag `$$Token'");
173 switch (static_cast<TextClassTags>(le)) {
174 case TC_OUTPUTTYPE: // output type definition
175 readOutputType(lexrc);
178 case TC_INPUT: // Include file
180 string tmp = LibFileSearch("layouts",
184 if (Read(tmp, true)) {
185 lexrc.printError("Error reading input"
192 case TC_DEFAULTSTYLE:
194 string const name = subst(lexrc.getString(),
196 defaultlayout_ = name;
202 string const name = subst(lexrc.getString(),
204 if (hasLayout(name)) {
206 operator[](name).get();
207 error = do_readStyle(lexrc, *lay);
211 if (!(error = do_readStyle(lexrc, lay)))
212 layoutlist_.push_back(boost::shared_ptr<LyXLayout>(new LyXLayout(lay)));
213 if (defaultlayout_.empty()) {
214 // We do not have a default
215 // layout yet, so we choose
216 // the first layout we
218 defaultlayout_ = name;
223 lexrc.printError("No name given for style: `$$Token'.");
230 string const style = subst(lexrc.getString(),
232 if (!delete_layout(style))
233 lyxerr << "Cannot delete style `" << style << "'" << endl;
234 // lexrc.printError("Cannot delete style"
241 columns_ = lexrc.getInteger();
246 switch (lexrc.getInteger()) {
247 case 1: sides_ = OneSide; break;
248 case 2: sides_ = TwoSides; break;
250 lyxerr << "Impossible number of page"
251 " sides, setting to one."
261 pagestyle_ = rtrim(lexrc.getString());
265 defaultfont_.lyxRead(lexrc);
266 if (!defaultfont_.resolved()) {
267 lexrc.printError("Warning: defaultfont should "
268 "be fully instantiated!");
269 #ifndef INHERIT_LANGUAGE
270 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
272 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE),
279 readMaxCounter(lexrc);
284 secnumdepth_ = lexrc.getInteger();
289 tocdepth_ = lexrc.getInteger();
292 // First step to support options
293 case TC_CLASSOPTIONS:
294 readClassOptions(lexrc);
298 preamble_ = lexrc.getLongString("EndPreamble");
301 case TC_PROVIDESAMSMATH:
302 if (lexrc.next() && lexrc.getInteger())
303 provides_ |= amsmath;
306 case TC_PROVIDESNATBIB:
307 if (lexrc.next() && lexrc.getInteger())
311 case TC_PROVIDESMAKEIDX:
312 if (lexrc.next() && lexrc.getInteger())
313 provides_ |= makeidx;
317 if (lexrc.next() && lexrc.getInteger())
321 case TC_LEFTMARGIN: // left margin type
323 leftmargin_ = lexrc.getString();
326 case TC_RIGHTMARGIN: // right margin type
328 rightmargin_ = lexrc.getString();
339 if (!merge) { // we are at top level here.
340 lyxerr[Debug::TCLASS] << "Finished reading textclass "
341 << MakeDisplayPath(filename)
343 if (defaultlayout_.empty()) {
344 lyxerr << "Error: Textclass '" << name_
345 << "' is missing a defaultstyle." << endl;
349 lyxerr[Debug::TCLASS] << "Finished reading input file "
350 << MakeDisplayPath(filename)
357 void LyXTextClass::readOutputType(LyXLex & lexrc)
359 keyword_item outputTypeTags[] = {
360 { "docbook", DOCBOOK },
362 { "linuxdoc", LINUXDOC },
363 { "literate", LITERATE }
366 pushpophelper pph(lexrc, outputTypeTags, LITERATE);
368 int le = lexrc.lex();
370 case LyXLex::LEX_UNDEF:
371 lexrc.printError("Unknown output type `$$Token'");
377 outputType_ = static_cast<OutputType>(le);
380 lyxerr << "Unhandled value " << le
381 << " in LyXTextClass::readOutputType." << endl;
388 enum MaxCounterTags {
389 MC_COUNTER_CHAPTER = 1,
391 MC_COUNTER_SUBSECTION,
392 MC_COUNTER_SUBSUBSECTION,
393 MC_COUNTER_PARAGRAPH,
394 MC_COUNTER_SUBPARAGRAPH,
402 void LyXTextClass::readMaxCounter(LyXLex & lexrc)
404 keyword_item maxCounterTags[] = {
405 {"counter_chapter", MC_COUNTER_CHAPTER },
406 {"counter_enumi", MC_COUNTER_ENUMI },
407 {"counter_enumii", MC_COUNTER_ENUMII },
408 {"counter_enumiii", MC_COUNTER_ENUMIII },
409 {"counter_enumiv", MC_COUNTER_ENUMIV },
410 {"counter_paragraph", MC_COUNTER_PARAGRAPH },
411 {"counter_section", MC_COUNTER_SECTION },
412 {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
413 {"counter_subsection", MC_COUNTER_SUBSECTION },
414 {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
417 pushpophelper pph(lexrc, maxCounterTags, MC_COUNTER_ENUMIV);
418 int le = lexrc.lex();
420 case LyXLex::LEX_UNDEF:
421 lexrc.printError("Unknown MaxCounter tag `$$Token'");
425 switch (static_cast<MaxCounterTags>(le)) {
426 case MC_COUNTER_CHAPTER:
427 maxcounter_ = LABEL_COUNTER_CHAPTER;
429 case MC_COUNTER_SECTION:
430 maxcounter_ = LABEL_COUNTER_SECTION;
432 case MC_COUNTER_SUBSECTION:
433 maxcounter_ = LABEL_COUNTER_SUBSECTION;
435 case MC_COUNTER_SUBSUBSECTION:
436 maxcounter_ = LABEL_COUNTER_SUBSUBSECTION;
438 case MC_COUNTER_PARAGRAPH:
439 maxcounter_ = LABEL_COUNTER_PARAGRAPH;
441 case MC_COUNTER_SUBPARAGRAPH:
442 maxcounter_ = LABEL_COUNTER_SUBPARAGRAPH;
444 case MC_COUNTER_ENUMI:
445 maxcounter_ = LABEL_COUNTER_ENUMI;
447 case MC_COUNTER_ENUMII:
448 maxcounter_ = LABEL_COUNTER_ENUMII;
450 case MC_COUNTER_ENUMIII:
451 maxcounter_ = LABEL_COUNTER_ENUMIII;
453 case MC_COUNTER_ENUMIV:
454 maxcounter_ = LABEL_COUNTER_ENUMIV;
460 enum ClassOptionsTags {
468 void LyXTextClass::readClassOptions(LyXLex & lexrc)
470 keyword_item classOptionsTags[] = {
472 {"fontsize", CO_FONTSIZE },
473 {"other", CO_OTHER },
474 {"pagestyle", CO_PAGESTYLE }
477 lexrc.pushTable(classOptionsTags, CO_END);
479 while (!getout && lexrc.isOK()) {
480 int le = lexrc.lex();
482 case LyXLex::LEX_UNDEF:
483 lexrc.printError("Unknown ClassOption tag `$$Token'");
487 switch (static_cast<ClassOptionsTags>(le)) {
490 opt_fontsize_ = rtrim(lexrc.getString());
494 opt_pagestyle_ = rtrim(lexrc.getString());
498 options_ = lexrc.getString();
521 void LyXTextClass::readFloat(LyXLex & lexrc)
523 keyword_item floatTags[] = {
525 { "extension", FT_EXT },
526 { "guiname", FT_NAME },
527 { "latexbuiltin", FT_BUILTIN },
528 { "listname", FT_LISTNAME },
529 { "numberwithin", FT_WITHIN },
530 { "placement", FT_PLACEMENT },
531 { "style", FT_STYLE },
535 lexrc.pushTable(floatTags, FT_END);
544 bool builtin = false;
547 while (!getout && lexrc.isOK()) {
548 int le = lexrc.lex();
550 case LyXLex::LEX_UNDEF:
551 lexrc.printError("Unknown ClassOption tag `$$Token'");
555 switch (static_cast<FloatTags>(le)) {
558 type = lexrc.getString();
559 // Here we could check if this type is already defined
560 // and modify it with the rest of the vars instead.
564 name = lexrc.getString();
568 placement = lexrc.getString();
572 ext = lexrc.getString();
576 within = lexrc.getString();
577 if (within == "none")
582 style = lexrc.getString();
586 listname = lexrc.getString();
590 builtin = lexrc.getBool();
598 // Here if have a full float if getout == true
600 Floating newfloat(type, placement, ext, within,
601 style, name, listname, builtin);
602 floatlist_.newFloat(newfloat);
615 void LyXTextClass::readCounter(LyXLex & lexrc)
617 keyword_item counterTags[] = {
620 { "within", CT_WITHIN }
623 lexrc.pushTable(counterTags, CT_END);
629 while (!getout && lexrc.isOK()) {
630 int le = lexrc.lex();
632 case LyXLex::LEX_UNDEF:
633 lexrc.printError("Unknown ClassOption tag `$$Token'");
637 switch (static_cast<CounterTags>(le)) {
640 name = lexrc.getString();
644 within = lexrc.getString();
645 if (within == "none")
654 // Here if have a full float if getout == true
656 if (within.empty()) {
657 ctrs_->newCounter(name);
659 ctrs_->newCounter(name, within);
667 LyXFont const & LyXTextClass::defaultfont() const
673 string const & LyXTextClass::leftmargin() const
679 string const & LyXTextClass::rightmargin() const
685 bool LyXTextClass::hasLayout(string const & n) const
687 string const name = (n.empty() ? defaultLayoutName() : n);
689 return find_if(layoutlist_.begin(), layoutlist_.end(),
691 != layoutlist_.end();
695 LyXLayout_ptr const & LyXTextClass::operator[](string const & n) const
697 lyx::Assert(!n.empty());
700 lyxerr << "Operator[] called with empty n" << endl;
702 string const name = (n.empty() ? defaultLayoutName() : n);
704 static string lastLayoutName;
705 static LayoutList::difference_type lastLayoutIndex;
707 if (name == lastLayoutName)
708 return layoutlist_[lastLayoutIndex];
710 LayoutList::const_iterator cit =
711 find_if(layoutlist_.begin(),
715 if (cit == layoutlist_.end()) {
716 lyxerr << "We failed to find the layout '" << name
717 << "' in the layout list. You MUST investigate!"
720 // we require the name to exist
724 lastLayoutName = name;
725 lastLayoutIndex = std::distance(layoutlist_.begin(), cit);
731 bool LyXTextClass::delete_layout(string const & name)
733 if (name == defaultLayoutName())
736 LayoutList::iterator it =
737 remove_if(layoutlist_.begin(), layoutlist_.end(),
740 LayoutList::iterator end = layoutlist_.end();
741 bool const ret = (it != end);
742 layoutlist_.erase(it, end);
747 // Load textclass info if not loaded yet
748 bool LyXTextClass::load() const
754 string const real_file = LibFileSearch("layouts", name_, "layout");
756 if (const_cast<LyXTextClass*>(this)->Read(real_file)) {
757 lyxerr << "Error reading `"
758 << MakeDisplayPath(real_file)
759 << "'\n(Check `" << name_
760 << "')\nCheck your installation and "
761 "try Options/Reconfigure..." << endl;
769 FloatList & LyXTextClass::floats()
775 FloatList const & LyXTextClass::floats() const
781 Counters & LyXTextClass::counters() const
787 string const & LyXTextClass::defaultLayoutName() const
789 // This really should come from the actual layout... (Lgb)
790 return defaultlayout_;
794 LyXLayout_ptr const & LyXTextClass::defaultLayout() const
796 return operator[](defaultLayoutName());
800 string const & LyXTextClass::name() const
806 string const & LyXTextClass::latexname() const
808 const_cast<LyXTextClass*>(this)->load();
813 string const & LyXTextClass::description() const
819 string const & LyXTextClass::opt_fontsize() const
821 return opt_fontsize_;
825 string const & LyXTextClass::opt_pagestyle() const
827 return opt_pagestyle_;
831 string const & LyXTextClass::options() const
837 string const & LyXTextClass::pagestyle() const
843 string const & LyXTextClass::preamble() const
849 LyXTextClass::PageSides LyXTextClass::sides() const
855 int LyXTextClass::secnumdepth() const
861 int LyXTextClass::tocdepth() const
867 OutputType LyXTextClass::outputType() const
873 bool LyXTextClass::provides(LyXTextClass::Provides p) const
875 return provides_ & p;
879 unsigned int LyXTextClass::columns() const
885 int LyXTextClass::maxcounter() const
891 int LyXTextClass::size() const
893 return layoutlist_.size();
897 ostream & operator<<(ostream & os, LyXTextClass::PageSides p)
900 case LyXTextClass::OneSide:
903 case LyXTextClass::TwoSides: