mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-26 19:25:39 +00:00
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:
parent
be73bdd410
commit
48f9225e27
@ -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.
|
||||
embeddedFiles().enable(params().embedded, *this, false);
|
||||
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();
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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."));
|
||||
|
Loading…
Reference in New Issue
Block a user