]> git.lyx.org Git - lyx.git/blobdiff - src/TextClass.cpp
Fulfill promise to Andre: TextClass_ptr --> TextClassPtr.
[lyx.git] / src / TextClass.cpp
index 2072b08d785a5afebd4962c04db5b00d9819a8fe..8aae1abe87667f081ba339f8327cb8a461266ccc 100644 (file)
 #include "debug.h"
 #include "Lexer.h"
 #include "Counters.h"
+#include "gettext.h"
 #include "Floating.h"
 #include "FloatList.h"
 
+#include "frontends/alert.h"
+
 #include "support/lstrings.h"
 #include "support/lyxlib.h"
 #include "support/filetools.h"
@@ -51,21 +54,21 @@ using std::ostream;
 
 namespace {
 
-class LayoutNamesEqual : public std::unary_function<Layout_ptr, bool> {
+class LayoutNamesEqual : public std::unary_function<LayoutPtr, bool> {
 public:
-       LayoutNamesEqual(string const & name)
+       LayoutNamesEqual(docstring const & name)
                : name_(name)
        {}
-       bool operator()(Layout_ptr const & c) const
+       bool operator()(LayoutPtr const & c) const
        {
                return c->name() == name_;
        }
 private:
-       string name_;
+       docstring name_;
 };
 
 
-int const FORMAT = 4;
+int const FORMAT = 5;
 
 
 bool layout2layout(FileName const & filename, FileName const & tempfile)
@@ -101,9 +104,10 @@ bool layout2layout(FileName const & filename, FileName const & tempfile)
 TextClass::TextClass(string const & fn, string const & cln,
                           string const & desc, bool texClassAvail )
        : name_(fn), latexname_(cln), description_(desc),
-         floatlist_(new FloatList), ctrs_(new Counters),
+         floatlist_(new FloatList), counters_(new Counters),
          texClassAvail_(texClassAvail)
 {
+       modular_ = false;
        outputType_ = LATEX;
        columns_ = 1;
        sides_ = OneSide;
@@ -127,7 +131,7 @@ bool TextClass::isTeXClassAvailable() const
 
 bool TextClass::do_readStyle(Lexer & lexrc, Layout & lay)
 {
-       LYXERR(Debug::TCLASS) << "Reading style " << lay.name() << endl;
+       LYXERR(Debug::TCLASS) << "Reading style " << to_utf8(lay.name()) << endl;
        if (!lay.read(lexrc, *this)) {
                // Resolve fonts
                lay.resfont = lay.font;
@@ -136,7 +140,7 @@ bool TextClass::do_readStyle(Lexer & lexrc, Layout & lay)
                lay.reslabelfont.realize(defaultfont());
                return false; // no errors
        }
-       lyxerr << "Error parsing style `" << lay.name() << '\'' << endl;
+       lyxerr << "Error parsing style `" << to_utf8(lay.name()) << '\'' << endl;
        return true;
 }
 
@@ -146,7 +150,7 @@ enum TextClassTags {
        TC_INPUT,
        TC_STYLE,
        TC_DEFAULTSTYLE,
-       TC_CHARSTYLE,
+       TC_INSETLAYOUT,
        TC_ENVIRONMENT,
        TC_NOSTYLE,
        TC_COLUMNS,
@@ -170,7 +174,7 @@ enum TextClassTags {
 
 
 // Reads a textclass structure from file.
-bool TextClass::read(FileName const & filename, bool merge)
+bool TextClass::read(FileName const & filename, ReadType rt)
 {
        if (!support::isFileReadable(filename)) {
                lyxerr << "Cannot read layout file `" << filename << "'."
@@ -179,7 +183,6 @@ bool TextClass::read(FileName const & filename, bool merge)
        }
 
        keyword_item textClassTags[] = {
-               { "charstyle",       TC_CHARSTYLE },
                { "classoptions",    TC_CLASSOPTIONS },
                { "columns",         TC_COLUMNS },
                { "counter",         TC_COUNTER },
@@ -189,6 +192,7 @@ bool TextClass::read(FileName const & filename, bool merge)
                { "float",           TC_FLOAT },
                { "format",          TC_FORMAT },
                { "input",           TC_INPUT },
+               { "insetlayout",     TC_INSETLAYOUT },
                { "leftmargin",      TC_LEFTMARGIN },
                { "nofloat",         TC_NOFLOAT },
                { "nostyle",         TC_NOSTYLE },
@@ -205,14 +209,21 @@ bool TextClass::read(FileName const & filename, bool merge)
                { "tocdepth",        TC_TOCDEPTH }
        };
 
-       if (!merge)
-               LYXERR(Debug::TCLASS) << "Reading textclass "
-                                       << to_utf8(makeDisplayPath(filename.absFilename()))
-                                       << endl;
-       else
-               LYXERR(Debug::TCLASS) << "Reading input file "
-                                    << to_utf8(makeDisplayPath(filename.absFilename()))
-                                    << endl;
+       switch (rt) {
+       case BASECLASS:
+               LYXERR(Debug::TCLASS) << "Reading textclass ";
+               break;
+       case MERGE:
+               LYXERR(Debug::TCLASS) << "Reading input file ";
+         break;
+       case MODULE:
+               LYXERR(Debug::TCLASS) << "Reading module file ";
+               break;
+       default:
+               BOOST_ASSERT(false);
+       }
+       LYXERR(Debug::TCLASS) << to_utf8(makeDisplayPath(filename.absFilename()))
+               << endl;
 
        Lexer lexrc(textClassTags,
                sizeof(textClassTags) / sizeof(textClassTags[0]));
@@ -261,7 +272,7 @@ bool TextClass::read(FileName const & filename, bool merge)
                                        lexrc.printError("Could not find input"
                                                         "file: " + inc);
                                        error = true;
-                               } else if (read(tmp, true)) {
+                               } else if (read(tmp, MERGE)) {
                                        lexrc.printError("Error reading input"
                                                         "file: " + tmp.absFilename());
                                        error = true;
@@ -271,8 +282,8 @@ bool TextClass::read(FileName const & filename, bool merge)
 
                case TC_DEFAULTSTYLE:
                        if (lexrc.next()) {
-                               string const name = subst(lexrc.getString(),
-                                                         '_', ' ');
+                               docstring const name = from_utf8(subst(lexrc.getString(),
+                                                         '_', ' '));
                                defaultlayout_ = name;
                        }
                        break;
@@ -280,9 +291,15 @@ bool TextClass::read(FileName const & filename, bool merge)
                case TC_ENVIRONMENT:
                case TC_STYLE:
                        if (lexrc.next()) {
-                               string const name = subst(lexrc.getString(),
-                                                   '_', ' ');
-                               if (hasLayout(name)) {
+                               docstring const name = from_utf8(subst(lexrc.getString(),
+                                                   '_', ' '));
+                               if (name.empty()) {
+                                       string s = "Could not read name for style: `$$Token' "
+                                               + lexrc.getString() + " is probably not valid UTF-8!";
+                                       lexrc.printError(s.c_str());
+                                       Layout lay;
+                                       error = do_readStyle(lexrc, lay);
+                               } else if (hasLayout(name)) {
                                        Layout * lay = operator[](name).get();
                                        error = do_readStyle(lexrc, *lay);
                                } else {
@@ -313,11 +330,11 @@ bool TextClass::read(FileName const & filename, bool merge)
 
                case TC_NOSTYLE:
                        if (lexrc.next()) {
-                               string const style = subst(lexrc.getString(),
-                                                    '_', ' ');
+                               docstring const style = from_utf8(subst(lexrc.getString(),
+                                                    '_', ' '));
                                if (!delete_layout(style))
                                        lyxerr << "Cannot delete style `"
-                                              << style << '\'' << endl;
+                                              << to_utf8(style) << '\'' << endl;
 //                                     lexrc.printError("Cannot delete style"
 //                                                      " `$$Token'");
                        }
@@ -389,17 +406,17 @@ bool TextClass::read(FileName const & filename, bool merge)
 
                case TC_LEFTMARGIN:     // left margin type
                        if (lexrc.next())
-                               leftmargin_ = lexrc.getString();
+                               leftmargin_ = lexrc.getDocString();
                        break;
 
                case TC_RIGHTMARGIN:    // right margin type
                        if (lexrc.next())
-                               rightmargin_ = lexrc.getString();
+                               rightmargin_ = lexrc.getDocString();
                        break;
-               case TC_CHARSTYLE:
+               case TC_INSETLAYOUT:
                        if (lexrc.next()) {
-                               string const name = subst(lexrc.getString(), '_', ' ');
-                               readCharStyle(lexrc, name);
+                               docstring const name = subst(lexrc.getDocString(), '_', ' ');
+                               readInsetLayout(lexrc, name);
                        }
                        break;
                case TC_FLOAT:
@@ -432,12 +449,20 @@ bool TextClass::read(FileName const & filename, bool merge)
                FileName const tempfile(support::tempName());
                error = !layout2layout(filename, tempfile);
                if (!error)
-                       error = read(tempfile, merge);
+                       error = read(tempfile, rt);
                support::unlink(tempfile);
                return error;
        }
 
-       if (!merge) { // we are at top level here.
+       if (rt == MODULE) 
+               LYXERR(Debug::TCLASS) << "Finished reading module file "
+                               << to_utf8(makeDisplayPath(filename.absFilename()))
+                               << endl;
+       else if (rt == MERGE)
+               LYXERR(Debug::TCLASS) << "Finished reading input file "
+                               << to_utf8(makeDisplayPath(filename.absFilename()))
+                               << endl;
+       else { // we are at top level here.
                LYXERR(Debug::TCLASS) << "Finished reading textclass "
                                      << to_utf8(makeDisplayPath(filename.absFilename()))
                                      << endl;
@@ -467,10 +492,7 @@ bool TextClass::read(FileName const & filename, bool merge)
                        << "Minimum TocLevel is " << min_toclevel_
                        << ", maximum is " << max_toclevel_ <<endl;
 
-       } else
-               LYXERR(Debug::TCLASS) << "Finished reading input file "
-                                     << to_utf8(makeDisplayPath(filename.absFilename()))
-                                     << endl;
+       }
 
        return error;
 }
@@ -586,36 +608,49 @@ void TextClass::readClassOptions(Lexer & lexrc)
        lexrc.popTable();
 }
 
-enum CharStyleTags {
-       CS_FONT = 1,
-       CS_LABELFONT,
-       CS_LATEXTYPE,
-       CS_LATEXNAME,
-       CS_LATEXPARAM,
-       CS_PREAMBLE,
-       CS_END
+
+enum InsetLayoutTags {
+       IL_FONT = 1,
+       IL_BGCOLOR,
+       IL_DECORATION,
+       IL_LABELFONT,
+       IL_LABELSTRING,
+       IL_LATEXNAME,
+       IL_LATEXPARAM,
+       IL_LATEXTYPE,
+       IL_LYXTYPE,
+       IL_PREAMBLE,
+       IL_END
 };
 
 
-void TextClass::readCharStyle(Lexer & lexrc, string const & name)
+void TextClass::readInsetLayout(Lexer & lexrc, docstring const & name)
 {
        keyword_item elementTags[] = {
-               { "end", CS_END },
-               { "font", CS_FONT },
-               { "labelfont", CS_LABELFONT },
-               { "latexname", CS_LATEXNAME },
-               { "latexparam", CS_LATEXPARAM },
-               { "latextype", CS_LATEXTYPE },
-               { "preamble", CS_PREAMBLE}
+               { "bgcolor", IL_BGCOLOR },
+               { "decoration", IL_DECORATION },
+               { "end", IL_END },
+               { "font", IL_FONT },
+               { "labelfont", IL_LABELFONT },
+               { "labelstring", IL_LABELSTRING },
+               { "latexname", IL_LATEXNAME },
+               { "latexparam", IL_LATEXPARAM },
+               { "latextype", IL_LATEXTYPE },
+               { "lyxtype", IL_LYXTYPE },
+               { "preamble", IL_PREAMBLE }
        };
 
-       lexrc.pushTable(elementTags, CS_END);
+       lexrc.pushTable(elementTags, IL_END);
 
+       string lyxtype;
+       docstring labelstring;
        string latextype;
+       string decoration;
        string latexname;
        string latexparam;
        Font font(Font::ALL_INHERIT);
        Font labelfont(Font::ALL_INHERIT);
+       Color::color bgcolor(Color::background);
        string preamble;
 
        bool getout = false;
@@ -627,30 +662,51 @@ void TextClass::readCharStyle(Lexer & lexrc, string const & name)
                        continue;
                default: break;
                }
-               switch (static_cast<CharStyleTags>(le)) {
-               case CS_LATEXTYPE:
+               switch (static_cast<InsetLayoutTags>(le)) {
+               case IL_LYXTYPE:
+                       lexrc.next();
+                       lyxtype = lexrc.getString();
+                       break;
+               case IL_LATEXTYPE:
                        lexrc.next();
                        latextype = lexrc.getString();
                        break;
-               case CS_LATEXNAME:
+               case IL_LABELSTRING:
+                       lexrc.next();
+                       labelstring = lexrc.getDocString();
+                       break;
+               case IL_DECORATION:
+                       lexrc.next();
+                       decoration = lexrc.getString();
+                       break;
+               case IL_LATEXNAME:
                        lexrc.next();
                        latexname = lexrc.getString();
                        break;
-               case CS_LATEXPARAM:
+               case IL_LATEXPARAM:
                        lexrc.next();
                        latexparam = subst(lexrc.getString(), "&quot;", "\"");
                        break;
-               case CS_LABELFONT:
+               case IL_LABELFONT:
                        labelfont.lyxRead(lexrc);
+                       labelfont.realize(defaultfont());
                        break;
-               case CS_FONT:
+               case IL_FONT:
                        font.lyxRead(lexrc);
+                       font.realize(defaultfont());
+                       // So: define font before labelfont
                        labelfont = font;
                        break;
-               case CS_PREAMBLE:
+               case IL_BGCOLOR: {
+                       lexrc.next();
+                       string const token = lexrc.getString();
+                       bgcolor = lcolor.getFromLyXName(token);
+                       break;
+               }
+               case IL_PREAMBLE:
                        preamble = lexrc.getLongString("EndPreamble");
                        break;
-               case CS_END:
+               case IL_END:
                        getout = true;
                        break;
                }
@@ -659,21 +715,26 @@ void TextClass::readCharStyle(Lexer & lexrc, string const & name)
        //
        // Here add element to list if getout == true
        if (getout) {
-               CharStyle cs;
-               cs.name = name;
-               cs.latextype = latextype;
-               cs.latexname = latexname;
-               cs.latexparam = latexparam;
-               cs.font = font;
-               cs.labelfont = labelfont;
-               cs.preamble = from_utf8(preamble);
-               charstyles().push_back(cs);
+               InsetLayout il;
+               il.name = to_ascii(name);
+               il.lyxtype = lyxtype;
+               il.labelstring = labelstring;
+               il.decoration = decoration;
+               il.latextype = latextype;
+               il.latexname = latexname;
+               il.latexparam = latexparam;
+               il.font = font;
+               il.labelfont = labelfont;
+               il.bgcolor = bgcolor;           
+               il.preamble = preamble;
+               insetlayoutlist_[name] = il;
        }
 
        lexrc.popTable();
 }
 
 
+
 enum FloatTags {
        FT_TYPE = 1,
        FT_NAME,
@@ -709,7 +770,7 @@ void TextClass::readFloat(Lexer & lexrc)
        string within;
        string style;
        string name;
-       string listname;
+       string listName;
        bool builtin = false;
 
        bool getout = false;
@@ -725,8 +786,16 @@ void TextClass::readFloat(Lexer & lexrc)
                case FT_TYPE:
                        lexrc.next();
                        type = lexrc.getString();
-                       // Here we could check if this type is already defined
-                       // and modify it with the rest of the vars instead.
+                       if (floatlist_->typeExist(type)) {
+                               Floating const & fl = floatlist_->getType(type);
+                               placement = fl.placement();
+                               ext = fl.ext();
+                               within = fl.within();
+                               style = fl.style();
+                               name = fl.name();
+                               listName = fl.listName();
+                               builtin = fl.builtin();
+                       } 
                        break;
                case FT_NAME:
                        lexrc.next();
@@ -752,7 +821,7 @@ void TextClass::readFloat(Lexer & lexrc)
                        break;
                case FT_LISTNAME:
                        lexrc.next();
-                       listname = lexrc.getString();
+                       listName = lexrc.getString();
                        break;
                case FT_BUILTIN:
                        lexrc.next();
@@ -766,9 +835,12 @@ void TextClass::readFloat(Lexer & lexrc)
 
        // Here if have a full float if getout == true
        if (getout) {
-               Floating newfloat(type, placement, ext, within,
-                                 style, name, listname, builtin);
-               floatlist_->newFloat(newfloat);
+               Floating fl(type, placement, ext, within,
+                           style, name, listName, builtin);
+               floatlist_->newFloat(fl);
+               // each float has its own counter
+               counters_->newCounter(from_ascii(type), from_ascii(within), 
+                                     docstring(), docstring());
        }
 
        lexrc.popTable();
@@ -778,6 +850,8 @@ void TextClass::readFloat(Lexer & lexrc)
 enum CounterTags {
        CT_NAME = 1,
        CT_WITHIN,
+       CT_LABELSTRING,
+       CT_LABELSTRING_APPENDIX,
        CT_END
 };
 
@@ -785,6 +859,8 @@ void TextClass::readCounter(Lexer & lexrc)
 {
        keyword_item counterTags[] = {
                { "end", CT_END },
+               { "labelstring", CT_LABELSTRING },
+               { "labelstringappendix", CT_LABELSTRING_APPENDIX },
                { "name", CT_NAME },
                { "within", CT_WITHIN }
        };
@@ -793,6 +869,8 @@ void TextClass::readCounter(Lexer & lexrc)
 
        docstring name;
        docstring within;
+       docstring labelstring;
+       docstring labelstring_appendix;
 
        bool getout = false;
        while (!getout && lexrc.isOK()) {
@@ -806,14 +884,31 @@ void TextClass::readCounter(Lexer & lexrc)
                switch (static_cast<CounterTags>(le)) {
                case CT_NAME:
                        lexrc.next();
-                       name = from_ascii(lexrc.getString());
+                       name = lexrc.getDocString();
+                       if (counters_->hasCounter(name))
+                               LYXERR(Debug::TCLASS) 
+                                       << "Reading existing counter " 
+                                       << to_utf8(name) << endl;
+                       else
+                               LYXERR(Debug::TCLASS) 
+                                       << "Reading new counter " 
+                                       << to_utf8(name) << endl;
                        break;
                case CT_WITHIN:
                        lexrc.next();
-                       within = from_ascii(lexrc.getString());
+                       within = lexrc.getDocString();
                        if (within == "none")
                                within.erase();
                        break;
+               case CT_LABELSTRING:
+                       lexrc.next();
+                       labelstring = lexrc.getDocString();
+                       labelstring_appendix = labelstring;
+                       break;
+               case CT_LABELSTRING_APPENDIX:
+                       lexrc.next();
+                       labelstring_appendix = lexrc.getDocString();
+                       break;
                case CT_END:
                        getout = true;
                        break;
@@ -821,12 +916,9 @@ void TextClass::readCounter(Lexer & lexrc)
        }
 
        // Here if have a full counter if getout == true
-       if (getout) {
-               if (within.empty())
-                       ctrs_->newCounter(name);
-               else
-                       ctrs_->newCounter(name, within);
-       }
+       if (getout)
+               counters_->newCounter(name, within, 
+                                     labelstring, labelstring_appendix);
 
        lexrc.popTable();
 }
@@ -838,21 +930,21 @@ Font const & TextClass::defaultfont() const
 }
 
 
-string const & TextClass::leftmargin() const
+docstring const & TextClass::leftmargin() const
 {
        return leftmargin_;
 }
 
 
-string const & TextClass::rightmargin() const
+docstring const & TextClass::rightmargin() const
 {
        return rightmargin_;
 }
 
 
-bool TextClass::hasLayout(string const & n) const
+bool TextClass::hasLayout(docstring const & n) const
 {
-       string const name = (n.empty() ? defaultLayoutName() : n);
+       docstring const name = n.empty() ? defaultLayoutName() : n;
 
        return find_if(layoutlist_.begin(), layoutlist_.end(),
                       LayoutNamesEqual(name))
@@ -861,7 +953,7 @@ bool TextClass::hasLayout(string const & n) const
 
 
 
-Layout_ptr const & TextClass::operator[](string const & name) const
+LayoutPtr const & TextClass::operator[](docstring const & name) const
 {
        BOOST_ASSERT(!name.empty());
 
@@ -871,12 +963,12 @@ Layout_ptr const & TextClass::operator[](string const & name) const
                        LayoutNamesEqual(name));
 
        if (cit == layoutlist_.end()) {
-               lyxerr << "We failed to find the layout '" << name
+               lyxerr << "We failed to find the layout '" << to_utf8(name)
                       << "' in the layout list. You MUST investigate!"
                       << endl;
                for (LayoutList::const_iterator it = layoutlist_.begin();
                         it != layoutlist_.end(); ++it)
-                       lyxerr  << " " << it->get()->name() << endl;
+                       lyxerr  << " " << to_utf8(it->get()->name()) << endl;
 
                // we require the name to exist
                BOOST_ASSERT(false);
@@ -887,7 +979,7 @@ Layout_ptr const & TextClass::operator[](string const & name) const
 
 
 
-bool TextClass::delete_layout(string const & name)
+bool TextClass::delete_layout(docstring const & name)
 {
        if (name == defaultLayoutName())
                return false;
@@ -943,30 +1035,43 @@ FloatList const & TextClass::floats() const
 
 Counters & TextClass::counters() const
 {
-       return *ctrs_.get();
+       return *counters_.get();
 }
 
 
-CharStyles::iterator TextClass::charstyle(string const & s) const
+// Return the layout object of an inset given by name. If the name
+// is not found as such, the part after the ':' is stripped off, and
+// searched again. In this way, an error fallback can be provided:
+// An erroneous 'CharStyle:badname' (e.g., after a documentclass switch)
+// will invoke the layout object defined by name = 'CharStyle'.
+// If that doesn't work either, an empty object returns (shouldn't
+// happen).  -- Idea JMarc, comment MV
+InsetLayout const & TextClass::insetlayout(docstring const & name) const 
 {
-       CharStyles::iterator cs = charstyles().begin();
-       CharStyles::iterator csend = charstyles().end();
-       for (; cs != csend; ++cs) {
-               if (cs->name == s)
-                       return cs;
+       docstring n = name;
+       while (!n.empty()) {
+               if (insetlayoutlist_.count(n) > 0)
+                       return insetlayoutlist_[n];
+               docstring::size_type i = n.find(':');
+               if (i == string::npos)
+                       break;
+               n = n.substr(0,i);
        }
-       return csend;
+       static InsetLayout empty;
+       empty.labelstring = from_utf8("UNDEFINED");
+       empty.bgcolor = Color::error;
+       return empty;
 }
 
 
-string const & TextClass::defaultLayoutName() const
+docstring const & TextClass::defaultLayoutName() const
 {
        // This really should come from the actual layout... (Lgb)
        return defaultlayout_;
 }
 
 
-Layout_ptr const & TextClass::defaultLayout() const
+LayoutPtr const & TextClass::defaultLayout() const
 {
        return operator[](defaultLayoutName());
 }