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 "TextClass.h"
19 #include "LayoutFile.h"
23 #include "FloatList.h"
27 #include "ModuleList.h"
29 #include "frontends/alert.h"
31 #include "support/lassert.h"
32 #include "support/debug.h"
33 #include "support/ExceptionMessage.h"
34 #include "support/FileName.h"
35 #include "support/filetools.h"
36 #include "support/gettext.h"
37 #include "support/lstrings.h"
38 #include "support/os.h"
49 using namespace lyx::support;
55 class LayoutNamesEqual : public unary_function<Layout, bool> {
57 LayoutNamesEqual(docstring const & name)
60 bool operator()(Layout const & c) const
62 return c.name() == name_;
68 // Keep the changes documented in the Customization manual.
69 int const FORMAT = 26;
72 bool layout2layout(FileName const & filename, FileName const & tempfile)
74 FileName const script = libFileSearch("scripts", "layout2layout.py");
76 LYXERR0("Could not find layout conversion "
77 "script layout2layout.py.");
81 ostringstream command;
82 command << os::python() << ' ' << quoteName(script.toFilesystemEncoding())
83 << ' ' << quoteName(filename.toFilesystemEncoding())
84 << ' ' << quoteName(tempfile.toFilesystemEncoding());
85 string const command_str = command.str();
87 LYXERR(Debug::TCLASS, "Running `" << command_str << '\'');
89 cmd_ret const ret = runCommand(command_str);
91 LYXERR0("Could not run layout conversion script layout2layout.py.");
98 string translateRT(TextClass::ReadType rt)
101 case TextClass::BASECLASS:
103 case TextClass::MERGE:
105 case TextClass::MODULE:
106 return "module file";
107 case TextClass::VALIDATION:
117 // This string should not be translated here,
118 // because it is a layout identifier.
119 docstring const TextClass::plain_layout_ = from_ascii("Plain Layout");
122 InsetLayout DocumentClass::plain_insetlayout_;
125 /////////////////////////////////////////////////////////////////////////
129 /////////////////////////////////////////////////////////////////////////
131 TextClass::TextClass()
134 outputFormat_ = "latex";
139 pagestyle_ = "default";
140 defaultfont_ = sane_font;
141 opt_fontsize_ = "10|11|12";
142 opt_pagestyle_ = "empty|plain|headings|fancy";
143 titletype_ = TITLE_COMMAND_AFTER;
144 titlename_ = "maketitle";
146 _("Plain Layout"); // a hack to make this translatable
150 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
152 LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
153 if (!lay.read(lexrc, *this)) {
154 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
158 lay.resfont = lay.font;
159 lay.resfont.realize(defaultfont_);
160 lay.reslabelfont = lay.labelfont;
161 lay.reslabelfont.realize(defaultfont_);
162 return true; // no errors
196 TC_ADDTOHTMLPREAMBLE,
207 LexerKeyword textClassTags[] = {
208 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
209 { "addtopreamble", TC_ADDTOPREAMBLE },
210 { "citeformat", TC_CITEFORMAT },
211 { "classoptions", TC_CLASSOPTIONS },
212 { "columns", TC_COLUMNS },
213 { "counter", TC_COUNTER },
214 { "defaultfont", TC_DEFAULTFONT },
215 { "defaultmodule", TC_DEFAULTMODULE },
216 { "defaultstyle", TC_DEFAULTSTYLE },
217 { "excludesmodule", TC_EXCLUDESMODULE },
218 { "float", TC_FLOAT },
219 { "format", TC_FORMAT },
220 { "htmlpreamble", TC_HTMLPREAMBLE },
221 { "htmltocsection", TC_HTMLTOCSECTION },
222 { "ifcounter", TC_IFCOUNTER },
223 { "ifstyle", TC_IFSTYLE },
224 { "input", TC_INPUT },
225 { "insetlayout", TC_INSETLAYOUT },
226 { "leftmargin", TC_LEFTMARGIN },
227 { "nofloat", TC_NOFLOAT },
228 { "nostyle", TC_NOSTYLE },
229 { "outputformat", TC_OUTPUTFORMAT },
230 { "outputtype", TC_OUTPUTTYPE },
231 { "pagestyle", TC_PAGESTYLE },
232 { "preamble", TC_PREAMBLE },
233 { "provides", TC_PROVIDES },
234 { "providesmodule", TC_PROVIDESMODULE },
235 { "requires", TC_REQUIRES },
236 { "rightmargin", TC_RIGHTMARGIN },
237 { "secnumdepth", TC_SECNUMDEPTH },
238 { "sides", TC_SIDES },
239 { "style", TC_STYLE },
240 { "titlelatexname", TC_TITLELATEXNAME },
241 { "titlelatextype", TC_TITLELATEXTYPE },
242 { "tocdepth", TC_TOCDEPTH }
248 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
250 LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
251 FileName const tempfile = FileName::tempName("convert_layout");
252 bool success = layout2layout(filename, tempfile);
254 success = readWithoutConv(tempfile, rt) == OK;
255 tempfile.removeFile();
260 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
262 if (!filename.isReadableFile()) {
263 lyxerr << "Cannot read layout file `" << filename << "'."
268 LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
269 to_utf8(makeDisplayPath(filename.absFilename())));
271 // Define the plain layout used in table cells, ert, etc. Note that
272 // we do this before loading any layout file, so that classes can
273 // override features of this layout if they should choose to do so.
274 if (rt == BASECLASS && !hasLayout(plain_layout_))
275 layoutlist_.push_back(createBasicLayout(plain_layout_));
277 Lexer lexrc(textClassTags);
278 lexrc.setFile(filename);
279 ReturnValues retval = read(lexrc, rt);
281 LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
282 to_utf8(makeDisplayPath(filename.absFilename())));
288 bool TextClass::read(FileName const & filename, ReadType rt)
290 ReturnValues const retval = readWithoutConv(filename, rt);
291 if (retval != FORMAT_MISMATCH)
294 bool const worx = convertLayoutFormat(filename, rt);
296 LYXERR0 ("Unable to convert " << filename <<
297 " to format " << FORMAT);
304 bool TextClass::validate(std::string const & str)
307 return tc.read(str, VALIDATION);
311 bool TextClass::read(std::string const & str, ReadType rt)
313 Lexer lexrc(textClassTags);
314 istringstream is(str);
316 ReturnValues retval = read(lexrc, rt);
318 if (retval != FORMAT_MISMATCH)
321 // write the layout string to a temporary file
322 FileName const tempfile = FileName::tempName("TextClass_read");
323 ofstream os(tempfile.toFilesystemEncoding().c_str());
325 LYXERR0("Unable to create temporary file");
331 // now try to convert it
332 bool const worx = convertLayoutFormat(tempfile, rt);
334 LYXERR0("Unable to convert internal layout information to format "
337 tempfile.removeFile();
342 // Reads a textclass structure from file.
343 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
345 bool error = !lexrc.isOK();
347 // Format of files before the 'Format' tag was introduced
351 while (lexrc.isOK() && !error) {
352 int le = lexrc.lex();
355 case Lexer::LEX_FEOF:
358 case Lexer::LEX_UNDEF:
359 lexrc.printError("Unknown TextClass tag `$$Token'");
367 // used below to track whether we are in an IfStyle or IfCounter tag.
368 bool ifstyle = false;
369 bool ifcounter = false;
371 switch (static_cast<TextClassTags>(le)) {
375 format = lexrc.getInteger();
378 case TC_OUTPUTFORMAT:
380 outputFormat_ = lexrc.getString();
384 readOutputType(lexrc);
385 switch(outputType_) {
387 outputFormat_ = "latex";
390 outputFormat_ = "docbook";
393 outputFormat_ = "literate";
398 case TC_INPUT: // Include file
400 string const inc = lexrc.getString();
401 FileName tmp = libFileSearch("layouts", inc,
405 lexrc.printError("Could not find input file: " + inc);
407 } else if (!read(tmp, MERGE)) {
408 lexrc.printError("Error reading input"
409 "file: " + tmp.absFilename());
415 case TC_DEFAULTSTYLE:
417 docstring const name = from_utf8(subst(lexrc.getString(),
419 defaultlayout_ = name;
428 lexrc.printError("No name given for style: `$$Token'.");
432 docstring const name = from_utf8(subst(lexrc.getString(),
435 string s = "Could not read name for style: `$$Token' "
436 + lexrc.getString() + " is probably not valid UTF-8!";
437 lexrc.printError(s.c_str());
439 // Since we couldn't read the name, we just scan the rest
440 // of the style and discard it.
441 error = !readStyle(lexrc, lay);
442 } else if (hasLayout(name)) {
443 Layout & lay = operator[](name);
444 error = !readStyle(lexrc, lay);
445 } else if (!ifstyle) {
447 layout.setName(name);
448 error = !readStyle(lexrc, layout);
450 layoutlist_.push_back(layout);
452 if (defaultlayout_.empty()) {
453 // We do not have a default layout yet, so we choose
454 // the first layout we encounter.
455 defaultlayout_ = name;
459 // scan the rest and discard it
461 readStyle(lexrc, lay);
472 docstring const style = from_utf8(subst(lexrc.getString(),
474 if (!deleteLayout(style))
475 lyxerr << "Cannot delete style `"
476 << to_utf8(style) << '\'' << endl;
482 columns_ = lexrc.getInteger();
487 switch (lexrc.getInteger()) {
488 case 1: sides_ = OneSide; break;
489 case 2: sides_ = TwoSides; break;
491 lyxerr << "Impossible number of page"
492 " sides, setting to one."
502 pagestyle_ = rtrim(lexrc.getString());
506 defaultfont_ = lyxRead(lexrc);
507 if (!defaultfont_.resolved()) {
508 lexrc.printError("Warning: defaultfont should "
509 "be fully instantiated!");
510 defaultfont_.realize(sane_font);
516 secnumdepth_ = lexrc.getInteger();
521 tocdepth_ = lexrc.getInteger();
524 // First step to support options
525 case TC_CLASSOPTIONS:
526 readClassOptions(lexrc);
530 preamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
533 case TC_HTMLPREAMBLE:
534 htmlpreamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
537 case TC_HTMLTOCSECTION:
538 html_toc_section_ = from_utf8(trim(lexrc.getString()));
541 case TC_ADDTOPREAMBLE:
542 preamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
545 case TC_ADDTOHTMLPREAMBLE:
546 htmlpreamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
551 string const feature = lexrc.getString();
553 if (lexrc.getInteger())
554 provides_.insert(feature);
556 provides_.erase(feature);
562 vector<string> const req
563 = getVectorFromString(lexrc.getString());
564 requires_.insert(req.begin(), req.end());
568 case TC_DEFAULTMODULE: {
570 string const module = lexrc.getString();
571 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
572 default_modules_.push_back(module);
576 case TC_PROVIDESMODULE: {
578 string const module = lexrc.getString();
579 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
580 provided_modules_.push_back(module);
584 case TC_EXCLUDESMODULE: {
586 string const module = lexrc.getString();
587 // modules already have their own way to exclude other modules
589 LYXERR0("ExcludesModule tag cannot be used in a module!");
592 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
593 excluded_modules_.push_back(module);
597 case TC_LEFTMARGIN: // left margin type
599 leftmargin_ = lexrc.getDocString();
602 case TC_RIGHTMARGIN: // right margin type
604 rightmargin_ = lexrc.getDocString();
607 case TC_INSETLAYOUT: {
609 lexrc.printError("No name given for InsetLayout: `$$Token'.");
613 docstring const name = subst(lexrc.getDocString(), '_', ' ');
615 string s = "Could not read name for InsetLayout: `$$Token' "
616 + lexrc.getString() + " is probably not valid UTF-8!";
617 lexrc.printError(s.c_str());
619 // Since we couldn't read the name, we just scan the rest
620 // of the style and discard it.
621 il.read(lexrc, *this);
623 } else if (hasInsetLayout(name)) {
624 InsetLayout & il = insetlayoutlist_[name];
625 error = !il.read(lexrc, *this);
629 error = !il.read(lexrc, *this);
631 insetlayoutlist_[name] = il;
641 readCiteFormat(lexrc);
648 docstring const name = lexrc.getDocString();
650 string s = "Could not read name for counter: `$$Token' "
651 + lexrc.getString() + " is probably not valid UTF-8!";
652 lexrc.printError(s.c_str());
654 // Since we couldn't read the name, we just scan the rest
658 error = !counters_.read(lexrc, name, !ifcounter);
661 lexrc.printError("No name given for style: `$$Token'.");
668 case TC_TITLELATEXTYPE:
669 readTitleType(lexrc);
672 case TC_TITLELATEXNAME:
674 titlename_ = lexrc.getString();
679 string const nofloat = lexrc.getString();
680 floatlist_.erase(nofloat);
685 //Note that this is triggered the first time through the loop unless
686 //we hit a format tag.
687 if (format != FORMAT)
691 if (format != FORMAT)
692 return FORMAT_MISMATCH;
695 return (error ? ERROR : OK);
697 if (defaultlayout_.empty()) {
698 LYXERR0("Error: Textclass '" << name_
699 << "' is missing a defaultstyle.");
703 // Try to erase "stdinsets" from the provides_ set.
705 // Provides stdinsets 1
706 // declaration simply tells us that the standard insets have been
707 // defined. (It's found in stdinsets.inc but could also be used in
708 // user-defined files.) There isn't really any such package. So we
709 // might as well go ahead and erase it.
710 // If we do not succeed, then it was not there, which means that
711 // the textclass did not provide the definitions of the standard
712 // insets. So we need to try to load them.
713 int erased = provides_.erase("stdinsets");
715 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
718 throw ExceptionMessage(WarningException, _("Missing File"),
719 _("Could not find stdinsets.inc! This may lead to data loss!"));
721 } else if (!read(tmp, MERGE)) {
722 throw ExceptionMessage(WarningException, _("Corrupt File"),
723 _("Could not read stdinsets.inc! This may lead to data loss!"));
728 min_toclevel_ = Layout::NOT_IN_TOC;
729 max_toclevel_ = Layout::NOT_IN_TOC;
730 const_iterator lit = begin();
731 const_iterator len = end();
732 for (; lit != len; ++lit) {
733 int const toclevel = lit->toclevel;
734 if (toclevel != Layout::NOT_IN_TOC) {
735 if (min_toclevel_ == Layout::NOT_IN_TOC)
736 min_toclevel_ = toclevel;
738 min_toclevel_ = min(min_toclevel_, toclevel);
739 max_toclevel_ = max(max_toclevel_, toclevel);
742 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
743 << ", maximum is " << max_toclevel_);
745 return (error ? ERROR : OK);
749 void TextClass::readTitleType(Lexer & lexrc)
751 LexerKeyword titleTypeTags[] = {
752 { "commandafter", TITLE_COMMAND_AFTER },
753 { "environment", TITLE_ENVIRONMENT }
756 PushPopHelper pph(lexrc, titleTypeTags);
758 int le = lexrc.lex();
760 case Lexer::LEX_UNDEF:
761 lexrc.printError("Unknown output type `$$Token'");
763 case TITLE_COMMAND_AFTER:
764 case TITLE_ENVIRONMENT:
765 titletype_ = static_cast<TitleLatexType>(le);
768 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
774 void TextClass::readOutputType(Lexer & lexrc)
776 LexerKeyword outputTypeTags[] = {
777 { "docbook", DOCBOOK },
779 { "literate", LITERATE }
782 PushPopHelper pph(lexrc, outputTypeTags);
784 int le = lexrc.lex();
786 case Lexer::LEX_UNDEF:
787 lexrc.printError("Unknown output type `$$Token'");
792 outputType_ = static_cast<OutputType>(le);
795 LYXERR0("Unhandled value " << le);
801 void TextClass::readClassOptions(Lexer & lexrc)
811 LexerKeyword classOptionsTags[] = {
813 {"fontsize", CO_FONTSIZE },
814 {"header", CO_HEADER },
815 {"other", CO_OTHER },
816 {"pagestyle", CO_PAGESTYLE }
819 lexrc.pushTable(classOptionsTags);
821 while (!getout && lexrc.isOK()) {
822 int le = lexrc.lex();
824 case Lexer::LEX_UNDEF:
825 lexrc.printError("Unknown ClassOption tag `$$Token'");
832 opt_fontsize_ = rtrim(lexrc.getString());
836 opt_pagestyle_ = rtrim(lexrc.getString());
840 if (options_.empty())
841 options_ = lexrc.getString();
843 options_ += ',' + lexrc.getString();
847 class_header_ = subst(lexrc.getString(), """, "\"");
858 void TextClass::readCiteFormat(Lexer & lexrc)
862 while (lexrc.isOK()) {
864 etype = lexrc.getString();
865 if (!lexrc.isOK() || compare_ascii_no_case(etype, "end") == 0)
868 definition = lexrc.getString();
869 char initchar = etype[0];
872 if (initchar == '!' || initchar == '_')
873 cite_macros_[etype] = definition;
875 cite_formats_[etype] = definition;
880 void TextClass::readFloat(Lexer & lexrc)
899 LexerKeyword floatTags[] = {
901 { "extension", FT_EXT },
902 { "guiname", FT_NAME },
903 { "htmlattr", FT_HTMLATTR },
904 { "htmlstyle", FT_HTMLSTYLE },
905 { "htmltag", FT_HTMLTAG },
906 { "listcommand", FT_LISTCOMMAND },
907 { "listname", FT_LISTNAME },
908 { "needsfloatpkg", FT_NEEDSFLOAT },
909 { "numberwithin", FT_WITHIN },
910 { "placement", FT_PLACEMENT },
911 { "refprefix", FT_REFPREFIX },
912 { "style", FT_STYLE },
916 lexrc.pushTable(floatTags);
930 bool needsfloat = true;
933 while (!getout && lexrc.isOK()) {
934 int le = lexrc.lex();
936 case Lexer::LEX_UNDEF:
937 lexrc.printError("Unknown float tag `$$Token'");
944 type = lexrc.getString();
945 if (floatlist_.typeExist(type)) {
946 Floating const & fl = floatlist_.getType(type);
947 placement = fl.placement();
949 within = fl.within();
952 listname = fl.listName();
953 needsfloat = fl.needsFloatPkg();
954 listcommand = fl.listCommand();
955 refprefix = fl.refPrefix();
960 name = lexrc.getString();
964 placement = lexrc.getString();
968 ext = lexrc.getString();
972 within = lexrc.getString();
973 if (within == "none")
978 style = lexrc.getString();
982 listcommand = lexrc.getString();
986 refprefix = lexrc.getString();
990 listname = lexrc.getString();
994 needsfloat = lexrc.getBool();
998 htmlattr = lexrc.getString();
1002 htmlstyle = lexrc.getLongString("EndHTMLStyle");
1006 htmltag = lexrc.getString();
1014 // Here we have a full float if getout == true
1016 if (!needsfloat && listcommand.empty())
1017 LYXERR0("The layout does not provide a list command " <<
1018 "for the builtin float `" << type << "'. LyX will " <<
1019 "not be able to produce a float list.");
1020 Floating fl(type, placement, ext, within, style, name,
1021 listname, listcommand, refprefix,
1022 htmltag, htmlattr, htmlstyle, needsfloat);
1023 floatlist_.newFloat(fl);
1024 // each float has its own counter
1025 counters_.newCounter(from_ascii(type), from_ascii(within),
1026 docstring(), docstring());
1027 // also define sub-float counters
1028 docstring const subtype = "sub-" + from_ascii(type);
1029 counters_.newCounter(subtype, from_ascii(type),
1030 "\\alph{" + subtype + "}", docstring());
1037 string const & TextClass::prerequisites() const
1039 if (contains(prerequisites_, ',')) {
1040 vector<string> const pres = getVectorFromString(prerequisites_);
1041 prerequisites_ = getStringFromVector(pres, "\n\t");
1043 return prerequisites_;
1046 bool TextClass::hasLayout(docstring const & n) const
1048 docstring const name = n.empty() ? defaultLayoutName() : n;
1050 return find_if(layoutlist_.begin(), layoutlist_.end(),
1051 LayoutNamesEqual(name))
1052 != layoutlist_.end();
1056 bool TextClass::hasInsetLayout(docstring const & n) const
1060 InsetLayouts::const_iterator it = insetlayoutlist_.begin();
1061 InsetLayouts::const_iterator en = insetlayoutlist_.end();
1062 for (; it != en; ++it)
1069 Layout const & TextClass::operator[](docstring const & name) const
1071 LASSERT(!name.empty(), /**/);
1074 find_if(begin(), end(), LayoutNamesEqual(name));
1077 lyxerr << "We failed to find the layout '" << to_utf8(name)
1078 << "' in the layout list. You MUST investigate!"
1080 for (const_iterator cit = begin(); cit != end(); ++cit)
1081 lyxerr << " " << to_utf8(cit->name()) << endl;
1083 // we require the name to exist
1084 LASSERT(false, /**/);
1091 Layout & TextClass::operator[](docstring const & name)
1093 LASSERT(!name.empty(), /**/);
1095 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1098 LYXERR0("We failed to find the layout '" << to_utf8(name)
1099 << "' in the layout list. You MUST investigate!");
1100 for (const_iterator cit = begin(); cit != end(); ++cit)
1101 LYXERR0(" " << to_utf8(cit->name()));
1103 // we require the name to exist
1104 LASSERT(false, /**/);
1111 bool TextClass::deleteLayout(docstring const & name)
1113 if (name == defaultLayoutName() || name == plainLayoutName())
1116 LayoutList::iterator it =
1117 remove_if(layoutlist_.begin(), layoutlist_.end(),
1118 LayoutNamesEqual(name));
1120 LayoutList::iterator end = layoutlist_.end();
1121 bool const ret = (it != end);
1122 layoutlist_.erase(it, end);
1127 // Load textclass info if not loaded yet
1128 bool TextClass::load(string const & path) const
1133 // Read style-file, provided path is searched before the system ones
1134 // If path is a file, it is loaded directly.
1135 FileName layout_file(path);
1136 if (!path.empty() && !layout_file.isReadableFile())
1137 layout_file = FileName(addName(path, name_ + ".layout"));
1138 if (layout_file.empty() || !layout_file.exists())
1139 layout_file = libFileSearch("layouts", name_, "layout");
1140 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1143 lyxerr << "Error reading `"
1144 << to_utf8(makeDisplayPath(layout_file.absFilename()))
1145 << "'\n(Check `" << name_
1146 << "')\nCheck your installation and "
1147 "try Options/Reconfigure..."
1155 void DocumentClass::addLayoutIfNeeded(docstring const & n) const
1158 layoutlist_.push_back(createBasicLayout(n, true));
1162 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1164 // FIXME The fix for the InsetLayout part of 4812 would be here:
1165 // Add the InsetLayout to the document class if it is not found.
1167 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1168 while (!n.empty()) {
1169 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1170 if (cit != cen && cit->first == n)
1172 size_t i = n.find(':');
1173 if (i == string::npos)
1177 return plain_insetlayout_;
1181 docstring const & TextClass::defaultLayoutName() const
1183 // This really should come from the actual layout... (Lgb)
1184 return defaultlayout_;
1188 Layout const & TextClass::defaultLayout() const
1190 return operator[](defaultLayoutName());
1194 bool TextClass::isDefaultLayout(Layout const & layout) const
1196 return layout.name() == defaultLayoutName();
1200 bool TextClass::isPlainLayout(Layout const & layout) const
1202 return layout.name() == plainLayoutName();
1206 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1208 static Layout * defaultLayout = NULL;
1210 if (defaultLayout) {
1211 defaultLayout->setUnknown(unknown);
1212 defaultLayout->setName(name);
1213 return *defaultLayout;
1216 static char const * s = "Margin Static\n"
1217 "LatexType Paragraph\n"
1220 "AlignPossible Left, Right, Center\n"
1221 "LabelType No_Label\n"
1223 istringstream ss(s);
1224 Lexer lex(textClassTags);
1226 defaultLayout = new Layout;
1227 defaultLayout->setUnknown(unknown);
1228 defaultLayout->setName(name);
1229 if (!readStyle(lex, *defaultLayout)) {
1230 // The only way this happens is because the hardcoded layout above
1232 LASSERT(false, /**/);
1234 return *defaultLayout;
1238 /////////////////////////////////////////////////////////////////////////
1240 // DocumentClassBundle
1242 /////////////////////////////////////////////////////////////////////////
1244 DocumentClassBundle::~DocumentClassBundle()
1246 for (size_t i = 0; i != documentClasses_.size(); ++i)
1247 delete documentClasses_[i];
1248 documentClasses_.clear();
1251 DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
1253 DocumentClass * dc = new DocumentClass(baseClass);
1254 documentClasses_.push_back(dc);
1255 return *documentClasses_.back();
1259 DocumentClassBundle & DocumentClassBundle::get()
1261 static DocumentClassBundle singleton;
1266 DocumentClass & DocumentClassBundle::makeDocumentClass(
1267 LayoutFile const & baseClass, LayoutModuleList const & modlist)
1269 DocumentClass & doc_class = newClass(baseClass);
1270 LayoutModuleList::const_iterator it = modlist.begin();
1271 LayoutModuleList::const_iterator en = modlist.end();
1272 for (; it != en; it++) {
1273 string const modName = *it;
1274 LyXModule * lm = theModuleList[modName];
1276 docstring const msg =
1277 bformat(_("The module %1$s has been requested by\n"
1278 "this document but has not been found in the list of\n"
1279 "available modules. If you recently installed it, you\n"
1280 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1281 throw ExceptionMessage(WarningException,_("Module not available"),
1282 msg + _("Some layouts may not be available."));
1285 if (!lm->isAvailable()) {
1286 docstring const msg =
1287 bformat(_("The module %1$s requires a package that is\n"
1288 "not available in your LaTeX installation. LaTeX output\n"
1289 "may not be possible.\n"), from_utf8(modName));
1290 throw ExceptionMessage(WarningException, _("Package not available"), msg);
1292 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1293 if (!doc_class.read(layout_file, TextClass::MODULE)) {
1294 docstring const msg =
1295 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1296 throw ExceptionMessage(WarningException, _("Read Error"), msg);
1303 /////////////////////////////////////////////////////////////////////////
1307 /////////////////////////////////////////////////////////////////////////
1309 DocumentClass::DocumentClass(LayoutFile const & tc)
1314 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1316 LayoutList::const_iterator it = layoutlist_.begin();
1317 LayoutList::const_iterator end = layoutlist_.end();
1318 for (; it != end; ++it)
1319 if (it->latexname() == lay)
1325 bool DocumentClass::provides(string const & p) const
1327 return provides_.find(p) != provides_.end();
1331 bool DocumentClass::hasTocLevels() const
1333 return min_toclevel_ != Layout::NOT_IN_TOC;
1337 Layout const & DocumentClass::htmlTOCLayout() const
1339 if (html_toc_section_.empty()) {
1340 // we're going to look for the layout with the minimum toclevel
1341 TextClass::LayoutList::const_iterator lit = begin();
1342 TextClass::LayoutList::const_iterator const len = end();
1343 int minlevel = 1000;
1344 Layout const * lay = NULL;
1345 for (; lit != len; ++lit) {
1346 int const level = lit->toclevel;
1347 // we don't want Part
1348 if (level == Layout::NOT_IN_TOC || level < 0 || level >= minlevel)
1354 html_toc_section_ = lay->name();
1356 // hmm. that is very odd, so we'll do our best
1357 html_toc_section_ = defaultLayoutName();
1359 return operator[](html_toc_section_);
1363 string const & DocumentClass::getCiteFormat(string const & entry_type) const
1365 static string default_format = N_("{%author%[[%author%, ]][[{%editor%[[%editor%, ed., ]]}]]}\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]][[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}.");
1367 map<string, string>::const_iterator it = cite_formats_.find(entry_type);
1368 if (it != cite_formats_.end())
1370 return default_format;
1374 string const & DocumentClass::getCiteMacro(string const & macro) const
1376 static string empty;
1377 map<string, string>::const_iterator it = cite_macros_.find(macro);
1378 if (it != cite_macros_.end())
1384 /////////////////////////////////////////////////////////////////////////
1388 /////////////////////////////////////////////////////////////////////////
1390 ostream & operator<<(ostream & os, PageSides p)