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 `" << style << "'" << endl;
232 // lexrc.printError("Cannot delete style"
239 columns_ = lexrc.getInteger();
244 switch (lexrc.getInteger()) {
245 case 1: sides_ = OneSide; break;
246 case 2: sides_ = TwoSides; break;
248 lyxerr << "Impossible number of page"
249 " sides, setting to one."
259 pagestyle_ = rtrim(lexrc.getString());
263 defaultfont_.lyxRead(lexrc);
264 if (!defaultfont_.resolved()) {
265 lexrc.printError("Warning: defaultfont should "
266 "be fully instantiated!");
267 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
272 readMaxCounter(lexrc);
277 secnumdepth_ = lexrc.getInteger();
282 tocdepth_ = lexrc.getInteger();
285 // First step to support options
286 case TC_CLASSOPTIONS:
287 readClassOptions(lexrc);
291 preamble_ = lexrc.getLongString("EndPreamble");
294 case TC_PROVIDESAMSMATH:
295 if (lexrc.next() && lexrc.getInteger())
296 provides_ |= amsmath;
299 case TC_PROVIDESNATBIB:
300 if (lexrc.next() && lexrc.getInteger())
304 case TC_PROVIDESMAKEIDX:
305 if (lexrc.next() && lexrc.getInteger())
306 provides_ |= makeidx;
310 if (lexrc.next() && lexrc.getInteger())
314 case TC_LEFTMARGIN: // left margin type
316 leftmargin_ = lexrc.getString();
319 case TC_RIGHTMARGIN: // right margin type
321 rightmargin_ = lexrc.getString();
331 string const nofloat = lexrc.getString();
332 floatlist_->erase(nofloat);
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()
771 return *floatlist_.get();
775 FloatList const & LyXTextClass::floats() const
777 return *floatlist_.get();
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: