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"
45 using namespace lyx::support
;
51 class LayoutNamesEqual
: public unary_function
<Layout
, bool> {
53 LayoutNamesEqual(docstring
const & name
)
56 bool operator()(Layout
const & c
) const
58 return c
.name() == name_
;
64 // Keep the changes documented in the Customization manual.
65 int const FORMAT
= 17;
68 bool layout2layout(FileName
const & filename
, FileName
const & tempfile
)
70 FileName
const script
= libFileSearch("scripts", "layout2layout.py");
72 LYXERR0("Could not find layout conversion "
73 "script layout2layout.py.");
77 ostringstream command
;
78 command
<< os::python() << ' ' << quoteName(script
.toFilesystemEncoding())
79 << ' ' << quoteName(filename
.toFilesystemEncoding())
80 << ' ' << quoteName(tempfile
.toFilesystemEncoding());
81 string
const command_str
= command
.str();
83 LYXERR(Debug::TCLASS
, "Running `" << command_str
<< '\'');
85 cmd_ret
const ret
= runCommand(command_str
);
87 LYXERR0("Could not run layout conversion script layout2layout.py.");
94 std::string
translateRT(TextClass::ReadType rt
)
97 case TextClass::BASECLASS
:
99 case TextClass::MERGE
:
101 case TextClass::MODULE
:
102 return "module file";
103 case TextClass::VALIDATION
:
113 // This string should not be translated here,
114 // because it is a layout identifier.
115 docstring
const TextClass::plain_layout_
= from_ascii("Plain Layout");
118 InsetLayout
DocumentClass::plain_insetlayout_
;
121 /////////////////////////////////////////////////////////////////////////
125 /////////////////////////////////////////////////////////////////////////
127 TextClass::TextClass()
130 outputFormat_
= "latex";
135 pagestyle_
= "default";
136 defaultfont_
= sane_font
;
137 opt_fontsize_
= "10|11|12";
138 opt_pagestyle_
= "empty|plain|headings|fancy";
139 titletype_
= TITLE_COMMAND_AFTER
;
140 titlename_
= "maketitle";
142 _("Plain Layout"); // a hack to make this translatable
146 bool TextClass::readStyle(Lexer
& lexrc
, Layout
& lay
) const
148 LYXERR(Debug::TCLASS
, "Reading style " << to_utf8(lay
.name()));
149 if (!lay
.read(lexrc
, *this)) {
150 LYXERR0("Error parsing style `" << to_utf8(lay
.name()) << '\'');
154 lay
.resfont
= lay
.font
;
155 lay
.resfont
.realize(defaultfont_
);
156 lay
.reslabelfont
= lay
.labelfont
;
157 lay
.reslabelfont
.realize(defaultfont_
);
158 return true; // no errors
192 TC_ADDTOHTMLPREAMBLE
,
201 LexerKeyword textClassTags
[] = {
202 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE
},
203 { "addtopreamble", TC_ADDTOPREAMBLE
},
204 { "classoptions", TC_CLASSOPTIONS
},
205 { "columns", TC_COLUMNS
},
206 { "counter", TC_COUNTER
},
207 { "defaultfont", TC_DEFAULTFONT
},
208 { "defaultmodule", TC_DEFAULTMODULE
},
209 { "defaultstyle", TC_DEFAULTSTYLE
},
210 { "excludesmodule", TC_EXCLUDESMODULE
},
211 { "float", TC_FLOAT
},
212 { "format", TC_FORMAT
},
213 { "htmlpreamble", TC_HTMLPREAMBLE
},
214 { "ifcounter", TC_IFCOUNTER
},
215 { "ifstyle", TC_IFSTYLE
},
216 { "input", TC_INPUT
},
217 { "insetlayout", TC_INSETLAYOUT
},
218 { "leftmargin", TC_LEFTMARGIN
},
219 { "nofloat", TC_NOFLOAT
},
220 { "nostyle", TC_NOSTYLE
},
221 { "outputformat", TC_OUTPUTFORMAT
},
222 { "outputtype", TC_OUTPUTTYPE
},
223 { "pagestyle", TC_PAGESTYLE
},
224 { "preamble", TC_PREAMBLE
},
225 { "provides", TC_PROVIDES
},
226 { "providesmodule", TC_PROVIDESMODULE
},
227 { "requires", TC_REQUIRES
},
228 { "rightmargin", TC_RIGHTMARGIN
},
229 { "secnumdepth", TC_SECNUMDEPTH
},
230 { "sides", TC_SIDES
},
231 { "style", TC_STYLE
},
232 { "titlelatexname", TC_TITLELATEXNAME
},
233 { "titlelatextype", TC_TITLELATEXTYPE
},
234 { "tocdepth", TC_TOCDEPTH
}
240 bool TextClass::convertLayoutFormat(support::FileName
const & filename
, ReadType rt
)
242 LYXERR(Debug::TCLASS
, "Converting layout file to " << FORMAT
);
243 FileName
const tempfile
= FileName::tempName("convert_layout");
244 bool success
= layout2layout(filename
, tempfile
);
246 success
= readWithoutConv(tempfile
, rt
) == OK
;
247 tempfile
.removeFile();
252 TextClass::ReturnValues
TextClass::readWithoutConv(FileName
const & filename
, ReadType rt
)
254 if (!filename
.isReadableFile()) {
255 lyxerr
<< "Cannot read layout file `" << filename
<< "'."
260 LYXERR(Debug::TCLASS
, "Reading " + translateRT(rt
) + ": " +
261 to_utf8(makeDisplayPath(filename
.absFilename())));
263 // Define the plain layout used in table cells, ert, etc. Note that
264 // we do this before loading any layout file, so that classes can
265 // override features of this layout if they should choose to do so.
266 if (rt
== BASECLASS
&& !hasLayout(plain_layout_
))
267 layoutlist_
.push_back(createBasicLayout(plain_layout_
));
269 Lexer
lexrc(textClassTags
);
270 lexrc
.setFile(filename
);
271 ReturnValues retval
= read(lexrc
, rt
);
273 LYXERR(Debug::TCLASS
, "Finished reading " + translateRT(rt
) + ": " +
274 to_utf8(makeDisplayPath(filename
.absFilename())));
280 bool TextClass::read(FileName
const & filename
, ReadType rt
)
282 ReturnValues
const retval
= readWithoutConv(filename
, rt
);
283 if (retval
!= FORMAT_MISMATCH
)
286 bool const worx
= convertLayoutFormat(filename
, rt
);
288 LYXERR0 ("Unable to convert " << filename
<<
289 " to format " << FORMAT
);
296 bool TextClass::validate(std::string
const & str
)
299 return tc
.read(str
, VALIDATION
);
303 bool TextClass::read(std::string
const & str
, ReadType rt
)
305 Lexer
lexrc(textClassTags
);
306 istringstream
is(str
);
308 ReturnValues retval
= read(lexrc
, rt
);
310 if (retval
!= FORMAT_MISMATCH
)
313 // write the layout string to a temporary file
314 FileName
const tempfile
= FileName::tempName("TextClass_read");
315 ofstream
os(tempfile
.toFilesystemEncoding().c_str());
317 LYXERR0("Unable to create temporary file");
323 // now try to convert it
324 bool const worx
= convertLayoutFormat(tempfile
, rt
);
326 LYXERR0("Unable to convert internal layout information to format "
329 tempfile
.removeFile();
334 // Reads a textclass structure from file.
335 TextClass::ReturnValues
TextClass::read(Lexer
& lexrc
, ReadType rt
)
337 bool error
= !lexrc
.isOK();
339 // Format of files before the 'Format' tag was introduced
343 while (lexrc
.isOK() && !error
) {
344 int le
= lexrc
.lex();
347 case Lexer::LEX_FEOF
:
350 case Lexer::LEX_UNDEF
:
351 lexrc
.printError("Unknown TextClass tag `$$Token'");
359 // used below to track whether we are in an IfStyle or IfCounter tag.
360 bool ifstyle
= false;
361 bool ifcounter
= false;
363 switch (static_cast<TextClassTags
>(le
)) {
367 format
= lexrc
.getInteger();
370 case TC_OUTPUTFORMAT
:
372 outputFormat_
= lexrc
.getString();
376 readOutputType(lexrc
);
377 switch(outputType_
) {
379 outputFormat_
= "latex";
382 outputFormat_
= "docbook";
385 outputFormat_
= "literate";
390 case TC_INPUT
: // Include file
392 string
const inc
= lexrc
.getString();
393 FileName tmp
= libFileSearch("layouts", inc
,
397 lexrc
.printError("Could not find input file: " + inc
);
399 } else if (!read(tmp
, MERGE
)) {
400 lexrc
.printError("Error reading input"
401 "file: " + tmp
.absFilename());
407 case TC_DEFAULTSTYLE
:
409 docstring
const name
= from_utf8(subst(lexrc
.getString(),
411 defaultlayout_
= name
;
420 lexrc
.printError("No name given for style: `$$Token'.");
424 docstring
const name
= from_utf8(subst(lexrc
.getString(),
427 string s
= "Could not read name for style: `$$Token' "
428 + lexrc
.getString() + " is probably not valid UTF-8!";
429 lexrc
.printError(s
.c_str());
431 // Since we couldn't read the name, we just scan the rest
432 // of the style and discard it.
433 error
= !readStyle(lexrc
, lay
);
434 } else if (hasLayout(name
)) {
435 Layout
& lay
= operator[](name
);
436 error
= !readStyle(lexrc
, lay
);
437 } else if (!ifstyle
) {
439 layout
.setName(name
);
440 error
= !readStyle(lexrc
, layout
);
442 layoutlist_
.push_back(layout
);
444 if (defaultlayout_
.empty()) {
445 // We do not have a default layout yet, so we choose
446 // the first layout we encounter.
447 defaultlayout_
= name
;
451 // scan the rest and discard it
453 readStyle(lexrc
, lay
);
464 docstring
const style
= from_utf8(subst(lexrc
.getString(),
466 if (!deleteLayout(style
))
467 lyxerr
<< "Cannot delete style `"
468 << to_utf8(style
) << '\'' << endl
;
474 columns_
= lexrc
.getInteger();
479 switch (lexrc
.getInteger()) {
480 case 1: sides_
= OneSide
; break;
481 case 2: sides_
= TwoSides
; break;
483 lyxerr
<< "Impossible number of page"
484 " sides, setting to one."
494 pagestyle_
= rtrim(lexrc
.getString());
498 defaultfont_
= lyxRead(lexrc
);
499 if (!defaultfont_
.resolved()) {
500 lexrc
.printError("Warning: defaultfont should "
501 "be fully instantiated!");
502 defaultfont_
.realize(sane_font
);
508 secnumdepth_
= lexrc
.getInteger();
513 tocdepth_
= lexrc
.getInteger();
516 // First step to support options
517 case TC_CLASSOPTIONS
:
518 readClassOptions(lexrc
);
522 preamble_
= from_utf8(lexrc
.getLongString("EndPreamble"));
525 case TC_HTMLPREAMBLE
:
526 htmlpreamble_
= from_utf8(lexrc
.getLongString("EndPreamble"));
529 case TC_ADDTOPREAMBLE
:
530 preamble_
+= from_utf8(lexrc
.getLongString("EndPreamble"));
533 case TC_ADDTOHTMLPREAMBLE
:
534 htmlpreamble_
+= from_utf8(lexrc
.getLongString("EndPreamble"));
539 string
const feature
= lexrc
.getString();
541 if (lexrc
.getInteger())
542 provides_
.insert(feature
);
544 provides_
.erase(feature
);
550 vector
<string
> const req
551 = getVectorFromString(lexrc
.getString());
552 requires_
.insert(req
.begin(), req
.end());
556 case TC_DEFAULTMODULE
: {
558 string
const module
= lexrc
.getString();
559 if (find(default_modules_
.begin(), default_modules_
.end(), module
) == default_modules_
.end())
560 default_modules_
.push_back(module
);
564 case TC_PROVIDESMODULE
: {
566 string
const module
= lexrc
.getString();
567 if (find(provided_modules_
.begin(), provided_modules_
.end(), module
) == provided_modules_
.end())
568 provided_modules_
.push_back(module
);
572 case TC_EXCLUDESMODULE
: {
574 string
const module
= lexrc
.getString();
575 // modules already have their own way to exclude other modules
577 LYXERR0("ExcludesModule tag cannot be used in a module!");
580 if (find(excluded_modules_
.begin(), excluded_modules_
.end(), module
) == excluded_modules_
.end())
581 excluded_modules_
.push_back(module
);
585 case TC_LEFTMARGIN
: // left margin type
587 leftmargin_
= lexrc
.getDocString();
590 case TC_RIGHTMARGIN
: // right margin type
592 rightmargin_
= lexrc
.getDocString();
595 case TC_INSETLAYOUT
: {
597 lexrc
.printError("No name given for InsetLayout: `$$Token'.");
601 docstring
const name
= subst(lexrc
.getDocString(), '_', ' ');
603 string s
= "Could not read name for InsetLayout: `$$Token' "
604 + lexrc
.getString() + " is probably not valid UTF-8!";
605 lexrc
.printError(s
.c_str());
607 // Since we couldn't read the name, we just scan the rest
608 // of the style and discard it.
609 il
.read(lexrc
, *this);
611 } else if (hasInsetLayout(name
)) {
612 InsetLayout
& il
= insetlayoutlist_
[name
];
613 error
= !il
.read(lexrc
, *this);
617 error
= !il
.read(lexrc
, *this);
619 insetlayoutlist_
[name
] = il
;
632 docstring
const name
= lexrc
.getDocString();
634 string s
= "Could not read name for counter: `$$Token' "
635 + lexrc
.getString() + " is probably not valid UTF-8!";
636 lexrc
.printError(s
.c_str());
638 // Since we couldn't read the name, we just scan the rest
642 error
= !counters_
.read(lexrc
, name
, !ifcounter
);
645 lexrc
.printError("No name given for style: `$$Token'.");
652 case TC_TITLELATEXTYPE
:
653 readTitleType(lexrc
);
656 case TC_TITLELATEXNAME
:
658 titlename_
= lexrc
.getString();
663 string
const nofloat
= lexrc
.getString();
664 floatlist_
.erase(nofloat
);
669 //Note that this is triggered the first time through the loop unless
670 //we hit a format tag.
671 if (format
!= FORMAT
)
675 if (format
!= FORMAT
)
676 return FORMAT_MISMATCH
;
679 return (error
? ERROR
: OK
);
681 if (defaultlayout_
.empty()) {
682 LYXERR0("Error: Textclass '" << name_
683 << "' is missing a defaultstyle.");
687 // Try to erase "stdinsets" from the provides_ set.
689 // Provides stdinsets 1
690 // declaration simply tells us that the standard insets have been
691 // defined. (It's found in stdinsets.inc but could also be used in
692 // user-defined files.) There isn't really any such package. So we
693 // might as well go ahead and erase it.
694 // If we do not succeed, then it was not there, which means that
695 // the textclass did not provide the definitions of the standard
696 // insets. So we need to try to load them.
697 int erased
= provides_
.erase("stdinsets");
699 FileName tmp
= libFileSearch("layouts", "stdinsets.inc");
702 throw ExceptionMessage(WarningException
, _("Missing File"),
703 _("Could not find stdinsets.inc! This may lead to data loss!"));
705 } else if (!read(tmp
, MERGE
)) {
706 throw ExceptionMessage(WarningException
, _("Corrupt File"),
707 _("Could not read stdinsets.inc! This may lead to data loss!"));
712 min_toclevel_
= Layout::NOT_IN_TOC
;
713 max_toclevel_
= Layout::NOT_IN_TOC
;
714 const_iterator lit
= begin();
715 const_iterator len
= end();
716 for (; lit
!= len
; ++lit
) {
717 int const toclevel
= lit
->toclevel
;
718 if (toclevel
!= Layout::NOT_IN_TOC
) {
719 if (min_toclevel_
== Layout::NOT_IN_TOC
)
720 min_toclevel_
= toclevel
;
722 min_toclevel_
= min(min_toclevel_
, toclevel
);
723 max_toclevel_
= max(max_toclevel_
, toclevel
);
726 LYXERR(Debug::TCLASS
, "Minimum TocLevel is " << min_toclevel_
727 << ", maximum is " << max_toclevel_
);
729 return (error
? ERROR
: OK
);
733 void TextClass::readTitleType(Lexer
& lexrc
)
735 LexerKeyword titleTypeTags
[] = {
736 { "commandafter", TITLE_COMMAND_AFTER
},
737 { "environment", TITLE_ENVIRONMENT
}
740 PushPopHelper
pph(lexrc
, titleTypeTags
);
742 int le
= lexrc
.lex();
744 case Lexer::LEX_UNDEF
:
745 lexrc
.printError("Unknown output type `$$Token'");
747 case TITLE_COMMAND_AFTER
:
748 case TITLE_ENVIRONMENT
:
749 titletype_
= static_cast<TitleLatexType
>(le
);
752 LYXERR0("Unhandled value " << le
<< " in TextClass::readTitleType.");
758 void TextClass::readOutputType(Lexer
& lexrc
)
760 LexerKeyword outputTypeTags
[] = {
761 { "docbook", DOCBOOK
},
763 { "literate", LITERATE
}
766 PushPopHelper
pph(lexrc
, outputTypeTags
);
768 int le
= lexrc
.lex();
770 case Lexer::LEX_UNDEF
:
771 lexrc
.printError("Unknown output type `$$Token'");
776 outputType_
= static_cast<OutputType
>(le
);
779 LYXERR0("Unhandled value " << le
);
785 void TextClass::readClassOptions(Lexer
& lexrc
)
795 LexerKeyword classOptionsTags
[] = {
797 {"fontsize", CO_FONTSIZE
},
798 {"header", CO_HEADER
},
799 {"other", CO_OTHER
},
800 {"pagestyle", CO_PAGESTYLE
}
803 lexrc
.pushTable(classOptionsTags
);
805 while (!getout
&& lexrc
.isOK()) {
806 int le
= lexrc
.lex();
808 case Lexer::LEX_UNDEF
:
809 lexrc
.printError("Unknown ClassOption tag `$$Token'");
816 opt_fontsize_
= rtrim(lexrc
.getString());
820 opt_pagestyle_
= rtrim(lexrc
.getString());
824 options_
= lexrc
.getString();
828 class_header_
= subst(lexrc
.getString(), """, "\"");
839 void TextClass::readFloat(Lexer
& lexrc
)
856 LexerKeyword floatTags
[] = {
858 { "extension", FT_EXT
},
859 { "guiname", FT_NAME
},
860 { "htmlclass", FT_HTMLCLASS
},
861 { "htmlstyle", FT_HTMLSTYLE
},
862 { "htmltype", FT_HTMLTYPE
},
863 { "latexbuiltin", FT_BUILTIN
},
864 { "listname", FT_LISTNAME
},
865 { "numberwithin", FT_WITHIN
},
866 { "placement", FT_PLACEMENT
},
867 { "style", FT_STYLE
},
871 lexrc
.pushTable(floatTags
);
883 bool builtin
= false;
886 while (!getout
&& lexrc
.isOK()) {
887 int le
= lexrc
.lex();
889 case Lexer::LEX_UNDEF
:
890 lexrc
.printError("Unknown float tag `$$Token'");
897 type
= lexrc
.getString();
898 if (floatlist_
.typeExist(type
)) {
899 Floating
const & fl
= floatlist_
.getType(type
);
900 placement
= fl
.placement();
902 within
= fl
.within();
905 listName
= fl
.listName();
906 builtin
= fl
.builtin();
911 name
= lexrc
.getString();
915 placement
= lexrc
.getString();
919 ext
= lexrc
.getString();
923 within
= lexrc
.getString();
924 if (within
== "none")
929 style
= lexrc
.getString();
933 listName
= lexrc
.getString();
937 builtin
= lexrc
.getBool();
941 htmlclass
= lexrc
.getString();
945 htmlstyle
= lexrc
.getLongString("EndHTMLStyle");
949 htmltype
= lexrc
.getString();
957 // Here if have a full float if getout == true
959 Floating
fl(type
, placement
, ext
, within
, style
, name
,
960 listName
, htmltype
, htmlclass
, htmlstyle
, builtin
);
961 floatlist_
.newFloat(fl
);
962 // each float has its own counter
963 counters_
.newCounter(from_ascii(type
), from_ascii(within
),
964 docstring(), docstring());
965 // also define sub-float counters
966 docstring
const subtype
= "sub-" + from_ascii(type
);
967 counters_
.newCounter(subtype
, from_ascii(type
),
968 "\\alph{" + subtype
+ "}", docstring());
975 bool TextClass::hasLayout(docstring
const & n
) const
977 docstring
const name
= n
.empty() ? defaultLayoutName() : n
;
979 return find_if(layoutlist_
.begin(), layoutlist_
.end(),
980 LayoutNamesEqual(name
))
981 != layoutlist_
.end();
985 bool TextClass::hasInsetLayout(docstring
const & n
) const
989 InsetLayouts::const_iterator it
= insetlayoutlist_
.begin();
990 InsetLayouts::const_iterator en
= insetlayoutlist_
.end();
991 for (; it
!= en
; ++it
)
998 Layout
const & TextClass::operator[](docstring
const & name
) const
1000 LASSERT(!name
.empty(), /**/);
1003 find_if(begin(), end(), LayoutNamesEqual(name
));
1006 lyxerr
<< "We failed to find the layout '" << to_utf8(name
)
1007 << "' in the layout list. You MUST investigate!"
1009 for (const_iterator cit
= begin(); cit
!= end(); ++cit
)
1010 lyxerr
<< " " << to_utf8(cit
->name()) << endl
;
1012 // we require the name to exist
1013 LASSERT(false, /**/);
1020 Layout
& TextClass::operator[](docstring
const & name
)
1022 LASSERT(!name
.empty(), /**/);
1024 iterator it
= find_if(begin(), end(), LayoutNamesEqual(name
));
1027 LYXERR0("We failed to find the layout '" << to_utf8(name
)
1028 << "' in the layout list. You MUST investigate!");
1029 for (const_iterator cit
= begin(); cit
!= end(); ++cit
)
1030 LYXERR0(" " << to_utf8(cit
->name()));
1032 // we require the name to exist
1033 LASSERT(false, /**/);
1040 bool TextClass::deleteLayout(docstring
const & name
)
1042 if (name
== defaultLayoutName() || name
== plainLayoutName())
1045 LayoutList::iterator it
=
1046 remove_if(layoutlist_
.begin(), layoutlist_
.end(),
1047 LayoutNamesEqual(name
));
1049 LayoutList::iterator end
= layoutlist_
.end();
1050 bool const ret
= (it
!= end
);
1051 layoutlist_
.erase(it
, end
);
1056 // Load textclass info if not loaded yet
1057 bool TextClass::load(string
const & path
) const
1062 // Read style-file, provided path is searched before the system ones
1063 // If path is a file, it is loaded directly.
1064 FileName
layout_file(path
);
1065 if (!path
.empty() && !layout_file
.isReadableFile())
1066 layout_file
= FileName(addName(path
, name_
+ ".layout"));
1067 if (layout_file
.empty() || !layout_file
.exists())
1068 layout_file
= libFileSearch("layouts", name_
, "layout");
1069 loaded_
= const_cast<TextClass
*>(this)->read(layout_file
);
1072 lyxerr
<< "Error reading `"
1073 << to_utf8(makeDisplayPath(layout_file
.absFilename()))
1074 << "'\n(Check `" << name_
1075 << "')\nCheck your installation and "
1076 "try Options/Reconfigure..." << endl
;
1083 void DocumentClass::addLayoutIfNeeded(docstring
const & n
) const
1086 layoutlist_
.push_back(createBasicLayout(n
, true));
1090 InsetLayout
const & DocumentClass::insetLayout(docstring
const & name
) const
1092 // FIXME The fix for the InsetLayout part of 4812 would be here:
1093 // Add the InsetLayout to the document class if it is not found.
1095 InsetLayouts::const_iterator cen
= insetlayoutlist_
.end();
1096 while (!n
.empty()) {
1097 InsetLayouts::const_iterator cit
= insetlayoutlist_
.lower_bound(n
);
1098 if (cit
!= cen
&& cit
->first
== n
)
1100 size_t i
= n
.find(':');
1101 if (i
== string::npos
)
1105 return plain_insetlayout_
;
1109 docstring
const & TextClass::defaultLayoutName() const
1111 // This really should come from the actual layout... (Lgb)
1112 return defaultlayout_
;
1116 Layout
const & TextClass::defaultLayout() const
1118 return operator[](defaultLayoutName());
1122 bool TextClass::isDefaultLayout(Layout
const & layout
) const
1124 return layout
.name() == defaultLayoutName();
1128 bool TextClass::isPlainLayout(Layout
const & layout
) const
1130 return layout
.name() == plainLayoutName();
1134 Layout
TextClass::createBasicLayout(docstring
const & name
, bool unknown
) const
1136 static Layout
* defaultLayout
= NULL
;
1138 if (defaultLayout
) {
1139 defaultLayout
->setUnknown(unknown
);
1140 defaultLayout
->setName(name
);
1141 return *defaultLayout
;
1144 static char const * s
= "Margin Static\n"
1145 "LatexType Paragraph\n"
1148 "AlignPossible Left, Right, Center\n"
1149 "LabelType No_Label\n"
1151 istringstream
ss(s
);
1152 Lexer
lex(textClassTags
);
1154 defaultLayout
= new Layout
;
1155 defaultLayout
->setUnknown(unknown
);
1156 defaultLayout
->setName(name
);
1157 if (!readStyle(lex
, *defaultLayout
)) {
1158 // The only way this happens is because the hardcoded layout above
1160 LASSERT(false, /**/);
1162 return *defaultLayout
;
1165 /////////////////////////////////////////////////////////////////////////
1167 // DocumentClassBundle
1169 /////////////////////////////////////////////////////////////////////////
1171 DocumentClassBundle::~DocumentClassBundle()
1173 for (size_t i
= 0; i
!= documentClasses_
.size(); ++i
)
1174 delete documentClasses_
[i
];
1175 documentClasses_
.clear();
1178 DocumentClass
& DocumentClassBundle::newClass(LayoutFile
const & baseClass
)
1180 DocumentClass
* dc
= new DocumentClass(baseClass
);
1181 documentClasses_
.push_back(dc
);
1182 return *documentClasses_
.back();
1186 DocumentClassBundle
& DocumentClassBundle::get()
1188 static DocumentClassBundle singleton
;
1193 DocumentClass
& DocumentClassBundle::makeDocumentClass(
1194 LayoutFile
const & baseClass
, LayoutModuleList
const & modlist
)
1196 DocumentClass
& doc_class
= newClass(baseClass
);
1197 LayoutModuleList::const_iterator it
= modlist
.begin();
1198 LayoutModuleList::const_iterator en
= modlist
.end();
1199 for (; it
!= en
; it
++) {
1200 string
const modName
= *it
;
1201 LyXModule
* lm
= theModuleList
[modName
];
1203 docstring
const msg
=
1204 bformat(_("The module %1$s has been requested by\n"
1205 "this document but has not been found in the list of\n"
1206 "available modules. If you recently installed it, you\n"
1207 "probably need to reconfigure LyX.\n"), from_utf8(modName
));
1208 ExceptionMessage(WarningException
,_("Module not available"),
1209 msg
+ _("Some layouts may not be available."));
1212 if (!lm
->isAvailable()) {
1213 docstring
const msg
=
1214 bformat(_("The module %1$s requires a package that is\n"
1215 "not available in your LaTeX installation. LaTeX output\n"
1216 "may not be possible.\n"), from_utf8(modName
));
1217 ExceptionMessage(WarningException
, _("Package not available"), msg
);
1219 FileName layout_file
= libFileSearch("layouts", lm
->getFilename());
1220 if (!doc_class
.read(layout_file
, TextClass::MODULE
)) {
1221 docstring
const msg
=
1222 bformat(_("Error reading module %1$s\n"), from_utf8(modName
));
1223 throw ExceptionMessage(WarningException
, _("Read Error"), msg
);
1230 /////////////////////////////////////////////////////////////////////////
1234 /////////////////////////////////////////////////////////////////////////
1236 DocumentClass::DocumentClass(LayoutFile
const & tc
)
1241 bool DocumentClass::hasLaTeXLayout(std::string
const & lay
) const
1243 LayoutList::const_iterator it
= layoutlist_
.begin();
1244 LayoutList::const_iterator end
= layoutlist_
.end();
1245 for (; it
!= end
; ++it
)
1246 if (it
->latexname() == lay
)
1252 bool DocumentClass::provides(string
const & p
) const
1254 return provides_
.find(p
) != provides_
.end();
1258 bool DocumentClass::hasTocLevels() const
1260 return min_toclevel_
!= Layout::NOT_IN_TOC
;
1264 /////////////////////////////////////////////////////////////////////////
1268 /////////////////////////////////////////////////////////////////////////
1270 ostream
& operator<<(ostream
& os
, PageSides p
)