]> git.lyx.org Git - lyx.git/blobdiff - src/TextClass.cpp
Pass the encoding to the japanese pLaTeX processor (#4697).
[lyx.git] / src / TextClass.cpp
index ce66cf856072b4045b68c54238a73b1294382686..0ab0c5ce88c1ce31b5ef6a5e0f86606ddfcd9bc8 100644 (file)
@@ -30,7 +30,6 @@
 
 #include "support/lassert.h"
 #include "support/debug.h"
-#include "support/ExceptionMessage.h"
 #include "support/FileName.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
@@ -50,6 +49,19 @@ using namespace lyx::support;
 
 namespace lyx {
 
+// Keep the changes documented in the Customization manual. 
+//
+// If you change this format, then you MUST also make sure that
+// your changes do not invalidate the hardcoded layout file in 
+// LayoutFile.cpp. Additions will never do so, but syntax changes
+// could. See LayoutFileList::addEmptyClass() and, especially, the
+// definition of the layoutpost string. 
+// You should also run (or ask someone who has bash to run) the
+// development/updatelayouts.sh script, to update the format of 
+// all of our layout files.
+//
+int const LAYOUT_FORMAT = 35;
+       
 namespace {
 
 class LayoutNamesEqual : public unary_function<Layout, bool> {
@@ -65,9 +77,6 @@ private:
        docstring name_;
 };
 
-// Keep the changes documented in the Customization manual. 
-int const FORMAT = 24;
-
 
 bool layout2layout(FileName const & filename, FileName const & tempfile)
 {
@@ -95,7 +104,7 @@ bool layout2layout(FileName const & filename, FileName const & tempfile)
 }
 
 
-string translateRT(TextClass::ReadType rt) 
+string translateReadType(TextClass::ReadType rt) 
 {
        switch (rt) {
        case TextClass::BASECLASS:
@@ -187,6 +196,7 @@ enum TextClassTags {
        TC_RIGHTMARGIN,
        TC_FLOAT,
        TC_COUNTER,
+       TC_NOCOUNTER,
        TC_IFCOUNTER,
        TC_NOFLOAT,
        TC_TITLELATEXNAME,
@@ -197,7 +207,8 @@ enum TextClassTags {
        TC_DEFAULTMODULE,
        TC_PROVIDESMODULE,
        TC_EXCLUDESMODULE,
-       TC_HTMLTOCSECTION
+       TC_HTMLTOCSECTION,
+       TC_CITEFORMAT
 };
 
 
@@ -206,6 +217,7 @@ namespace {
        LexerKeyword textClassTags[] = {
                { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
                { "addtopreamble",     TC_ADDTOPREAMBLE },
+               { "citeformat",        TC_CITEFORMAT },
                { "classoptions",      TC_CLASSOPTIONS },
                { "columns",           TC_COLUMNS },
                { "counter",           TC_COUNTER },
@@ -222,6 +234,7 @@ namespace {
                { "input",             TC_INPUT },
                { "insetlayout",       TC_INSETLAYOUT },
                { "leftmargin",        TC_LEFTMARGIN },
+               { "nocounter",         TC_NOCOUNTER },
                { "nofloat",           TC_NOFLOAT },
                { "nostyle",           TC_NOSTYLE },
                { "outputformat",      TC_OUTPUTFORMAT },
@@ -245,7 +258,7 @@ namespace {
 
 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
 {
-       LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
+       LYXERR(Debug::TCLASS, "Converting layout file to " << LAYOUT_FORMAT);
        FileName const tempfile = FileName::tempName("convert_layout");
        bool success = layout2layout(filename, tempfile);
        if (success)
@@ -255,6 +268,29 @@ bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType
 }
 
 
+std::string TextClass::convert(std::string const & str)
+{
+       FileName const fn = FileName::tempName("locallayout");
+       ofstream os(fn.toFilesystemEncoding().c_str());
+       os << str;
+       os.close();
+       FileName const tempfile = FileName::tempName("convert_locallayout");
+       bool success = layout2layout(fn, tempfile);
+       if (!success)
+               return "";
+       ifstream is(tempfile.toFilesystemEncoding().c_str());
+       string ret;
+       string tmp;
+       while (!is.eof()) {
+               getline(is, tmp);
+               ret += tmp + '\n';
+       }
+       is.close();
+       tempfile.removeFile();
+       return ret;
+}
+
+
 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
 {
        if (!filename.isReadableFile()) {
@@ -263,8 +299,8 @@ TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, Re
                return ERROR;
        }
 
-       LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
-               to_utf8(makeDisplayPath(filename.absFilename())));
+       LYXERR(Debug::TCLASS, "Reading " + translateReadType(rt) + ": " +
+               to_utf8(makeDisplayPath(filename.absFileName())));
 
        // Define the plain layout used in table cells, ert, etc. Note that 
        // we do this before loading any layout file, so that classes can 
@@ -276,8 +312,8 @@ TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, Re
        lexrc.setFile(filename);
        ReturnValues retval = read(lexrc, rt);
        
-       LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
-                       to_utf8(makeDisplayPath(filename.absFilename())));
+       LYXERR(Debug::TCLASS, "Finished reading " + translateReadType(rt) + ": " +
+                       to_utf8(makeDisplayPath(filename.absFileName())));
 
        return retval;
 }
@@ -290,23 +326,21 @@ bool TextClass::read(FileName const & filename, ReadType rt)
                return retval == OK;
 
        bool const worx = convertLayoutFormat(filename, rt);
-       if (!worx) {
+       if (!worx)
                LYXERR0 ("Unable to convert " << filename << 
-                       " to format " << FORMAT);
-               return false;
-       }
-       return true;
+                       " to format " << LAYOUT_FORMAT);
+       return worx;
 }
 
 
-bool TextClass::validate(std::string const & str)
+TextClass::ReturnValues TextClass::validate(std::string const & str)
 {
        TextClass tc;
        return tc.read(str, VALIDATION);
 }
 
 
-bool TextClass::read(std::string const & str, ReadType rt) 
+TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt)
 {
        Lexer lexrc(textClassTags);
        istringstream is(str);
@@ -314,14 +348,14 @@ bool TextClass::read(std::string const & str, ReadType rt)
        ReturnValues retval = read(lexrc, rt);
 
        if (retval != FORMAT_MISMATCH) 
-               return retval == OK;
+               return retval;
 
        // write the layout string to a temporary file
        FileName const tempfile = FileName::tempName("TextClass_read");
        ofstream os(tempfile.toFilesystemEncoding().c_str());
        if (!os) {
                LYXERR0("Unable to create temporary file");
-               return false;
+               return ERROR;
        }
        os << str;
        os.close();
@@ -330,20 +364,23 @@ bool TextClass::read(std::string const & str, ReadType rt)
        bool const worx = convertLayoutFormat(tempfile, rt);
        if (!worx) {
                LYXERR0("Unable to convert internal layout information to format " 
-                       << FORMAT);
+                       << LAYOUT_FORMAT);
+               return ERROR;
        }
        tempfile.removeFile();
-       return worx;
+       return OK_OLDFORMAT;
 }
 
 
 // Reads a textclass structure from file.
 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt) 
 {
-       bool error = !lexrc.isOK();
+       if (!lexrc.isOK())
+               return ERROR;
 
        // Format of files before the 'Format' tag was introduced
        int format = 1;
+       bool error = false;
 
        // parsing
        while (lexrc.isOK() && !error) {
@@ -403,8 +440,7 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                                        lexrc.printError("Could not find input file: " + inc);
                                        error = true;
                                } else if (!read(tmp, MERGE)) {
-                                       lexrc.printError("Error reading input"
-                                                        "file: " + tmp.absFilename());
+                                       lexrc.printError("Error reading input file: " + tmp.absFileName());
                                        error = true;
                                }
                        }
@@ -432,7 +468,7 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                        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());
+                               lexrc.printError(s);
                                Layout lay;
                                // Since we couldn't read the name, we just scan the rest
                                // of the style and discard it.
@@ -454,10 +490,10 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                                }
                        }
                        else {
+                               // this was an ifstyle where we didn't have the style
                                // scan the rest and discard it
                                Layout lay;
                                readStyle(lexrc, lay);
-                               error = false;
                        }
 
                        // reset flag
@@ -612,12 +648,13 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                        if (name.empty()) {
                                string s = "Could not read name for InsetLayout: `$$Token' "
                                        + lexrc.getString() + " is probably not valid UTF-8!";
-                               lexrc.printError(s.c_str());
+                               lexrc.printError(s);
                                InsetLayout il;
                                // Since we couldn't read the name, we just scan the rest
                                // of the style and discard it.
                                il.read(lexrc, *this);
-                               error = true;
+                               // Let's try to continue rather than abort.
+                               // error = true;
                        } else if (hasInsetLayout(name)) {
                                InsetLayout & il = insetlayoutlist_[name];
                                error = !il.read(lexrc, *this);
@@ -632,7 +669,19 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                }
 
                case TC_FLOAT:
-                       readFloat(lexrc);
+                       error = !readFloat(lexrc);
+                       break;
+               
+               case TC_CITEFORMAT:
+                       readCiteFormat(lexrc);
+                       break;
+
+               case TC_NOCOUNTER:
+                       if (lexrc.next()) {
+                               docstring const cnt = lexrc.getDocString();
+                               if (!counters_.remove(cnt))
+                                       LYXERR0("Unable to remove counter: " + to_utf8(cnt));
+                       }
                        break;
 
                case TC_IFCOUNTER:
@@ -676,22 +725,24 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                        break;
                } // end of switch
 
-               //Note that this is triggered the first time through the loop unless
-               //we hit a format tag.
-               if (format != FORMAT)
-                       break;
+               // Note that this is triggered the first time through the loop unless
+               // we hit a format tag.
+               if (format != LAYOUT_FORMAT)
+                       return FORMAT_MISMATCH;
        }
 
-       if (format != FORMAT)
-               return FORMAT_MISMATCH;
+       // at present, we abort if we encounter an error,
+       // so there is no point continuing.
+       if (error)
+               return ERROR;
 
-       if (rt != BASECLASS) 
+       if (rt != BASECLASS)
                return (error ? ERROR : OK);
 
        if (defaultlayout_.empty()) {
                LYXERR0("Error: Textclass '" << name_
                                                << "' is missing a defaultstyle.");
-               error = true;
+               return ERROR;
        }
                
        // Try to erase "stdinsets" from the provides_ set. 
@@ -709,11 +760,11 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                FileName tmp = libFileSearch("layouts", "stdinsets.inc");
 
                if (tmp.empty()) {
-                       throw ExceptionMessage(WarningException, _("Missing File"),
+                       frontend::Alert::warning(_("Missing File"),
                                _("Could not find stdinsets.inc! This may lead to data loss!"));
                        error = true;
                } else if (!read(tmp, MERGE)) {
-                       throw ExceptionMessage(WarningException, _("Corrupt File"),
+                       frontend::Alert::warning(_("Corrupt File"),
                                _("Could not read stdinsets.inc! This may lead to data loss!"));
                        error = true;
                }
@@ -818,7 +869,8 @@ void TextClass::readClassOptions(Lexer & lexrc)
                case Lexer::LEX_UNDEF:
                        lexrc.printError("Unknown ClassOption tag `$$Token'");
                        continue;
-               default: break;
+               default:
+                       break;
                }
                switch (le) {
                case CO_FONTSIZE:
@@ -831,7 +883,10 @@ void TextClass::readClassOptions(Lexer & lexrc)
                        break;
                case CO_OTHER:
                        lexrc.next();
-                       options_ = lexrc.getString();
+                       if (options_.empty())
+                               options_ = lexrc.getString();
+                       else
+                               options_ += ',' + lexrc.getString();
                        break;
                case CO_HEADER:
                        lexrc.next();
@@ -846,7 +901,29 @@ void TextClass::readClassOptions(Lexer & lexrc)
 }
 
 
-void TextClass::readFloat(Lexer & lexrc)
+void TextClass::readCiteFormat(Lexer & lexrc)
+{
+       string etype;
+       string definition;
+       while (lexrc.isOK()) {
+               lexrc.next();
+               etype = lexrc.getString();
+               if (!lexrc.isOK() || compare_ascii_no_case(etype, "end") == 0)
+                       break;
+               lexrc.eatLine();
+               definition = lexrc.getString();
+               char initchar = etype[0];
+               if (initchar == '#')
+                       continue;
+               if (initchar == '!' || initchar == '_')
+                       cite_macros_[etype] = definition;
+               else
+                       cite_formats_[etype] = definition;
+       }
+}
+
+
+bool TextClass::readFloat(Lexer & lexrc)
 {
        enum {
                FT_TYPE = 1,
@@ -856,11 +933,13 @@ void TextClass::readFloat(Lexer & lexrc)
                FT_WITHIN,
                FT_STYLE,
                FT_LISTNAME,
-               FT_NEEDSFLOAT,
+               FT_USESFLOAT,
+               FT_PREDEFINED,
                FT_HTMLSTYLE,
                FT_HTMLATTR,
                FT_HTMLTAG,
                FT_LISTCOMMAND,
+               FT_REFPREFIX,
                FT_END
        };
 
@@ -871,13 +950,15 @@ void TextClass::readFloat(Lexer & lexrc)
                { "htmlattr", FT_HTMLATTR },
                { "htmlstyle", FT_HTMLSTYLE },
                { "htmltag", FT_HTMLTAG },
+               { "ispredefined", FT_PREDEFINED },
                { "listcommand", FT_LISTCOMMAND },
                { "listname", FT_LISTNAME },
-               { "needsfloatpkg", FT_NEEDSFLOAT },
                { "numberwithin", FT_WITHIN },
                { "placement", FT_PLACEMENT },
+               { "refprefix", FT_REFPREFIX },
                { "style", FT_STYLE },
-               { "type", FT_TYPE }
+               { "type", FT_TYPE },
+               { "usesfloatpkg", FT_USESFLOAT }
        };
 
        lexrc.pushTable(floatTags);
@@ -886,14 +967,16 @@ void TextClass::readFloat(Lexer & lexrc)
        string htmlattr;
        string htmlstyle;
        string htmltag;
-       string listName;
-       string listCommand;
+       string listname;
+       string listcommand;
        string name;
        string placement;
+       string refprefix;
        string style;
        string type;
        string within;
-       bool needsfloat = true;
+       bool usesfloat = true;
+       bool ispredefined = false;
 
        bool getout = false;
        while (!getout && lexrc.isOK()) {
@@ -902,7 +985,8 @@ void TextClass::readFloat(Lexer & lexrc)
                case Lexer::LEX_UNDEF:
                        lexrc.printError("Unknown float tag `$$Token'");
                        continue;
-               default: break;
+               default:
+                       break;
                }
                switch (le) {
                case FT_TYPE:
@@ -915,9 +999,11 @@ void TextClass::readFloat(Lexer & lexrc)
                                within = fl.within();
                                style = fl.style();
                                name = fl.name();
-                               listName = fl.listName();
-                               needsfloat = fl.needsFloatPkg();
-                               listCommand = fl.listCommand();
+                               listname = fl.listName();
+                               usesfloat = fl.usesFloatPkg();
+                               ispredefined = fl.isPredefined();
+                               listcommand = fl.listCommand();
+                               refprefix = fl.refPrefix();
                        } 
                        break;
                case FT_NAME:
@@ -944,15 +1030,23 @@ void TextClass::readFloat(Lexer & lexrc)
                        break;
                case FT_LISTCOMMAND:
                        lexrc.next();
-                       listCommand = lexrc.getString();
+                       listcommand = lexrc.getString();
+                       break;
+               case FT_REFPREFIX:
+                       lexrc.next();
+                       refprefix = lexrc.getString();
                        break;
                case FT_LISTNAME:
                        lexrc.next();
-                       listName = lexrc.getString();
+                       listname = lexrc.getString();
                        break;
-               case FT_NEEDSFLOAT:
+               case FT_USESFLOAT:
                        lexrc.next();
-                       needsfloat = lexrc.getBool();
+                       usesfloat = lexrc.getBool();
+                       break;
+               case FT_PREDEFINED:
+                       lexrc.next();
+                       ispredefined = lexrc.getBool();
                        break;
                case FT_HTMLATTR:
                        lexrc.next();
@@ -972,15 +1066,30 @@ void TextClass::readFloat(Lexer & lexrc)
                }
        }
 
+       lexrc.popTable();
+
        // Here we have a full float if getout == true
        if (getout) {
-               if (!needsfloat && listCommand.empty())
-                       LYXERR0("The layout does not provide a list command " <<
-                               "for the builtin float `" << type << "'. LyX will " <<
-                               "not be able to produce a float list.");
+               if (!usesfloat && listcommand.empty()) {
+                       // if this float uses the same auxfile as an existing one,
+                       // there is no need for it to provide a list command.
+                       FloatList::const_iterator it = floatlist_.begin();
+                       FloatList::const_iterator en = floatlist_.end();
+                       bool found_ext = false;
+                       for (; it != en; ++it) {
+                               if (it->second.ext() == ext) {
+                                       found_ext = true;
+                                       break;
+                               }
+                       }
+                       if (!found_ext)
+                               LYXERR0("The layout does not provide a list command " <<
+                                 "for the float `" << type << "'. LyX will " <<
+                                 "not be able to produce a float list.");
+               }
                Floating fl(type, placement, ext, within, style, name, 
-                               listName, listCommand, htmltag, htmlattr, htmlstyle
-                               needsfloat);
+                               listname, listcommand, refprefix
+                               htmltag, htmlattr, htmlstyle, usesfloat, ispredefined);
                floatlist_.newFloat(fl);
                // each float has its own counter
                counters_.newCounter(from_ascii(type), from_ascii(within),
@@ -990,11 +1099,19 @@ void TextClass::readFloat(Lexer & lexrc)
                counters_.newCounter(subtype, from_ascii(type),
                                      "\\alph{" + subtype + "}", docstring());
        }
-
-       lexrc.popTable();
+       return getout;
 }
 
 
+string const & TextClass::prerequisites() const
+{ 
+       if (contains(prerequisites_, ',')) {
+               vector<string> const pres = getVectorFromString(prerequisites_);
+               prerequisites_ = getStringFromVector(pres, "\n\t");
+       }
+       return prerequisites_; 
+}
+
 bool TextClass::hasLayout(docstring const & n) const
 {
        docstring const name = n.empty() ? defaultLayoutName() : n;
@@ -1093,20 +1210,24 @@ bool TextClass::load(string const & path) const
 
        if (!loaded_) {
                lyxerr << "Error reading `"
-                      << to_utf8(makeDisplayPath(layout_file.absFilename()))
+                      << to_utf8(makeDisplayPath(layout_file.absFileName()))
                       << "'\n(Check `" << name_
                       << "')\nCheck your installation and "
-                       "try Options/Reconfigure..." << endl;
+                         "try Options/Reconfigure..." 
+                      << endl;
        }
 
        return loaded_;
 }
 
 
-void DocumentClass::addLayoutIfNeeded(docstring const & n) const
+bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
 {
-       if (!hasLayout(n))
-               layoutlist_.push_back(createBasicLayout(n, true));
+       if (hasLayout(n))
+               return false;
+
+       layoutlist_.push_back(createBasicLayout(n, true));
+       return true;
 }
 
 
@@ -1131,7 +1252,6 @@ InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
 
 docstring const & TextClass::defaultLayoutName() const
 {
-       // This really should come from the actual layout... (Lgb)
        return defaultlayout_;
 }
 
@@ -1229,22 +1349,26 @@ DocumentClass & DocumentClassBundle::makeDocumentClass(
                                                "this document but has not been found in the list of\n"
                                                "available modules. If you recently installed it, you\n"
                                                "probably need to reconfigure LyX.\n"), from_utf8(modName));
-                       ExceptionMessage(WarningException,_("Module not available"),
-                                       msg + _("Some layouts may not be available."));
+                       frontend::Alert::warning(_("Module not available"), msg);
                        continue;
                }
                if (!lm->isAvailable()) {
+                       docstring const prereqs = from_utf8(getStringFromVector(lm->prerequisites(), "\n\t"));
                        docstring const msg =
-                                               bformat(_("The module %1$s requires a package that is\n"
-                                               "not available in your LaTeX installation. LaTeX output\n"
-                                               "may not be possible.\n"), from_utf8(modName));
-                       ExceptionMessage(WarningException, _("Package not available"), msg);
+                               bformat(_("The module %1$s requires a package that is not\n"
+                                       "available in your LaTeX installation, or a converter that\n"
+                                       "you have not installed. LaTeX output may not be possible.\n"
+                                       "Missing prerequisites:\n"
+                                               "\t%2$s\n"
+                                       "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
+                               from_utf8(modName), prereqs);
+                       frontend::Alert::warning(_("Package not available"), msg, true);
                }
                FileName layout_file = libFileSearch("layouts", lm->getFilename());
                if (!doc_class.read(layout_file, TextClass::MODULE)) {
                        docstring const msg =
                                                bformat(_("Error reading module %1$s\n"), from_utf8(modName));
-                       throw ExceptionMessage(WarningException, _("Read Error"), msg);
+                       frontend::Alert::warning(_("Read Error"), msg);
                }
        }
        return doc_class;
@@ -1311,6 +1435,27 @@ Layout const & DocumentClass::htmlTOCLayout() const
 }
 
 
+string const & DocumentClass::getCiteFormat(string const & entry_type) const
+{
+       static string default_format = "{%author%[[%author%, ]][[{%editor%[[%editor%, ed., ]]}]]}\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]][[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}.";
+       
+       map<string, string>::const_iterator it = cite_formats_.find(entry_type);
+       if (it != cite_formats_.end())
+               return it->second;
+       return default_format;
+}
+
+
+string const & DocumentClass::getCiteMacro(string const & macro) const
+{
+       static string empty;
+       map<string, string>::const_iterator it = cite_macros_.find(macro);
+       if (it != cite_macros_.end())
+               return it->second;
+       return empty;
+}
+
+
 /////////////////////////////////////////////////////////////////////////
 //
 // PageSides