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"
22 #include "FloatList.h"
24 #include "support/lstrings.h"
25 #include "support/LAssert.h"
26 #include "support/lyxfunctional.h"
27 #include "support/filetools.h"
39 compare_name(string const & name)
42 bool operator()(C & c) {
43 return c->name() == name_;
51 LyXTextClass::LyXTextClass(string const & fn, string const & cln,
53 : name_(fn), latexname_(cln), description_(desc),
54 floatlist_(new FloatList), ctrs_(new Counters)
61 pagestyle_ = "default";
62 maxcounter_ = LABEL_COUNTER_CHAPTER;
63 defaultfont_ = LyXFont(LyXFont::ALL_SANE);
64 opt_fontsize_ = "10|11|12";
65 opt_pagestyle_ = "empty|plain|headings|fancy";
71 bool LyXTextClass::do_readStyle(LyXLex & lexrc, LyXLayout & lay)
73 lyxerr[Debug::TCLASS] << "Reading style " << lay.name() << endl;
74 if (!lay.Read(lexrc, *this)) {
76 lay.resfont = lay.font;
77 lay.resfont.realize(defaultfont());
78 lay.reslabelfont = lay.labelfont;
79 lay.reslabelfont.realize(defaultfont());
80 return false; // no errors
82 lyxerr << "Error parsing style `" << lay.name() << '\'' << endl;
114 // Reads a textclass structure from file.
115 bool LyXTextClass::Read(string const & filename, bool merge)
117 keyword_item textClassTags[] = {
118 { "classoptions", TC_CLASSOPTIONS },
119 { "columns", TC_COLUMNS },
120 { "counter", TC_COUNTER },
121 { "defaultfont", TC_DEFAULTFONT },
122 { "defaultstyle", TC_DEFAULTSTYLE },
123 { "float", TC_FLOAT },
124 { "input", TC_INPUT },
125 { "leftmargin", TC_LEFTMARGIN },
126 { "maxcounter", TC_MAXCOUNTER },
127 { "nofloat", TC_NOFLOAT },
128 { "nostyle", TC_NOSTYLE },
129 { "outputtype", TC_OUTPUTTYPE },
130 { "pagestyle", TC_PAGESTYLE },
131 { "preamble", TC_PREAMBLE },
132 { "providesamsmath", TC_PROVIDESAMSMATH },
133 { "providesmakeidx", TC_PROVIDESMAKEIDX },
134 { "providesnatbib", TC_PROVIDESNATBIB },
135 { "providesurl", TC_PROVIDESURL },
136 { "rightmargin", TC_RIGHTMARGIN },
137 { "secnumdepth", TC_SECNUMDEPTH },
138 { "sides", TC_SIDES },
139 { "style", TC_STYLE },
140 { "tocdepth", TC_TOCDEPTH }
144 lyxerr[Debug::TCLASS] << "Reading textclass "
145 << MakeDisplayPath(filename)
148 lyxerr[Debug::TCLASS] << "Reading input file "
149 << MakeDisplayPath(filename)
152 LyXLex lexrc(textClassTags, TC_NOFLOAT);
155 lexrc.setFile(filename);
156 if (!lexrc.isOK()) error = true;
159 while (lexrc.isOK() && !error) {
160 int le = lexrc.lex();
162 case LyXLex::LEX_FEOF:
165 case LyXLex::LEX_UNDEF:
166 lexrc.printError("Unknown TextClass tag `$$Token'");
171 switch (static_cast<TextClassTags>(le)) {
172 case TC_OUTPUTTYPE: // output type definition
173 readOutputType(lexrc);
176 case TC_INPUT: // Include file
178 string tmp = LibFileSearch("layouts",
182 if (Read(tmp, true)) {
183 lexrc.printError("Error reading input"
190 case TC_DEFAULTSTYLE:
192 string const name = subst(lexrc.getString(),
194 defaultlayout_ = name;
200 string const name = subst(lexrc.getString(),
202 if (hasLayout(name)) {
204 operator[](name).get();
205 error = do_readStyle(lexrc, *lay);
209 if (!(error = do_readStyle(lexrc, lay)))
210 layoutlist_.push_back(boost::shared_ptr<LyXLayout>(new LyXLayout(lay)));
211 if (defaultlayout_.empty()) {
212 // We do not have a default
213 // layout yet, so we choose
214 // the first layout we
216 defaultlayout_ = name;
221 lexrc.printError("No name given for style: `$$Token'.");
228 string const style = subst(lexrc.getString(),
230 if (!delete_layout(style))
231 lyxerr << "Cannot delete style `"
232 << style << '\'' << endl;
233 // lexrc.printError("Cannot delete style"
240 columns_ = lexrc.getInteger();
245 switch (lexrc.getInteger()) {
246 case 1: sides_ = OneSide; break;
247 case 2: sides_ = TwoSides; break;
249 lyxerr << "Impossible number of page"
250 " sides, setting to one."
260 pagestyle_ = rtrim(lexrc.getString());
264 defaultfont_.lyxRead(lexrc);
265 if (!defaultfont_.resolved()) {
266 lexrc.printError("Warning: defaultfont should "
267 "be fully instantiated!");
268 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
273 readMaxCounter(lexrc);
278 secnumdepth_ = lexrc.getInteger();
283 tocdepth_ = lexrc.getInteger();
286 // First step to support options
287 case TC_CLASSOPTIONS:
288 readClassOptions(lexrc);
292 preamble_ = lexrc.getLongString("EndPreamble");
295 case TC_PROVIDESAMSMATH:
296 if (lexrc.next() && lexrc.getInteger())
297 provides_ |= amsmath;
300 case TC_PROVIDESNATBIB:
301 if (lexrc.next() && lexrc.getInteger())
305 case TC_PROVIDESMAKEIDX:
306 if (lexrc.next() && lexrc.getInteger())
307 provides_ |= makeidx;
311 if (lexrc.next() && lexrc.getInteger())
315 case TC_LEFTMARGIN: // left margin type
317 leftmargin_ = lexrc.getString();
320 case TC_RIGHTMARGIN: // right margin type
322 rightmargin_ = lexrc.getString();
332 string const nofloat = lexrc.getString();
333 floatlist_->erase(nofloat);
340 if (!merge) { // we are at top level here.
341 lyxerr[Debug::TCLASS] << "Finished reading textclass "
342 << MakeDisplayPath(filename)
344 if (defaultlayout_.empty()) {
345 lyxerr << "Error: Textclass '" << name_
346 << "' is missing a defaultstyle." << endl;
350 lyxerr[Debug::TCLASS] << "Finished reading input file "
351 << MakeDisplayPath(filename)
358 void LyXTextClass::readOutputType(LyXLex & lexrc)
360 keyword_item outputTypeTags[] = {
361 { "docbook", DOCBOOK },
363 { "linuxdoc", LINUXDOC },
364 { "literate", LITERATE }
367 pushpophelper pph(lexrc, outputTypeTags, LITERATE);
369 int le = lexrc.lex();
371 case LyXLex::LEX_UNDEF:
372 lexrc.printError("Unknown output type `$$Token'");
378 outputType_ = static_cast<OutputType>(le);
381 lyxerr << "Unhandled value " << le
382 << " in LyXTextClass::readOutputType." << endl;
389 enum MaxCounterTags {
390 MC_COUNTER_CHAPTER = 1,
392 MC_COUNTER_SUBSECTION,
393 MC_COUNTER_SUBSUBSECTION,
394 MC_COUNTER_PARAGRAPH,
395 MC_COUNTER_SUBPARAGRAPH,
403 void LyXTextClass::readMaxCounter(LyXLex & lexrc)
405 keyword_item maxCounterTags[] = {
406 {"counter_chapter", MC_COUNTER_CHAPTER },
407 {"counter_enumi", MC_COUNTER_ENUMI },
408 {"counter_enumii", MC_COUNTER_ENUMII },
409 {"counter_enumiii", MC_COUNTER_ENUMIII },
410 {"counter_enumiv", MC_COUNTER_ENUMIV },
411 {"counter_paragraph", MC_COUNTER_PARAGRAPH },
412 {"counter_section", MC_COUNTER_SECTION },
413 {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
414 {"counter_subsection", MC_COUNTER_SUBSECTION },
415 {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
418 pushpophelper pph(lexrc, maxCounterTags, MC_COUNTER_ENUMIV);
419 int le = lexrc.lex();
421 case LyXLex::LEX_UNDEF:
422 lexrc.printError("Unknown MaxCounter tag `$$Token'");
426 switch (static_cast<MaxCounterTags>(le)) {
427 case MC_COUNTER_CHAPTER:
428 maxcounter_ = LABEL_COUNTER_CHAPTER;
430 case MC_COUNTER_SECTION:
431 maxcounter_ = LABEL_COUNTER_SECTION;
433 case MC_COUNTER_SUBSECTION:
434 maxcounter_ = LABEL_COUNTER_SUBSECTION;
436 case MC_COUNTER_SUBSUBSECTION:
437 maxcounter_ = LABEL_COUNTER_SUBSUBSECTION;
439 case MC_COUNTER_PARAGRAPH:
440 maxcounter_ = LABEL_COUNTER_PARAGRAPH;
442 case MC_COUNTER_SUBPARAGRAPH:
443 maxcounter_ = LABEL_COUNTER_SUBPARAGRAPH;
445 case MC_COUNTER_ENUMI:
446 maxcounter_ = LABEL_COUNTER_ENUMI;
448 case MC_COUNTER_ENUMII:
449 maxcounter_ = LABEL_COUNTER_ENUMII;
451 case MC_COUNTER_ENUMIII:
452 maxcounter_ = LABEL_COUNTER_ENUMIII;
454 case MC_COUNTER_ENUMIV:
455 maxcounter_ = LABEL_COUNTER_ENUMIV;
461 enum ClassOptionsTags {
469 void LyXTextClass::readClassOptions(LyXLex & lexrc)
471 keyword_item classOptionsTags[] = {
473 {"fontsize", CO_FONTSIZE },
474 {"other", CO_OTHER },
475 {"pagestyle", CO_PAGESTYLE }
478 lexrc.pushTable(classOptionsTags, CO_END);
480 while (!getout && lexrc.isOK()) {
481 int le = lexrc.lex();
483 case LyXLex::LEX_UNDEF:
484 lexrc.printError("Unknown ClassOption tag `$$Token'");
488 switch (static_cast<ClassOptionsTags>(le)) {
491 opt_fontsize_ = rtrim(lexrc.getString());
495 opt_pagestyle_ = rtrim(lexrc.getString());
499 options_ = lexrc.getString();
522 void LyXTextClass::readFloat(LyXLex & lexrc)
524 keyword_item floatTags[] = {
526 { "extension", FT_EXT },
527 { "guiname", FT_NAME },
528 { "latexbuiltin", FT_BUILTIN },
529 { "listname", FT_LISTNAME },
530 { "numberwithin", FT_WITHIN },
531 { "placement", FT_PLACEMENT },
532 { "style", FT_STYLE },
536 lexrc.pushTable(floatTags, FT_END);
545 bool builtin = false;
548 while (!getout && lexrc.isOK()) {
549 int le = lexrc.lex();
551 case LyXLex::LEX_UNDEF:
552 lexrc.printError("Unknown ClassOption tag `$$Token'");
556 switch (static_cast<FloatTags>(le)) {
559 type = lexrc.getString();
560 // Here we could check if this type is already defined
561 // and modify it with the rest of the vars instead.
565 name = lexrc.getString();
569 placement = lexrc.getString();
573 ext = lexrc.getString();
577 within = lexrc.getString();
578 if (within == "none")
583 style = lexrc.getString();
587 listname = lexrc.getString();
591 builtin = lexrc.getBool();
599 // Here if have a full float if getout == true
601 Floating newfloat(type, placement, ext, within,
602 style, name, listname, builtin);
603 floatlist_->newFloat(newfloat);
616 void LyXTextClass::readCounter(LyXLex & lexrc)
618 keyword_item counterTags[] = {
621 { "within", CT_WITHIN }
624 lexrc.pushTable(counterTags, CT_END);
630 while (!getout && lexrc.isOK()) {
631 int le = lexrc.lex();
633 case LyXLex::LEX_UNDEF:
634 lexrc.printError("Unknown ClassOption tag `$$Token'");
638 switch (static_cast<CounterTags>(le)) {
641 name = lexrc.getString();
645 within = lexrc.getString();
646 if (within == "none")
655 // Here if have a full float if getout == true
657 if (within.empty()) {
658 ctrs_->newCounter(name);
660 ctrs_->newCounter(name, within);
668 LyXFont const & LyXTextClass::defaultfont() const
674 string const & LyXTextClass::leftmargin() const
680 string const & LyXTextClass::rightmargin() const
686 bool LyXTextClass::hasLayout(string const & n) const
688 string const name = (n.empty() ? defaultLayoutName() : n);
690 return find_if(layoutlist_.begin(), layoutlist_.end(),
692 != layoutlist_.end();
696 LyXLayout_ptr const & LyXTextClass::operator[](string const & n) const
698 lyx::Assert(!n.empty());
701 lyxerr << "Operator[] called with empty n" << endl;
703 string const name = (n.empty() ? defaultLayoutName() : n);
705 static string lastLayoutName;
706 static LayoutList::difference_type lastLayoutIndex;
708 if (name == lastLayoutName)
709 return layoutlist_[lastLayoutIndex];
711 LayoutList::const_iterator cit =
712 find_if(layoutlist_.begin(),
716 if (cit == layoutlist_.end()) {
717 lyxerr << "We failed to find the layout '" << name
718 << "' in the layout list. You MUST investigate!"
721 // we require the name to exist
725 lastLayoutName = name;
726 lastLayoutIndex = std::distance(layoutlist_.begin(), cit);
732 bool LyXTextClass::delete_layout(string const & name)
734 if (name == defaultLayoutName())
737 LayoutList::iterator it =
738 remove_if(layoutlist_.begin(), layoutlist_.end(),
741 LayoutList::iterator end = layoutlist_.end();
742 bool const ret = (it != end);
743 layoutlist_.erase(it, end);
748 // Load textclass info if not loaded yet
749 bool LyXTextClass::load() const
755 string const real_file = LibFileSearch("layouts", name_, "layout");
757 if (const_cast<LyXTextClass*>(this)->Read(real_file)) {
758 lyxerr << "Error reading `"
759 << MakeDisplayPath(real_file)
760 << "'\n(Check `" << name_
761 << "')\nCheck your installation and "
762 "try Options/Reconfigure..." << endl;
770 FloatList & LyXTextClass::floats()
772 return *floatlist_.get();
776 FloatList const & LyXTextClass::floats() const
778 return *floatlist_.get();
782 Counters & LyXTextClass::counters() const
788 string const & LyXTextClass::defaultLayoutName() const
790 // This really should come from the actual layout... (Lgb)
791 return defaultlayout_;
795 LyXLayout_ptr const & LyXTextClass::defaultLayout() const
797 return operator[](defaultLayoutName());
801 string const & LyXTextClass::name() const
807 string const & LyXTextClass::latexname() const
809 const_cast<LyXTextClass*>(this)->load();
814 string const & LyXTextClass::description() const
820 string const & LyXTextClass::opt_fontsize() const
822 return opt_fontsize_;
826 string const & LyXTextClass::opt_pagestyle() const
828 return opt_pagestyle_;
832 string const & LyXTextClass::options() const
838 string const & LyXTextClass::pagestyle() const
844 string const & LyXTextClass::preamble() const
850 LyXTextClass::PageSides LyXTextClass::sides() const
856 int LyXTextClass::secnumdepth() const
862 int LyXTextClass::tocdepth() const
868 OutputType LyXTextClass::outputType() const
874 bool LyXTextClass::provides(LyXTextClass::Provides p) const
876 return provides_ & p;
880 unsigned int LyXTextClass::columns() const
886 int LyXTextClass::maxcounter() const
892 int LyXTextClass::size() const
894 return layoutlist_.size();
898 ostream & operator<<(ostream & os, LyXTextClass::PageSides p)
901 case LyXTextClass::OneSide:
904 case LyXTextClass::TwoSides: