Add support for document-local layout information. GUI is to follow.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@23913 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Richard Heck 2008-03-24 12:31:07 +00:00
parent bcf91dd85c
commit 700af7e701
9 changed files with 170 additions and 33 deletions

View File

@ -1,6 +1,9 @@
LyX file-format changes
-----------------------
2008-03-24 Richard Heck <rgheck@comcast.net>
* Format incremented to 322: local layout
2008-03-18 Edwin Leuven <e.leuven@uva.nl>
* Format incremented to 321: drop row/col lines and ensure
consistency between cell and row/col lines.

View File

@ -80,7 +80,7 @@ format_relation = [("0_06", [200], minor_versions("0.6" , 4)),
("1_3", [221], minor_versions("1.3" , 7)),
("1_4", range(222,246), minor_versions("1.4" , 5)),
("1_5", range(246,277), minor_versions("1.5" , 2)),
("1_6", range(277,322), minor_versions("1.6" , 0))]
("1_6", range(277,323), minor_versions("1.6" , 0))] # rgh: local layout
def formats_list():

View File

@ -1631,6 +1631,21 @@ def revert_protected_hfill(document):
'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
def revert_local_layout(document):
' Revert local layout headers.'
i = 0
while True:
i = find_token(document.header, "\\begin_local_layout", i)
if i == -1:
return
j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
if j == -1:
# this should not happen
break
document.header[i : j + 1] = []
##
# Conversion hub
#
@ -1680,10 +1695,12 @@ convert = [[277, [fix_wrong_tables]],
[318, []],
[319, [convert_spaceinset, convert_hfill]],
[320, []],
[321, [convert_tablines]]
[321, [convert_tablines]],
[322, []]
]
revert = [[320, [revert_tablines]],
revert = [[321, [revert_local_layout]],
[320, [revert_tablines]],
[319, [revert_protected_hfill]],
[318, [revert_spaceinset, revert_hfills, revert_hspace]],
[317, [remove_extra_embedded_files]],

View File

@ -116,7 +116,7 @@ namespace os = support::os;
namespace {
int const LYX_FORMAT = 321;
int const LYX_FORMAT = 322; // rgh: local layout
typedef map<string, bool> DepClean;
typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;

View File

@ -506,6 +506,8 @@ string BufferParams::readToken(Lexer & lex, string const & token,
} else if (token == "\\begin_preamble") {
readPreamble(lex);
} else if (token == "\\begin_local_layout") {
readLocalLayout(lex);
} else if (token == "\\begin_modules") {
readModules(lex);
} else if (token == "\\options") {
@ -722,6 +724,15 @@ void BufferParams::writeFile(ostream & os) const
os << "\\end_modules" << '\n';
}
// local layout information
if (!local_layout.empty()) {
// remove '\n' from the end
string const tmplocal = rtrim(local_layout, "\n");
os << "\\begin_local_layout\n"
<< tmplocal
<< "\n\\end_local_layout\n";
}
// then the text parameters
if (language != ignore_language)
os << "\\language " << language->lang() << '\n';
@ -1501,6 +1512,12 @@ void BufferParams::makeDocumentClass()
frontend::Alert::warning(_("Read Error"), msg);
}
}
if (!local_layout.empty()) {
if (!doc_class_->read(local_layout, TextClass::MODULE)) {
docstring const msg = _("Error reading internal layout information");
frontend::Alert::warning(_("Read Error"), msg);
}
}
}
@ -1555,6 +1572,16 @@ void BufferParams::readPreamble(Lexer & lex)
}
void BufferParams::readLocalLayout(Lexer & lex)
{
if (lex.getString() != "\\begin_local_layout")
lyxerr << "Error (BufferParams::readLocalLayout):"
"consistency check failed." << endl;
local_layout = lex.getLongString("\\end_local_layout");
}
void BufferParams::readLanguage(Lexer & lex)
{
if (!lex.next()) return;

View File

@ -220,6 +220,8 @@ public:
///
std::string preamble;
///
std::string local_layout;
///
std::string options;
///
std::string float_placement;
@ -316,6 +318,8 @@ private:
///
void readPreamble(Lexer &);
///
void readLocalLayout(Lexer &);
///
void readLanguage(Lexer &);
///
void readGraphicsDriver(Lexer &);

View File

@ -36,6 +36,7 @@
#include "support/os.h"
#include <algorithm>
#include <fstream>
#include <sstream>
#include "boost/assert.hpp"
@ -101,6 +102,8 @@ std::string translateRT(TextClass::ReadType rt)
return "input file";
case TextClass::MODULE:
return "module file";
case TextClass::VALIDATION:
return "validation";
}
// shutup warning
return string();
@ -180,14 +183,7 @@ enum TextClassTags {
};
// Reads a textclass structure from file.
bool TextClass::read(FileName const & filename, ReadType rt)
{
if (!filename.isReadableFile()) {
lyxerr << "Cannot read layout file `" << filename << "'."
<< endl;
return false;
}
namespace {
keyword_item textClassTags[] = {
{ "classoptions", TC_CLASSOPTIONS },
@ -217,13 +213,35 @@ bool TextClass::read(FileName const & filename, ReadType rt)
{ "tocdepth", TC_TOCDEPTH }
};
} //namespace anon
bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
{
LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
FileName const tempfile = FileName::tempName();
bool success = layout2layout(filename, tempfile);
if (success)
success = read(tempfile, rt);
tempfile.removeFile();
return success;
}
bool TextClass::read(FileName const & filename, ReadType rt)
{
if (!filename.isReadableFile()) {
lyxerr << "Cannot read layout file `" << filename << "'."
<< endl;
return false;
}
LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
to_utf8(makeDisplayPath(filename.absFilename())));
// Define the `empty' layout used in table cells, ert, etc. Note that
// we do this before loading any layout file, so that classes can
// override features of this layout if they should choose to do so.
if (rt == BASECLASS) {
if (rt == BASECLASS && !hasLayout(emptylayout_)) {
static char const * s = "Margin Static\n"
"LatexType Paragraph\n"
"LatexName dummy\n"
@ -243,11 +261,71 @@ bool TextClass::read(FileName const & filename, ReadType rt)
};
layoutlist_.push_back(lay);
}
Lexer lexrc(textClassTags,
sizeof(textClassTags) / sizeof(textClassTags[0]));
lexrc.setFile(filename);
ReturnValues retval = read(lexrc, rt);
LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
to_utf8(makeDisplayPath(filename.absFilename())));
if (retval != FORMAT_MISMATCH)
return retval == OK;
bool const worx = convertLayoutFormat(filename, rt);
if (!worx) {
lyxerr << "Unable to convert " << filename <<
" to format " << FORMAT << std::endl;
return false;
}
return true;
}
bool TextClass::validate(std::string const & str)
{
TextClass tc;
return tc.read(str, VALIDATION);
}
bool TextClass::read(std::string const & str, ReadType rt)
{
Lexer lexrc(textClassTags,
sizeof(textClassTags) / sizeof(textClassTags[0]));
istringstream is(str);
lexrc.setStream(is);
ReturnValues retval = read(lexrc, rt);
if (retval != FORMAT_MISMATCH)
return retval == OK;
// write the layout string to a temporary file
FileName const tempfile = FileName::tempName();
ofstream os(tempfile.toFilesystemEncoding().c_str());
if (!os) {
lyxerr << "Unable to create tempoary file in TextClass::read!!"
<< std::endl;
return false;
}
os << str;
os.close();
// now try to convert it
bool const worx = convertLayoutFormat(tempfile, rt);
if (!worx) {
lyxerr << "Unable to convert internal layout information to format "
<< FORMAT << std::endl;
}
tempfile.removeFile();
return worx;
}
// Reads a textclass structure from file.
TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
{
bool error = !lexrc.isOK();
// Format of files before the 'Format' tag was introduced
@ -316,9 +394,8 @@ bool TextClass::read(FileName const & filename, ReadType rt)
+ lexrc.getString() + " is probably not valid UTF-8!";
lexrc.printError(s.c_str());
Layout lay;
//FIXME If we're just dropping this layout, do we really
//care whether there's an error?? Or should we just set
//error to true, since we couldn't even read the name?
// Since we couldn't read the name, we just scan the rest
// of the style and discard it.
error = !readStyle(lexrc, lay);
} else if (hasLayout(name)) {
Layout & lay = operator[](name);
@ -482,22 +559,11 @@ bool TextClass::read(FileName const & filename, ReadType rt)
break;
}
if (format != FORMAT) {
LYXERR(Debug::TCLASS, "Converting layout file from format "
<< format << " to " << FORMAT);
FileName const tempfile = FileName::tempName();
bool success = layout2layout(filename, tempfile);
if (success)
read(tempfile, rt);
tempfile.removeFile();
return success;
}
LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
to_utf8(makeDisplayPath(filename.absFilename())));
if (format != FORMAT)
return FORMAT_MISMATCH;
if (rt != BASECLASS)
return !error;
return (error ? ERROR : OK);
if (defaultlayout_.empty()) {
lyxerr << "Error: Textclass '" << name_
@ -547,7 +613,7 @@ bool TextClass::read(FileName const & filename, ReadType rt)
LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
<< ", maximum is " << max_toclevel_);
return !error;
return (error ? ERROR : OK);
}

View File

@ -127,11 +127,25 @@ public:
enum ReadType {
BASECLASS, //>This is a base class, i.e., top-level layout file
MERGE, //>This is a file included in a layout file
MODULE //>This is a layout module
MODULE, //>This is a layout module
VALIDATION //>We're just validating
};
/// return values for read()
enum ReturnValues {
OK,
ERROR,
FORMAT_MISMATCH
};
/// Performs the read of the layout file.
/// \return true on success.
bool read(support::FileName const & filename, ReadType rt = BASECLASS);
///
bool read(std::string const & str, ReadType rt = BASECLASS);
///
ReturnValues read(Lexer & lex, ReadType rt = BASECLASS);
/// validates the layout information passed in str
static bool validate(std::string const & str);
///////////////////////////////////////////////////////////////////
// loading
@ -242,6 +256,8 @@ private:
///////////////////////////////////////////////////////////////////
///
bool deleteLayout(docstring const &);
///
bool convertLayoutFormat(support::FileName const &, ReadType);
/// \return true for success.
bool readStyle(Lexer &, Layout &);
///

View File

@ -1296,6 +1296,10 @@ void GuiDocument::classChanged()
return;
}
}
// FIXME Note that by doing things this way, we load the TextClass
// as soon as it is selected. So, if you use the scroll wheel when
// sitting on the combo box, we'll load a lot of TextClass objects
// very quickly. This could be changed.
if (!bp_.setBaseClass(classname)) {
Alert::error(_("Error"), _("Unable to set document class."));
return;