Embed: allow the use of embedded layout and class (.cls, .sty) files.

* src/EmbeddedFiles.h|cpp: add validate() function to validate loaded .lyx file.
	* src/LayoutFile.h|cpp: add Layout_Type parameter to addLayoutFile to load an embedded layout.
	* src/BufferParams.h|cpp: read layout from temp directory, then local directory.
	* src/frontends/qt4/GuiDocument.cpp: handle embedded layout type
	* src/LyXFunc.cpp: handle embedded layout when a layout is re-read.
	* src/Buffer.cpp: validate after a buffer is read. handle exceptions properly.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@23667 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Bo Peng 2008-03-11 18:31:38 +00:00
parent be73bdd410
commit 48f9225e27
9 changed files with 116 additions and 19 deletions

View File

@ -502,7 +502,8 @@ int Buffer::readHeader(Lexer & lex)
LYXERR(Debug::PARSER, "Handling document header token: `"
<< token << '\'');
string unknown = params().readToken(lex, token, d->filename.onlyPath());
string unknown = params().readToken(lex, token, d->filename.onlyPath(),
d->temppath);
if (!unknown.empty()) {
if (unknown[0] != '\\' && token == "\\textclass") {
Alert::warning(_("Unknown document class"),
@ -577,7 +578,19 @@ bool Buffer::readDocument(Lexer & lex)
// Enable embeded files, which will set temp path and move
// inconsistent inzip files if needed.
try {
embeddedFiles().validate(*this);
embeddedFiles().enable(params().embedded, *this, false);
} catch (ExceptionMessage const & message) {
Alert::error(message.title_, message.details_);
Alert::warning(_("Failed to read embedded files"),
_("Due to most likely a bug, LyX failed to locate all embedded "
"file. If you unzip the LyX file, you should be able to see and "
"open content.lyx which is your main text. You may also be able "
"to recover some embedded files. Please report this bug to the "
"lyx-devel mailing list."));
return false;
}
updateMacros();
updateMacroInstances();

View File

@ -469,7 +469,7 @@ void BufferParams::setDefSkip(VSpace const & vs)
string const BufferParams::readToken(Lexer & lex, string const & token,
FileName const & filepath)
FileName const & filepath, FileName const & temppath)
{
if (token == "\\textclass") {
lex.next();
@ -478,8 +478,10 @@ string const BufferParams::readToken(Lexer & lex, string const & token,
// NOTE: in this case, the textclass (.cls file) is assumed to be available.
string tcp;
LayoutFileList & bcl = LayoutFileList::get();
if (!filepath.empty())
tcp = bcl.addLayoutFile(classname, filepath.absFilename());
if (!temppath.empty())
tcp = bcl.addLayoutFile(classname, temppath.absFilename(), LayoutFileList::Embedded);
if (tcp.empty() && !filepath.empty())
tcp = bcl.addLayoutFile(classname, filepath.absFilename(), LayoutFileList::Local);
if (!tcp.empty())
setBaseClass(tcp);
else if (bcl.haveClass(classname)) {

View File

@ -70,7 +70,8 @@ public:
/// read a header token, if unrecognised, return it or an unknown class name
std::string const readToken(Lexer & lex,
std::string const & token, ///< token to read.
support::FileName const & filepath); ///< where to look for local layout file.
support::FileName const & filepath,
support::FileName const & temppath); ///< where to look for local layout file.
///
void writeFile(std::ostream &) const;

View File

@ -129,8 +129,6 @@ void EmbeddedFile::enable(bool flag, Buffer const * buf, bool updateFile)
if (!suffixIs(temp_path_, '/'))
temp_path_ += '/';
if (embedded()) {
if (inzip_name_ != calcInzipName(buf->filePath()))
syncInzipFile(buf->filePath());
if (updateFile)
updateFromExternalFile();
}
@ -299,8 +297,14 @@ an absolute filename can be saved as
$temp/$embDirName/$absDirName/a/absolute/path for /a/absolute/path
FIXME:
embDirName is set to . so that embedded layout and class files can be
used directly. However, putting all embedded files directly under
the temp directory may lead to file conflicts. For example, if a user
embeds a file blah.log in blah.lyx, it will be replaced when
'latex blah.tex' is called.
*/
const std::string embDirName = "LyX.Embedded.Files";
const std::string embDirName = ".";
const std::string upDirName = "LyX.Embed.Dir.Up";
const std::string absDirName = "LyX.Embed.Dir.Abs";
const std::string driveName = "LyX.Embed.Drive";
@ -334,12 +338,18 @@ void EmbeddedFile::syncInzipFile(std::string const & buffer_path)
string old_emb_file = temp_path_ + '/' + inzip_name_;
FileName old_emb(old_emb_file);
if (!old_emb.exists())
throw ExceptionMessage(ErrorException, _("Failed to open file"),
bformat(_("Embedded file %1$s does not exist. Did you tamper lyx temporary directory?"),
old_emb.displayName()));
string new_inzip_name = calcInzipName(buffer_path);
if (new_inzip_name == inzip_name_)
return;
LYXERR(Debug::FILES, " OLD ZIP " << old_emb_file <<
" NEW ZIP " << calcInzipName(buffer_path));
//BOOST_ASSERT(old_emb.exists());
string new_inzip_name = calcInzipName(buffer_path);
string new_emb_file = temp_path_ + '/' + new_inzip_name;
FileName new_emb(new_emb_file);
@ -450,6 +460,46 @@ void EmbeddedFileList::registerFile(EmbeddedFile const & file,
}
void EmbeddedFileList::validate(Buffer const & buffer)
{
clear();
for (InsetIterator it = inset_iterator_begin(buffer.inset()); it; ++it)
it->registerEmbeddedFiles(*this);
iterator it = begin();
iterator it_end = end();
for (; it != it_end; ++it) {
if (buffer.embedded() && it->embedded())
// An exception will be raised if inzip file does not exist
it->syncInzipFile(buffer.filePath());
else
// inzipName may be OS dependent
it->setInzipName(it->calcInzipName(buffer.filePath()));
}
for (it = begin(); it != it_end; ++it)
it->updateInsets();
if (!buffer.embedded())
return;
// check if extra embedded files exist
vector<string> extra = buffer.params().extraEmbeddedFiles();
vector<string>::iterator e_it = extra.begin();
vector<string>::iterator e_end = extra.end();
for (; e_it != e_end; ++e_it) {
EmbeddedFile file = EmbeddedFile(*e_it, buffer.filePath());
// do not update from external file
file.enable(true, &buffer, false);
// but we do need to check file existence.
if (!FileName(file.embeddedFile()).exists())
throw ExceptionMessage(ErrorException, _("Failed to open file"),
bformat(_("Embedded file %1$s does not exist. Did you tamper lyx temporary directory?"),
file.displayName()));
}
}
void EmbeddedFileList::update(Buffer const & buffer)
{
clear();
@ -464,7 +514,7 @@ void EmbeddedFileList::update(Buffer const & buffer)
for (; it != it_end; ++it) {
EmbeddedFile file = EmbeddedFile(*it, buffer.filePath());
file.setEmbed(true);
file.enable(buffer.embedded(), &buffer, true);
file.enable(buffer.embedded(), &buffer, false);
insert(end(), file);
}
}

View File

@ -166,7 +166,6 @@ public:
/// Calculate checksum of availableFile
unsigned long checksum() const;
private:
// calculate inzip_name_ from filename
std::string calcInzipName(std::string const & buffer_path);
// move an embedded disk file with an existing inzip_name_ to
@ -205,6 +204,9 @@ public:
*/
void registerFile(EmbeddedFile const & file, Inset const * inset, Buffer const & buffer);
/// validate embedded fies after a file is read.
void validate(Buffer const & buffer);
/// scan the buffer and get a list of EmbeddedFile
void update(Buffer const & buffer);

View File

@ -186,10 +186,12 @@ void LayoutFileList::reset(LayoutFileIndex const & classname) {
string const LayoutFileList::localPrefix = "LOCAL:";
string const LayoutFileList::embeddedPrefix = "EMBED:";
LayoutFileIndex
LayoutFileList::addLayoutFile(string const & textclass, string const & path)
LayoutFileList::addLayoutFile(string const & textclass, string const & path,
Layout_Type type)
{
// FIXME There is a bug here: 4593
//
@ -197,7 +199,12 @@ LayoutFileIndex
// NOTE: latex class name is defined in textclass.layout, which can be
// different from textclass
string fullName = addName(path, textclass + ".layout");
string localIndex = localPrefix + fullName;
string localIndex;
if (type == Local)
localIndex = localPrefix + fullName;
else if (type == Embedded)
localIndex = embeddedPrefix + textclass;
// if the local file has already been loaded, return it
if (haveClass(localIndex))

View File

@ -86,15 +86,24 @@ public:
bool read();
/// Clears the textclass so as to force it to be reloaded
void reset(LayoutFileIndex const & tc);
enum Layout_Type {
System,
Local,
Embedded
};
/// add a textclass from user local directory.
/// \return the identifier for the loaded file, or else an
/// empty string if no file was loaded.
LayoutFileIndex
addLayoutFile(std::string const & textclass, std::string const & path);
addLayoutFile(std::string const & textclass, std::string const & path,
Layout_Type type);
/// a list of the available classes
std::vector<LayoutFileIndex> classList() const;
///
static std::string const localPrefix;
static std::string const embeddedPrefix;
private:
///
typedef std::map<std::string, LayoutFile *> ClassMap;

View File

@ -1579,7 +1579,8 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
BOOST_ASSERT(lyx_view_);
Buffer * buffer = lyx_view_->buffer();
if (!loadLayoutFile(argument, buffer->filePath()))
if (!loadLayoutFile(argument, buffer->temppath()) &&
!loadLayoutFile(argument, buffer->filePath()))
break;
LayoutFile const * old_layout = buffer->params().baseClass();
@ -1612,6 +1613,7 @@ void LyXFunc::dispatch(FuncRequest const & cmd)
}
case LFUN_TEXTCLASS_LOAD:
loadLayoutFile(argument, lyx_view_->buffer()->temppath()) ||
loadLayoutFile(argument, lyx_view_->buffer()->filePath());
break;

View File

@ -1242,7 +1242,8 @@ void GuiDocument::browseLayout()
string classname = layoutFile.onlyFileName();
LayoutFileIndex name = bcl.addLayoutFile(
classname.substr(0, classname.size() - 7),
layoutFile.onlyPath().absFilename());
layoutFile.onlyPath().absFilename(),
LayoutFileList::Local);
if (name.empty()) {
Alert::error(_("Error"),
@ -1284,6 +1285,16 @@ void GuiDocument::classChanged()
setLayoutComboByIDString(bp_.baseClassID());
return;
}
} else if (prefixIs(classname, LayoutFileList::embeddedPrefix)) {
int const ret = Alert::prompt(_("Embedded layout"),
_("The layout file you have selected is an embedded layout that\n"
"is embedded to a buffer. You cannot make use of it unless\n"
"it is already embedded to this buffer.\n"),
1, 1, _("&Set Layout"), _("&Cancel"));
if (ret == 1) {
setLayoutComboByIDString(bp_.baseClassID());
return;
}
}
if (!bp_.setBaseClass(classname)) {
Alert::error(_("Error"), _("Unable to set document class."));