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 "support/lstrings.h"
23 #include "support/LAssert.h"
24 #include "support/lyxfunctional.h"
25 #include "support/filetools.h"
37 compare_name(string const & name)
40 bool operator()(C & c) {
41 return c->name() == name_;
49 LyXTextClass::LyXTextClass(string const & fn, string const & cln,
51 : name_(fn), latexname_(cln), description_(desc)
58 pagestyle_ = "default";
59 maxcounter_ = LABEL_COUNTER_CHAPTER;
60 defaultfont_ = LyXFont(LyXFont::ALL_SANE);
61 opt_fontsize_ = "10|11|12";
62 opt_pagestyle_ = "empty|plain|headings|fancy";
68 bool LyXTextClass::do_readStyle(LyXLex & lexrc, LyXLayout & lay)
70 lyxerr[Debug::TCLASS] << "Reading style " << lay.name() << endl;
71 if (!lay.Read(lexrc, *this)) {
73 lay.resfont = lay.font;
74 #ifndef INHERIT_LANGUAGE
75 lay.resfont.realize(defaultfont());
76 lay.reslabelfont = lay.labelfont;
77 lay.reslabelfont.realize(defaultfont());
79 lay.resfont.realize(defaultfont(), default_language);
80 lay.reslabelfont = lay.labelfont;
81 lay.reslabelfont.realize(defaultfont(), default_language);
83 return false; // no errors
85 lyxerr << "Error parsing style `" << lay.name() << "'" << endl;
115 // Reads a textclass structure from file.
116 bool LyXTextClass::Read(string const & filename, bool merge)
118 keyword_item textClassTags[] = {
119 { "classoptions", TC_CLASSOPTIONS },
120 { "columns", TC_COLUMNS },
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 { "nostyle", TC_NOSTYLE },
128 { "outputtype", TC_OUTPUTTYPE },
129 { "pagestyle", TC_PAGESTYLE },
130 { "preamble", TC_PREAMBLE },
131 { "providesamsmath", TC_PROVIDESAMSMATH },
132 { "providesmakeidx", TC_PROVIDESMAKEIDX },
133 { "providesnatbib", TC_PROVIDESNATBIB },
134 { "providesurl", TC_PROVIDESURL },
135 { "rightmargin", TC_RIGHTMARGIN },
136 { "secnumdepth", TC_SECNUMDEPTH },
137 { "sides", TC_SIDES },
138 { "style", TC_STYLE },
139 { "tocdepth", TC_TOCDEPTH }
143 lyxerr[Debug::TCLASS] << "Reading textclass "
144 << MakeDisplayPath(filename)
147 lyxerr[Debug::TCLASS] << "Reading input file "
148 << MakeDisplayPath(filename)
151 LyXLex lexrc(textClassTags, TC_FLOAT);
154 lexrc.setFile(filename);
155 if (!lexrc.isOK()) error = true;
158 while (lexrc.isOK() && !error) {
159 int le = lexrc.lex();
161 case LyXLex::LEX_FEOF:
164 case LyXLex::LEX_UNDEF:
165 lexrc.printError("Unknown TextClass tag `$$Token'");
170 switch (static_cast<TextClassTags>(le)) {
171 case TC_OUTPUTTYPE: // output type definition
172 readOutputType(lexrc);
175 case TC_INPUT: // Include file
177 string tmp = LibFileSearch("layouts",
181 if (Read(tmp, true)) {
182 lexrc.printError("Error reading input"
189 case TC_DEFAULTSTYLE:
191 string const name = subst(lexrc.getString(),
193 defaultlayout_ = name;
199 string const name = subst(lexrc.getString(),
201 if (hasLayout(name)) {
203 operator[](name).get();
204 error = do_readStyle(lexrc, *lay);
208 if (!(error = do_readStyle(lexrc, lay)))
209 layoutlist_.push_back(boost::shared_ptr<LyXLayout>(new LyXLayout(lay)));
210 if (defaultlayout_.empty()) {
211 // We do not have a default
212 // layout yet, so we choose
213 // the first layout we
215 defaultlayout_ = name;
220 lexrc.printError("No name given for style: `$$Token'.");
227 string const style = subst(lexrc.getString(),
229 if (!delete_layout(style))
230 lyxerr << "Cannot delete style `" << style << "'" << endl;
231 // lexrc.printError("Cannot delete style"
238 columns_ = lexrc.getInteger();
243 switch (lexrc.getInteger()) {
244 case 1: sides_ = OneSide; break;
245 case 2: sides_ = TwoSides; break;
247 lyxerr << "Impossible number of page"
248 " sides, setting to one."
258 pagestyle_ = rtrim(lexrc.getString());
262 defaultfont_.lyxRead(lexrc);
263 if (!defaultfont_.resolved()) {
264 lexrc.printError("Warning: defaultfont should "
265 "be fully instantiated!");
266 #ifndef INHERIT_LANGUAGE
267 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
269 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE),
276 readMaxCounter(lexrc);
281 secnumdepth_ = lexrc.getInteger();
286 tocdepth_ = lexrc.getInteger();
289 // First step to support options
290 case TC_CLASSOPTIONS:
291 readClassOptions(lexrc);
295 preamble_ = lexrc.getLongString("EndPreamble");
298 case TC_PROVIDESAMSMATH:
299 if (lexrc.next() && lexrc.getInteger())
300 provides_ |= amsmath;
303 case TC_PROVIDESNATBIB:
304 if (lexrc.next() && lexrc.getInteger())
308 case TC_PROVIDESMAKEIDX:
309 if (lexrc.next() && lexrc.getInteger())
310 provides_ |= makeidx;
314 if (lexrc.next() && lexrc.getInteger())
318 case TC_LEFTMARGIN: // left margin type
320 leftmargin_ = lexrc.getString();
323 case TC_RIGHTMARGIN: // right margin type
325 rightmargin_ = lexrc.getString();
333 if (!merge) { // we are at top level here.
334 lyxerr[Debug::TCLASS] << "Finished reading textclass "
335 << MakeDisplayPath(filename)
337 if (defaultlayout_.empty()) {
338 lyxerr << "Error: Textclass '" << name_
339 << "' is missing a defaultstyle." << endl;
343 lyxerr[Debug::TCLASS] << "Finished reading input file "
344 << MakeDisplayPath(filename)
351 void LyXTextClass::readOutputType(LyXLex & lexrc)
353 keyword_item outputTypeTags[] = {
354 { "docbook", DOCBOOK },
356 { "linuxdoc", LINUXDOC },
357 { "literate", LITERATE }
360 pushpophelper pph(lexrc, outputTypeTags, LITERATE);
362 int le = lexrc.lex();
364 case LyXLex::LEX_UNDEF:
365 lexrc.printError("Unknown output type `$$Token'");
371 outputType_ = static_cast<OutputType>(le);
374 lyxerr << "Unhandled value " << le
375 << " in LyXTextClass::readOutputType." << endl;
382 enum MaxCounterTags {
383 MC_COUNTER_CHAPTER = 1,
385 MC_COUNTER_SUBSECTION,
386 MC_COUNTER_SUBSUBSECTION,
387 MC_COUNTER_PARAGRAPH,
388 MC_COUNTER_SUBPARAGRAPH,
396 void LyXTextClass::readMaxCounter(LyXLex & lexrc)
398 keyword_item maxCounterTags[] = {
399 {"counter_chapter", MC_COUNTER_CHAPTER },
400 {"counter_enumi", MC_COUNTER_ENUMI },
401 {"counter_enumii", MC_COUNTER_ENUMII },
402 {"counter_enumiii", MC_COUNTER_ENUMIII },
403 {"counter_enumiv", MC_COUNTER_ENUMIV },
404 {"counter_paragraph", MC_COUNTER_PARAGRAPH },
405 {"counter_section", MC_COUNTER_SECTION },
406 {"counter_subparagraph", MC_COUNTER_SUBPARAGRAPH },
407 {"counter_subsection", MC_COUNTER_SUBSECTION },
408 {"counter_subsubsection", MC_COUNTER_SUBSUBSECTION }
411 pushpophelper pph(lexrc, maxCounterTags, MC_COUNTER_ENUMIV);
412 int le = lexrc.lex();
414 case LyXLex::LEX_UNDEF:
415 lexrc.printError("Unknown MaxCounter tag `$$Token'");
419 switch (static_cast<MaxCounterTags>(le)) {
420 case MC_COUNTER_CHAPTER:
421 maxcounter_ = LABEL_COUNTER_CHAPTER;
423 case MC_COUNTER_SECTION:
424 maxcounter_ = LABEL_COUNTER_SECTION;
426 case MC_COUNTER_SUBSECTION:
427 maxcounter_ = LABEL_COUNTER_SUBSECTION;
429 case MC_COUNTER_SUBSUBSECTION:
430 maxcounter_ = LABEL_COUNTER_SUBSUBSECTION;
432 case MC_COUNTER_PARAGRAPH:
433 maxcounter_ = LABEL_COUNTER_PARAGRAPH;
435 case MC_COUNTER_SUBPARAGRAPH:
436 maxcounter_ = LABEL_COUNTER_SUBPARAGRAPH;
438 case MC_COUNTER_ENUMI:
439 maxcounter_ = LABEL_COUNTER_ENUMI;
441 case MC_COUNTER_ENUMII:
442 maxcounter_ = LABEL_COUNTER_ENUMII;
444 case MC_COUNTER_ENUMIII:
445 maxcounter_ = LABEL_COUNTER_ENUMIII;
447 case MC_COUNTER_ENUMIV:
448 maxcounter_ = LABEL_COUNTER_ENUMIV;
454 enum ClassOptionsTags {
462 void LyXTextClass::readClassOptions(LyXLex & lexrc)
464 keyword_item classOptionsTags[] = {
466 {"fontsize", CO_FONTSIZE },
467 {"other", CO_OTHER },
468 {"pagestyle", CO_PAGESTYLE }
471 lexrc.pushTable(classOptionsTags, CO_END);
473 while (!getout && lexrc.isOK()) {
474 int le = lexrc.lex();
476 case LyXLex::LEX_UNDEF:
477 lexrc.printError("Unknown ClassOption tag `$$Token'");
481 switch (static_cast<ClassOptionsTags>(le)) {
484 opt_fontsize_ = rtrim(lexrc.getString());
488 opt_pagestyle_ = rtrim(lexrc.getString());
492 options_ = lexrc.getString();
515 void LyXTextClass::readFloat(LyXLex & lexrc)
517 keyword_item floatTags[] = {
519 { "extension", FT_EXT },
520 { "guiname", FT_NAME },
521 { "latexbuiltin", FT_BUILTIN },
522 { "listname", FT_LISTNAME },
523 { "numberwithin", FT_WITHIN },
524 { "placement", FT_PLACEMENT },
525 { "style", FT_STYLE },
529 lexrc.pushTable(floatTags, FT_END);
538 bool builtin = false;
541 while (!getout && lexrc.isOK()) {
542 int le = lexrc.lex();
544 case LyXLex::LEX_UNDEF:
545 lexrc.printError("Unknown ClassOption tag `$$Token'");
549 switch (static_cast<FloatTags>(le)) {
552 type = lexrc.getString();
553 // Here we could check if this type is already defined
554 // and modify it with the rest of the vars instead.
558 name = lexrc.getString();
562 placement = lexrc.getString();
566 ext = lexrc.getString();
570 within = lexrc.getString();
571 if (within == "none")
576 style = lexrc.getString();
580 listname = lexrc.getString();
584 builtin = lexrc.getBool();
592 // Here if have a full float if getout == true
594 Floating newfloat(type, placement, ext, within,
595 style, name, listname, builtin);
596 floatlist_.newFloat(newfloat);
603 LyXFont const & LyXTextClass::defaultfont() const
609 string const & LyXTextClass::leftmargin() const
615 string const & LyXTextClass::rightmargin() const
621 bool LyXTextClass::hasLayout(string const & n) const
623 string const name = (n.empty() ? defaultLayoutName() : n);
625 return find_if(layoutlist_.begin(), layoutlist_.end(),
627 != layoutlist_.end();
631 LyXLayout_ptr const & LyXTextClass::operator[](string const & n) const
633 lyx::Assert(!n.empty());
636 lyxerr << "Operator[] called with empty n" << endl;
638 string const name = (n.empty() ? defaultLayoutName() : n);
640 static string lastLayoutName;
641 static LayoutList::difference_type lastLayoutIndex;
643 if (name == lastLayoutName)
644 return layoutlist_[lastLayoutIndex];
646 LayoutList::const_iterator cit =
647 find_if(layoutlist_.begin(),
651 if (cit == layoutlist_.end()) {
652 lyxerr << "We failed to find the layout '" << name
653 << "' in the layout list. You MUST investigate!"
656 // we require the name to exist
660 lastLayoutName = name;
661 lastLayoutIndex = std::distance(layoutlist_.begin(), cit);
667 bool LyXTextClass::delete_layout(string const & name)
669 if (name == defaultLayoutName())
672 LayoutList::iterator it =
673 remove_if(layoutlist_.begin(), layoutlist_.end(),
676 LayoutList::iterator end = layoutlist_.end();
677 bool const ret = (it != end);
678 layoutlist_.erase(it, end);
683 // Load textclass info if not loaded yet
684 bool LyXTextClass::load() const
690 string const real_file = LibFileSearch("layouts", name_, "layout");
692 if (const_cast<LyXTextClass*>(this)->Read(real_file)) {
693 lyxerr << "Error reading `"
694 << MakeDisplayPath(real_file)
695 << "'\n(Check `" << name_
696 << "')\nCheck your installation and "
697 "try Options/Reconfigure..." << endl;
705 FloatList & LyXTextClass::floats()
711 FloatList const & LyXTextClass::floats() const
717 string const LyXTextClass::defaultLayoutName() const
719 // This really should come from the actual layout... (Lgb)
720 return defaultlayout_;
724 LyXLayout_ptr const & LyXTextClass::defaultLayout() const
726 return operator[](defaultLayoutName());
730 string const & LyXTextClass::name() const
736 string const & LyXTextClass::latexname() const
738 const_cast<LyXTextClass*>(this)->load();
743 string const & LyXTextClass::description() const
749 string const & LyXTextClass::opt_fontsize() const
751 return opt_fontsize_;
755 string const & LyXTextClass::opt_pagestyle() const
757 return opt_pagestyle_;
761 string const & LyXTextClass::options() const
767 string const & LyXTextClass::pagestyle() const
773 string const & LyXTextClass::preamble() const
779 LyXTextClass::PageSides LyXTextClass::sides() const
785 int LyXTextClass::secnumdepth() const
791 int LyXTextClass::tocdepth() const
797 OutputType LyXTextClass::outputType() const
803 bool LyXTextClass::provides(LyXTextClass::Provides p) const
805 return provides_ & p;
809 unsigned int LyXTextClass::columns() const
815 int LyXTextClass::maxcounter() const
821 int LyXTextClass::size() const
823 return layoutlist_.size();
827 ostream & operator<<(ostream & os, LyXTextClass::PageSides p)
830 case LyXTextClass::OneSide:
833 case LyXTextClass::TwoSides: