3 * \file InsetLayout.cpp
4 * This file is part of LyX, the document processor.
5 * Licence details can be found in the file COPYING.
7 * \author Martin Vermeer
10 * Full author contact details are available in file CREDITS.
15 #include "InsetLayout.h"
19 #include "TextClass.h"
21 #include "support/debug.h"
22 #include "support/lstrings.h"
23 #include "support/textutils.h"
31 using namespace lyx::support;
35 InsetLayout::InsetDecoration translateDecoration(std::string const & str)
37 if (compare_ascii_no_case(str, "classic") == 0)
38 return InsetLayout::CLASSIC;
39 if (compare_ascii_no_case(str, "minimalistic") == 0)
40 return InsetLayout::MINIMALISTIC;
41 if (compare_ascii_no_case(str, "conglomerate") == 0)
42 return InsetLayout::CONGLOMERATE;
43 return InsetLayout::DEFAULT;
48 InsetLayout::InsetLaTeXType translateLaTeXType(std::string const & str)
50 if (compare_ascii_no_case(str, "command") == 0)
51 return InsetLayout::COMMAND;
52 if (compare_ascii_no_case(str, "environment") == 0)
53 return InsetLayout::ENVIRONMENT;
54 if (compare_ascii_no_case(str, "none") == 0)
55 return InsetLayout::NOLATEXTYPE;
56 return InsetLayout::ILT_ERROR;
62 bool InsetLayout::read(Lexer & lex, TextClass const & tclass,
77 IL_FIXEDWIDTH_PREAMBLE_ENCODING,
79 IL_FORCE_LOCAL_FONT_SWITCH,
99 IL_DOCBOOKWRAPPERTAGTYPE,
100 IL_DOCBOOKWRAPPERATTR,
102 IL_DOCBOOKITEMTAGTYPE,
104 IL_DOCBOOKITEMWRAPPERTAG,
105 IL_DOCBOOKITEMWRAPPERTAGTYPE,
106 IL_DOCBOOKITEMWRAPPERATTR,
128 IL_PARBREAKISNEWLINE,
140 LexerKeyword elementTags[] = {
141 { "addtotoc", IL_ADDTOTOC },
142 { "argument", IL_ARGUMENT },
143 { "babelpreamble", IL_BABELPREAMBLE },
144 { "bgcolor", IL_BGCOLOR },
145 { "contentaslabel", IL_CONTENTASLABEL },
146 { "copystyle", IL_COPYSTYLE },
147 { "counter", IL_COUNTER},
148 { "custompars", IL_CUSTOMPARS },
149 { "decoration", IL_DECORATION },
150 { "display", IL_DISPLAY },
151 { "docbookattr", IL_DOCBOOKATTR },
152 { "docbookininfo", IL_DOCBOOKININFO },
153 { "docbookitemattr", IL_DOCBOOKITEMATTR },
154 { "docbookitemtag", IL_DOCBOOKITEMTAG },
155 { "docbookitemtagtype", IL_DOCBOOKITEMTAGTYPE },
156 { "docbookitemwrapperattr", IL_DOCBOOKITEMWRAPPERATTR },
157 { "docbookitemwrappertag", IL_DOCBOOKITEMWRAPPERTAG },
158 { "docbookitemwrappertagtype", IL_DOCBOOKITEMWRAPPERTAGTYPE },
159 { "docbooksection", IL_DOCBOOKSECTION },
160 { "docbooktag", IL_DOCBOOKTAG },
161 { "docbooktagtype", IL_DOCBOOKTAGTYPE },
162 { "docbookwrapperattr", IL_DOCBOOKWRAPPERATTR },
163 { "docbookwrappertag", IL_DOCBOOKWRAPPERTAG },
164 { "docbookwrappertagtype", IL_DOCBOOKWRAPPERTAGTYPE },
165 { "editexternal", IL_EDITEXTERNAL },
167 { "fixedwidthpreambleencoding", IL_FIXEDWIDTH_PREAMBLE_ENCODING },
169 { "forcelocalfontswitch", IL_FORCE_LOCAL_FONT_SWITCH },
170 { "forceltr", IL_FORCELTR },
171 { "forceownlines", IL_FORCEOWNLINES },
172 { "forceplain", IL_FORCEPLAIN },
173 { "freespacing", IL_FREESPACING },
174 { "htmlattr", IL_HTMLATTR },
175 { "htmlforcecss", IL_HTMLFORCECSS },
176 { "htmlinnerattr", IL_HTMLINNERATTR},
177 { "htmlinnertag", IL_HTMLINNERTAG},
178 { "htmlisblock", IL_HTMLISBLOCK},
179 { "htmllabel", IL_HTMLLABEL },
180 { "htmlpreamble", IL_HTMLPREAMBLE },
181 { "htmlstyle", IL_HTMLSTYLE },
182 { "htmltag", IL_HTMLTAG },
183 { "intoc", IL_INTOC },
184 { "istoccaption", IL_ISTOCCAPTION },
185 { "keepempty", IL_KEEPEMPTY },
186 { "labelfont", IL_LABELFONT },
187 { "labelstring", IL_LABELSTRING },
188 { "langpreamble", IL_LANGPREAMBLE },
189 { "latexname", IL_LATEXNAME },
190 { "latexparam", IL_LATEXPARAM },
191 { "latextype", IL_LATEXTYPE },
192 { "leftdelim", IL_LEFTDELIM },
193 { "lyxtype", IL_LYXTYPE },
194 { "menustring", IL_MENUSTRING },
195 { "multipar", IL_MULTIPAR },
196 { "needcprotect", IL_NEEDCPROTECT },
197 { "needmboxprotect", IL_NEEDMBOXPROTECT },
198 { "needprotect", IL_NEEDPROTECT },
199 { "newlinecmd", IL_NEWLINE_CMD },
200 { "obsoletedby", IL_OBSOLETEDBY },
201 { "parbreakignored", IL_PARBREAKIGNORED },
202 { "parbreakisnewline", IL_PARBREAKISNEWLINE },
203 { "passthru", IL_PASSTHRU },
204 { "passthruchars", IL_PASSTHRU_CHARS },
205 { "preamble", IL_PREAMBLE },
206 { "refprefix", IL_REFPREFIX },
207 { "requires", IL_REQUIRES },
208 { "resetargs", IL_RESETARGS },
209 { "resetsfont", IL_RESETSFONT },
210 { "rightdelim", IL_RIGHTDELIM },
211 { "spellcheck", IL_SPELLCHECK }
214 lex.pushTable(elementTags);
216 labelfont_ = inherit_font;
217 bgcolor_ = Color_none;
219 // whether we've read the CustomPars or ForcePlain tag
220 // for issuing a warning in case MultiPars comes later
221 bool readCustomOrPlain = false;
224 while (!getout && lex.isOK()) {
227 case Lexer::LEX_UNDEF:
228 lex.printError("Unknown InsetLayout tag");
237 // Perhaps a more elegant way to deal with the next two would be the
238 // way this sort of thing is handled in Layout::read(), namely, by
241 // make sure that we have the right sort of name.
242 if (name_ != from_ascii("undefined")
243 && name_.substr(0,5) != from_ascii("Flex:")) {
244 LYXERR0("Flex insets must have names of the form `Flex:<name>'.\n"
245 "This one has the name `" << to_utf8(name_) << "'\n"
246 "Ignoring LyXType declaration.");
247 // this is not really a reason to abort
254 lyxtype_ = translateLyXType(lt);
255 if (lyxtype_ == NOLYXTYPE) {
256 LYXERR0("Unknown LyXType `" << lt << "'.");
257 // this is not really a reason to abort
261 if (lyxtype_ == CHARSTYLE) {
262 // by default, charstyles force the plain layout
271 latextype_ = translateLaTeXType(lt);
272 if (latextype_ == ILT_ERROR) {
273 LYXERR0("Unknown LaTeXType `" << lt << "'.");
274 // this is not really a reason to abort
288 decoration_ = translateDecoration(tmp);
295 latexparam_ = subst(tmp, """, "\"");
299 leftdelim_ = subst(leftdelim_, from_ascii("<br/>"),
302 case IL_FIXEDWIDTH_PREAMBLE_ENCODING:
303 lex >> fixedwidthpreambleencoding_;
305 case IL_FORCE_LOCAL_FONT_SWITCH:
306 lex >> forcelocalfontswitch_;
310 rightdelim_ = subst(rightdelim_, from_ascii("<br/>"),
314 labelfont_ = lyxRead(lex, inherit_font);
319 case IL_FORCEOWNLINES:
320 lex >> forceownlines_;
327 // the defaults for these depend upon multipar_
328 if (readCustomOrPlain)
329 LYXERR0("Warning: Read MultiPar after CustomPars or ForcePlain. "
330 "Previous value may be overwritten!");
331 readCustomOrPlain = false;
332 custompars_ = multipar_;
333 forceplain_ = !multipar_;
340 readCustomOrPlain = true;
344 readCustomOrPlain = true;
349 case IL_PASSTHRU_CHARS:
350 lex >> passthru_chars_;
355 case IL_PARBREAKIGNORED:
356 lex >> parbreakignored_;
358 case IL_PARBREAKISNEWLINE:
359 lex >> parbreakisnewline_;
370 case IL_NEEDCPROTECT:
371 lex >> needcprotect_;
373 case IL_NEEDMBOXPROTECT:
374 lex >> needmboxprotect_;
376 case IL_CONTENTASLABEL:
377 lex >> contentaslabel_;
380 // initialize with a known style
383 style = subst(style, '_', ' ');
385 // We don't want to apply the algorithm in DocumentClass::insetLayout()
386 // here. So we do it the long way.
387 TextClass::InsetLayouts::const_iterator it =
388 tclass.insetLayouts().find(style);
389 if (it != tclass.insetLayouts().end()) {
390 docstring const tmpname = name_;
391 this->operator=(it->second);
394 LYXERR0("Cannot copy unknown InsetLayout `"
395 << style << "' to InsetLayout `"
397 << "All InsetLayouts so far:");
398 TextClass::InsetLayouts::const_iterator lit =
399 tclass.insetLayouts().begin();
400 TextClass::InsetLayouts::const_iterator len =
401 tclass.insetLayouts().end();
402 for (; lit != len; ++lit)
403 lyxerr << lit->second.name() << "\n";
404 // this is not really a reason to abort
410 case IL_OBSOLETEDBY: {
413 style = subst(style, '_', ' ');
415 // We don't want to apply the algorithm in DocumentClass::insetLayout()
416 // here. So we do it the long way.
417 TextClass::InsetLayouts::const_iterator it =
418 tclass.insetLayouts().find(style);
419 if (it != tclass.insetLayouts().end()) {
420 docstring const tmpname = name_;
421 this->operator=(it->second);
423 if (obsoleted_by().empty())
424 obsoleted_by_ = style;
426 LYXERR0("Cannot replace InsetLayout `"
428 << "' with unknown InsetLayout `"
430 << "All InsetLayouts so far:");
431 TextClass::InsetLayouts::const_iterator lit =
432 tclass.insetLayouts().begin();
433 TextClass::InsetLayouts::const_iterator len =
434 tclass.insetLayouts().end();
435 for (; lit != len; ++lit)
436 lyxerr << lit->second.name() << "\n";
437 // this is not really a reason to abort
445 font_ = lyxRead(lex, inherit_font);
446 // If you want to define labelfont, you need to do so after
456 postcommandargs_.clear();
464 bgcolor_ = lcolor.getFromLyXName(tmp);
467 preamble_ = lex.getLongString(from_ascii("EndPreamble"));
469 case IL_BABELPREAMBLE:
470 babelpreamble_ = lex.getLongString(from_ascii("EndBabelPreamble"));
472 case IL_LANGPREAMBLE:
473 langpreamble_ = lex.getLongString(from_ascii("EndLangPreamble"));
484 case IL_HTMLFORCECSS:
485 lex >> htmlforcecss_;
487 case IL_HTMLINNERTAG:
488 lex >> htmlinnertag_;
490 case IL_HTMLINNERATTR:
491 lex >> htmlinnerattr_;
500 htmlstyle_ = lex.getLongString(from_ascii("EndHTMLStyle"));
502 case IL_HTMLPREAMBLE:
503 htmlpreamble_ = lex.getLongString(from_ascii("EndPreamble"));
511 case IL_DOCBOOKTAGTYPE:
512 lex >> docbooktagtype_;
514 case IL_DOCBOOKININFO:
515 lex >> docbookininfo_;
517 case IL_DOCBOOKSECTION:
518 lex >> docbooksection_;
520 case IL_DOCBOOKITEMTAG:
521 lex >> docbookitemtag_;
523 case IL_DOCBOOKITEMTAGTYPE:
524 lex >> docbookitemtagtype_;
526 case IL_DOCBOOKITEMATTR:
527 lex >> docbookitemattr_;
529 case IL_DOCBOOKITEMWRAPPERTAG:
530 lex >> docbookitemwrappertag_;
532 case IL_DOCBOOKITEMWRAPPERTAGTYPE:
533 lex >> docbookitemwrappertagtype_;
535 case IL_DOCBOOKITEMWRAPPERATTR:
536 lex >> docbookitemwrapperattr_;
538 case IL_DOCBOOKWRAPPERTAG:
539 lex >> docbookwrappertag_;
541 case IL_DOCBOOKWRAPPERTAGTYPE:
542 lex >> docbookwrappertagtype_;
544 case IL_DOCBOOKWRAPPERATTR:
545 lex >> docbookwrapperattr_;
549 vector<string> const req
550 = getVectorFromString(lex.getString(true));
551 required_.insert(req.begin(), req.end());
565 add_to_toc_ = !toc_type_.empty();
567 case IL_ISTOCCAPTION:
568 lex >> is_toc_caption_;
570 case IL_EDITEXTERNAL:
571 lex >> edit_external_;
579 // Here add element to list if getout == true
583 // The label font is generally used as-is without
584 // any realization against a given context.
585 labelfont_.realize(sane_font);
592 InsetLayout::InsetLyXType translateLyXType(std::string const & str)
594 if (compare_ascii_no_case(str, "charstyle") == 0)
595 return InsetLayout::CHARSTYLE;
596 if (compare_ascii_no_case(str, "custom") == 0)
597 return InsetLayout::CUSTOM;
598 if (compare_ascii_no_case(str, "end") == 0)
599 return InsetLayout::END;
600 if (compare_ascii_no_case(str, "standard") == 0)
601 return InsetLayout::STANDARD;
602 return InsetLayout::NOLYXTYPE;
606 string const & InsetLayout::htmltag() const
608 if (htmltag_.empty())
609 htmltag_ = multipar_ ? "div" : "span";
614 string const & InsetLayout::htmlattr() const
616 if (htmlattr_.empty())
617 htmlattr_ = "class=\"" + defaultCSSClass() + "\"";
622 string const & InsetLayout::htmlinnerattr() const
624 if (htmlinnerattr_.empty())
625 htmlinnerattr_ = "class=\"" + defaultCSSClass() + "_inner\"";
626 return htmlinnerattr_;
630 string InsetLayout::defaultCSSClass() const
632 if (!defaultcssclass_.empty())
633 return defaultcssclass_;
635 string n = to_utf8(name());
636 string::const_iterator it = n.begin();
637 string::const_iterator en = n.end();
638 for (; it != en; ++it) {
639 if (!isAlphaASCII(*it))
641 else if (isLower(*it))
646 // are there other characters we need to remove?
647 defaultcssclass_ = d;
648 return defaultcssclass_;
652 void InsetLayout::makeDefaultCSS() const
654 if (!htmldefaultstyle_.empty())
656 docstring const mainfontCSS = font_.asCSS();
657 if (!mainfontCSS.empty())
659 from_ascii(htmltag() + "." + defaultCSSClass() + " {\n") +
660 mainfontCSS + from_ascii("\n}\n");
664 docstring InsetLayout::htmlstyle() const
666 if (!htmlstyle_.empty() && !htmlforcecss_)
668 if (htmldefaultstyle_.empty())
670 docstring retval = htmldefaultstyle_;
671 if (!htmlstyle_.empty())
672 retval += '\n' + htmlstyle_ + '\n';
677 std::string const & InsetLayout::docbookininfo() const
679 // Same as Layout::docbookininfo.
680 // Indeed, a trilean. Only titles should be "maybe": otherwise, metadata is "always", content is "never".
681 if (docbookininfo_.empty() || (docbookininfo_ != "never" && docbookininfo_ != "always" && docbookininfo_ != "maybe"))
682 docbookininfo_ = "never";
683 return docbookininfo_;
687 std::string InsetLayout::docbooktagtype() const
689 if (docbooktagtype_ != "block" && docbooktagtype_ != "paragraph" && docbooktagtype_ != "inline")
690 docbooktagtype_ = "block";
691 return docbooktagtype_;
695 std::string InsetLayout::docbookwrappertagtype() const
697 if (docbookwrappertagtype_ != "block" && docbookwrappertagtype_ != "paragraph" && docbookwrappertagtype_ != "inline")
698 docbookwrappertagtype_ = "block";
699 return docbookwrappertagtype_;
703 std::string InsetLayout::docbookitemtagtype() const
705 if (docbookitemtagtype_ != "block" && docbookitemtagtype_ != "paragraph" && docbookitemtagtype_ != "inline")
706 docbookitemtagtype_ = "block";
707 return docbookitemtagtype_;
711 std::string InsetLayout::docbookitemwrappertagtype() const
713 if (docbookitemwrappertagtype_ != "block" && docbookitemwrappertagtype_ != "paragraph" && docbookitemwrappertagtype_ != "inline")
714 docbookitemwrappertagtype_ = "block";
715 return docbookitemwrappertagtype_;
719 void InsetLayout::readArgument(Lexer & lex)
721 Layout::latexarg arg;
722 arg.mandatory = false;
723 arg.autoinsert = false;
724 arg.insertcotext = false;
725 arg.insertonnewline = false;
727 bool finished = false;
728 arg.font = inherit_font;
729 arg.labelfont = inherit_font;
730 arg.is_toc_caption = false;
731 arg.free_spacing = false;
732 arg.passthru = PT_INHERITED;
733 arg.nodelims = false;
736 bool const postcmd = prefixIs(nr, "post:");
737 while (!finished && lex.isOK() && !error) {
739 string const tok = ascii_lowercase(lex.getString());
743 } else if (tok == "endargument") {
745 } else if (tok == "labelstring") {
747 arg.labelstring = lex.getDocString();
748 } else if (tok == "menustring") {
750 arg.menustring = lex.getDocString();
751 } else if (tok == "mandatory") {
753 arg.mandatory = lex.getBool();
754 } else if (tok == "autoinsert") {
756 arg.autoinsert = lex.getBool();
757 } else if (tok == "insertcotext") {
759 arg.insertcotext = lex.getBool();
760 } else if (tok == "insertonnewline") {
762 arg.insertonnewline = lex.getBool();
763 } else if (tok == "leftdelim") {
765 arg.ldelim = lex.getDocString();
766 arg.ldelim = subst(arg.ldelim,
767 from_ascii("<br/>"), from_ascii("\n"));
768 } else if (tok == "rightdelim") {
770 arg.rdelim = lex.getDocString();
771 arg.rdelim = subst(arg.rdelim,
772 from_ascii("<br/>"), from_ascii("\n"));
773 } else if (tok == "defaultarg") {
775 arg.defaultarg = lex.getDocString();
776 } else if (tok == "presetarg") {
778 arg.presetarg = lex.getDocString();
779 } else if (tok == "tooltip") {
781 arg.tooltip = lex.getDocString();
782 } else if (tok == "requires") {
784 arg.required = lex.getString();
785 } else if (tok == "decoration") {
787 arg.decoration = lex.getString();
788 } else if (tok == "newlinecmd") {
790 arg.newlinecmd = lex.getString();
791 } else if (tok == "font") {
792 arg.font = lyxRead(lex, arg.font);
793 } else if (tok == "labelfont") {
794 arg.labelfont = lyxRead(lex, arg.labelfont);
795 } else if (tok == "passthruchars") {
797 arg.pass_thru_chars = lex.getDocString();
798 } else if (tok == "passthru") {
800 docstring value = lex.getDocString();
801 if (value == "true" || value == "1")
802 arg.passthru = PT_TRUE;
803 else if (value == "false" || value == "0")
804 arg.passthru = PT_FALSE;
806 arg.passthru = PT_INHERITED;
807 } else if (tok == "istoccaption") {
809 arg.is_toc_caption = lex.getBool();
810 } else if (tok == "freespacing") {
812 arg.free_spacing = lex.getBool();
813 } else if (tok == "docbooktag") {
815 arg.docbooktag = lex.getDocString();
816 } else if (tok == "docbookattr") {
818 arg.docbookattr = lex.getDocString();
819 } else if (tok == "docbooktagtype") {
821 arg.docbooktagtype = lex.getDocString();
823 lex.printError("Unknown tag");
827 if (arg.labelstring.empty())
828 LYXERR0("Incomplete Argument definition!");
830 postcommandargs_[nr] = arg;
832 latexargs_[nr] = arg;
836 Layout::LaTeXArgMap InsetLayout::args() const
838 Layout::LaTeXArgMap args = latexargs_;
839 if (!postcommandargs_.empty())
840 args.insert(postcommandargs_.begin(), postcommandargs_.end());
845 int InsetLayout::optArgs() const
848 Layout::LaTeXArgMap const args = InsetLayout::args();
849 Layout::LaTeXArgMap::const_iterator it = args.begin();
850 for (; it != args.end(); ++it) {
851 if (!(*it).second.mandatory)
858 int InsetLayout::requiredArgs() const
861 Layout::LaTeXArgMap const args = InsetLayout::args();
862 Layout::LaTeXArgMap::const_iterator it = args.begin();
863 for (; it != args.end(); ++it) {
864 if ((*it).second.mandatory)