3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
8 * \author Angus Leeming
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
17 #include "lyxtextclass.h"
22 #include "FloatList.h"
24 #include "support/lstrings.h"
25 #include "support/filetools.h"
27 using lyx::support::LibFileSearch;
28 using lyx::support::MakeDisplayPath;
29 using lyx::support::rtrim;
30 using lyx::support::subst;
43 compare_name(string const & name)
47 bool operator()(boost::shared_ptr<LyXLayout> const & c)
49 return c->name() == name_;
59 LyXTextClass::LyXTextClass(string const & fn, string const & cln,
60 string const & desc, bool texClassAvail )
61 : name_(fn), latexname_(cln), description_(desc),
62 floatlist_(new FloatList), ctrs_(new Counters), texClassAvail_(texClassAvail)
69 pagestyle_ = "default";
71 defaultfont_ = LyXFont(LyXFont::ALL_SANE);
72 opt_fontsize_ = "10|11|12";
73 opt_pagestyle_ = "empty|plain|headings|fancy";
75 titletype_ = TITLE_COMMAND_AFTER;
76 titlename_ = "maketitle";
81 bool LyXTextClass::isTeXClassAvailable() const
83 return texClassAvail_;
87 bool LyXTextClass::do_readStyle(LyXLex & lexrc, LyXLayout & lay)
89 lyxerr[Debug::TCLASS] << "Reading style " << lay.name() << endl;
90 if (!lay.Read(lexrc, *this)) {
92 lay.resfont = lay.font;
93 lay.resfont.realize(defaultfont());
94 lay.reslabelfont = lay.labelfont;
95 lay.reslabelfont.realize(defaultfont());
96 return false; // no errors
98 lyxerr << "Error parsing style `" << lay.name() << '\'' << endl;
132 // Reads a textclass structure from file.
133 bool LyXTextClass::Read(string const & filename, bool merge)
135 keyword_item textClassTags[] = {
136 { "classoptions", TC_CLASSOPTIONS },
137 { "columns", TC_COLUMNS },
138 { "counter", TC_COUNTER },
139 { "defaultfont", TC_DEFAULTFONT },
140 { "defaultstyle", TC_DEFAULTSTYLE },
141 { "environment", TC_ENVIRONMENT },
142 { "float", TC_FLOAT },
143 { "input", TC_INPUT },
144 { "leftmargin", TC_LEFTMARGIN },
145 { "maxcounter", TC_MAXCOUNTER },
146 { "nofloat", TC_NOFLOAT },
147 { "nostyle", TC_NOSTYLE },
148 { "outputtype", TC_OUTPUTTYPE },
149 { "pagestyle", TC_PAGESTYLE },
150 { "preamble", TC_PREAMBLE },
151 { "providesamsmath", TC_PROVIDESAMSMATH },
152 { "providesmakeidx", TC_PROVIDESMAKEIDX },
153 { "providesnatbib", TC_PROVIDESNATBIB },
154 { "providesurl", TC_PROVIDESURL },
155 { "rightmargin", TC_RIGHTMARGIN },
156 { "secnumdepth", TC_SECNUMDEPTH },
157 { "sides", TC_SIDES },
158 { "style", TC_STYLE },
159 { "titlelatexname", TC_TITLELATEXNAME },
160 { "titlelatextype", TC_TITLELATEXTYPE },
161 { "tocdepth", TC_TOCDEPTH }
165 lyxerr[Debug::TCLASS] << "Reading textclass "
166 << MakeDisplayPath(filename)
169 lyxerr[Debug::TCLASS] << "Reading input file "
170 << MakeDisplayPath(filename)
173 LyXLex lexrc(textClassTags,
174 sizeof(textClassTags) / sizeof(textClassTags[0]));
177 lexrc.setFile(filename);
178 if (!lexrc.isOK()) error = true;
181 while (lexrc.isOK() && !error) {
182 int le = lexrc.lex();
185 case LyXLex::LEX_FEOF:
188 case LyXLex::LEX_UNDEF:
189 lexrc.printError("Unknown TextClass tag `$$Token'");
197 switch (static_cast<TextClassTags>(le)) {
199 case TC_OUTPUTTYPE: // output type definition
200 readOutputType(lexrc);
203 case TC_INPUT: // Include file
205 string tmp = LibFileSearch("layouts",
209 if (Read(tmp, true)) {
210 lexrc.printError("Error reading input"
217 case TC_DEFAULTSTYLE:
219 string const name = subst(lexrc.getString(),
221 defaultlayout_ = name;
228 string const name = subst(lexrc.getString(),
230 if (hasLayout(name)) {
231 LyXLayout * lay = operator[](name).get();
232 error = do_readStyle(lexrc, *lay);
236 if (le == TC_ENVIRONMENT)
237 lay.is_environment = true;
238 if (!(error = do_readStyle(lexrc, lay)))
239 layoutlist_.push_back
240 (boost::shared_ptr<LyXLayout>(new LyXLayout(lay)));
241 if (defaultlayout_.empty()) {
242 // We do not have a default
243 // layout yet, so we choose
244 // the first layout we
246 defaultlayout_ = name;
251 lexrc.printError("No name given for style: `$$Token'.");
258 string const style = subst(lexrc.getString(),
260 if (!delete_layout(style))
261 lyxerr << "Cannot delete style `"
262 << style << '\'' << endl;
263 // lexrc.printError("Cannot delete style"
270 columns_ = lexrc.getInteger();
275 switch (lexrc.getInteger()) {
276 case 1: sides_ = OneSide; break;
277 case 2: sides_ = TwoSides; break;
279 lyxerr << "Impossible number of page"
280 " sides, setting to one."
290 pagestyle_ = rtrim(lexrc.getString());
294 defaultfont_.lyxRead(lexrc);
295 if (!defaultfont_.resolved()) {
296 lexrc.printError("Warning: defaultfont should "
297 "be fully instantiated!");
298 defaultfont_.realize(LyXFont(LyXFont::ALL_SANE));
304 maxcounter_ = lexrc.getInteger();
309 secnumdepth_ = lexrc.getInteger();
314 tocdepth_ = lexrc.getInteger();
317 // First step to support options
318 case TC_CLASSOPTIONS:
319 readClassOptions(lexrc);
323 preamble_ = lexrc.getLongString("EndPreamble");
326 case TC_PROVIDESAMSMATH:
327 if (lexrc.next() && lexrc.getInteger())
328 provides_ |= amsmath;
331 case TC_PROVIDESNATBIB:
332 if (lexrc.next() && lexrc.getInteger())
336 case TC_PROVIDESMAKEIDX:
337 if (lexrc.next() && lexrc.getInteger())
338 provides_ |= makeidx;
342 if (lexrc.next() && lexrc.getInteger())
346 case TC_LEFTMARGIN: // left margin type
348 leftmargin_ = lexrc.getString();
351 case TC_RIGHTMARGIN: // right margin type
353 rightmargin_ = lexrc.getString();
361 case TC_TITLELATEXTYPE:
362 readTitleType(lexrc);
364 case TC_TITLELATEXNAME:
366 titlename_ = lexrc.getString();
370 string const nofloat = lexrc.getString();
371 floatlist_->erase(nofloat);
377 if (!merge) { // we are at top level here.
378 lyxerr[Debug::TCLASS] << "Finished reading textclass "
379 << MakeDisplayPath(filename)
381 if (defaultlayout_.empty()) {
382 lyxerr << "Error: Textclass '" << name_
383 << "' is missing a defaultstyle." << endl;
387 lyxerr[Debug::TCLASS] << "Finished reading input file "
388 << MakeDisplayPath(filename)
395 void LyXTextClass::readTitleType(LyXLex & lexrc)
397 keyword_item titleTypeTags[] = {
398 { "commandafter", TITLE_COMMAND_AFTER },
399 { "environment", TITLE_ENVIRONMENT }
402 pushpophelper pph(lexrc, titleTypeTags, TITLE_ENVIRONMENT);
404 int le = lexrc.lex();
406 case LyXLex::LEX_UNDEF:
407 lexrc.printError("Unknown output type `$$Token'");
409 case TITLE_COMMAND_AFTER:
410 case TITLE_ENVIRONMENT:
411 titletype_ = static_cast<LYX_TITLE_LATEX_TYPES>(le);
414 lyxerr << "Unhandled value " << le
415 << " in LyXTextClass::readTitleType." << endl;
422 void LyXTextClass::readOutputType(LyXLex & lexrc)
424 keyword_item outputTypeTags[] = {
425 { "docbook", DOCBOOK },
427 { "linuxdoc", LINUXDOC },
428 { "literate", LITERATE }
431 pushpophelper pph(lexrc, outputTypeTags, LITERATE);
433 int le = lexrc.lex();
435 case LyXLex::LEX_UNDEF:
436 lexrc.printError("Unknown output type `$$Token'");
442 outputType_ = static_cast<OutputType>(le);
445 lyxerr << "Unhandled value " << le
446 << " in LyXTextClass::readOutputType." << endl;
453 enum MaxCounterTags {
454 MC_COUNTER_CHAPTER = 1,
456 MC_COUNTER_SUBSECTION,
457 MC_COUNTER_SUBSUBSECTION,
458 MC_COUNTER_PARAGRAPH,
459 MC_COUNTER_SUBPARAGRAPH,
467 enum ClassOptionsTags {
475 void LyXTextClass::readClassOptions(LyXLex & lexrc)
477 keyword_item classOptionsTags[] = {
479 {"fontsize", CO_FONTSIZE },
480 {"other", CO_OTHER },
481 {"pagestyle", CO_PAGESTYLE }
484 lexrc.pushTable(classOptionsTags, CO_END);
486 while (!getout && lexrc.isOK()) {
487 int le = lexrc.lex();
489 case LyXLex::LEX_UNDEF:
490 lexrc.printError("Unknown ClassOption tag `$$Token'");
494 switch (static_cast<ClassOptionsTags>(le)) {
497 opt_fontsize_ = rtrim(lexrc.getString());
501 opt_pagestyle_ = rtrim(lexrc.getString());
505 options_ = lexrc.getString();
528 void LyXTextClass::readFloat(LyXLex & lexrc)
530 keyword_item floatTags[] = {
532 { "extension", FT_EXT },
533 { "guiname", FT_NAME },
534 { "latexbuiltin", FT_BUILTIN },
535 { "listname", FT_LISTNAME },
536 { "numberwithin", FT_WITHIN },
537 { "placement", FT_PLACEMENT },
538 { "style", FT_STYLE },
542 lexrc.pushTable(floatTags, FT_END);
551 bool builtin = false;
554 while (!getout && lexrc.isOK()) {
555 int le = lexrc.lex();
557 case LyXLex::LEX_UNDEF:
558 lexrc.printError("Unknown ClassOption tag `$$Token'");
562 switch (static_cast<FloatTags>(le)) {
565 type = lexrc.getString();
566 // Here we could check if this type is already defined
567 // and modify it with the rest of the vars instead.
571 name = lexrc.getString();
575 placement = lexrc.getString();
579 ext = lexrc.getString();
583 within = lexrc.getString();
584 if (within == "none")
589 style = lexrc.getString();
593 listname = lexrc.getString();
597 builtin = lexrc.getBool();
605 // Here if have a full float if getout == true
607 Floating newfloat(type, placement, ext, within,
608 style, name, listname, builtin);
609 floatlist_->newFloat(newfloat);
622 void LyXTextClass::readCounter(LyXLex & lexrc)
624 keyword_item counterTags[] = {
627 { "within", CT_WITHIN }
630 lexrc.pushTable(counterTags, CT_END);
636 while (!getout && lexrc.isOK()) {
637 int le = lexrc.lex();
639 case LyXLex::LEX_UNDEF:
640 lexrc.printError("Unknown ClassOption tag `$$Token'");
644 switch (static_cast<CounterTags>(le)) {
647 name = lexrc.getString();
651 within = lexrc.getString();
652 if (within == "none")
661 // Here if have a full counter if getout == true
663 if (within.empty()) {
664 ctrs_->newCounter(name);
666 ctrs_->newCounter(name, within);
674 LyXFont const & LyXTextClass::defaultfont() const
680 string const & LyXTextClass::leftmargin() const
686 string const & LyXTextClass::rightmargin() const
692 bool LyXTextClass::hasLayout(string const & n) const
694 string const name = (n.empty() ? defaultLayoutName() : n);
696 return find_if(layoutlist_.begin(), layoutlist_.end(),
698 != layoutlist_.end();
703 LyXLayout_ptr const & LyXTextClass::operator[](string const & name) const
705 BOOST_ASSERT(!name.empty());
707 LayoutList::const_iterator cit =
708 find_if(layoutlist_.begin(),
712 if (cit == layoutlist_.end()) {
713 lyxerr << "We failed to find the layout '" << name
714 << "' in the layout list. You MUST investigate!"
716 for (LayoutList::const_iterator it = layoutlist_.begin();
717 it != layoutlist_.end(); ++it)
718 lyxerr << " " << it->get()->name() << endl;
720 // we require the name to exist
729 bool LyXTextClass::delete_layout(string const & name)
731 if (name == defaultLayoutName())
734 LayoutList::iterator it =
735 remove_if(layoutlist_.begin(), layoutlist_.end(),
738 LayoutList::iterator end = layoutlist_.end();
739 bool const ret = (it != end);
740 layoutlist_.erase(it, end);
745 // Load textclass info if not loaded yet
746 bool LyXTextClass::load() const
752 string const real_file = LibFileSearch("layouts", name_, "layout");
754 if (const_cast<LyXTextClass*>(this)->Read(real_file)) {
755 lyxerr << "Error reading `"
756 << MakeDisplayPath(real_file)
757 << "'\n(Check `" << name_
758 << "')\nCheck your installation and "
759 "try Options/Reconfigure..." << endl;
767 FloatList & LyXTextClass::floats()
769 return *floatlist_.get();
773 FloatList const & LyXTextClass::floats() const
775 return *floatlist_.get();
779 Counters & LyXTextClass::counters() const
785 string const & LyXTextClass::defaultLayoutName() const
787 // This really should come from the actual layout... (Lgb)
788 return defaultlayout_;
792 LyXLayout_ptr const & LyXTextClass::defaultLayout() const
794 return operator[](defaultLayoutName());
798 string const & LyXTextClass::name() const
804 string const & LyXTextClass::latexname() const
806 const_cast<LyXTextClass*>(this)->load();
811 string const & LyXTextClass::description() const
817 string const & LyXTextClass::opt_fontsize() const
819 return opt_fontsize_;
823 string const & LyXTextClass::opt_pagestyle() const
825 return opt_pagestyle_;
829 string const & LyXTextClass::options() const
835 string const & LyXTextClass::pagestyle() const
841 string const & LyXTextClass::preamble() const
847 LyXTextClass::PageSides LyXTextClass::sides() const
853 int LyXTextClass::secnumdepth() const
859 int LyXTextClass::tocdepth() const
865 OutputType LyXTextClass::outputType() const
871 bool LyXTextClass::provides(LyXTextClass::Provides p) const
873 return provides_ & p;
877 unsigned int LyXTextClass::columns() const
883 int LyXTextClass::maxcounter() const
889 LYX_TITLE_LATEX_TYPES LyXTextClass::titletype() const
895 string const & LyXTextClass::titlename() const
904 int LyXTextClass::size() const
906 return layoutlist_.size();
910 ostream & operator<<(ostream & os, LyXTextClass::PageSides p)
913 case LyXTextClass::OneSide:
916 case LyXTextClass::TwoSides: