mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 05:16:21 +00:00
Embedding patch two: read/write embedded files'
* src/insets/InsetGraphics.h * src/insets/InsetExternal.cpp * src/insets/InsetGraphics.cpp * src/insets/InsetInclude.cpp * src/insets/Inset.h * src/insets/InsetInclude.h * src/insets/InsetExternal.h: register embedded files * src/EmbeddedFiles.h|cpp: core of embedded files * src/Buffer.h|cpp: read/write embed file * src/BufferParams.h|cpp: embedded flag * src/Makefile.am * po/POTFILES.in * development/scons/scons_manifest.py: build system updates git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19924 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
edd3e65556
commit
692363bbca
@ -56,6 +56,7 @@ src_header_files = Split('''
|
||||
Dimension.h
|
||||
DispatchResult.h
|
||||
DocIterator.h
|
||||
EmbeddedFiles.h
|
||||
Encoding.h
|
||||
ErrorList.h
|
||||
Exporter.h
|
||||
@ -166,6 +167,7 @@ src_pre_files = Split('''
|
||||
CutAndPaste.cpp
|
||||
DepTable.cpp
|
||||
DocIterator.cpp
|
||||
EmbeddedFiles.cpp
|
||||
Encoding.cpp
|
||||
ErrorList.cpp
|
||||
Exporter.cpp
|
||||
|
@ -7,6 +7,7 @@ src/Chktex.cpp
|
||||
src/Color.cpp
|
||||
src/Converter.cpp
|
||||
src/CutAndPaste.cpp
|
||||
src/EmbeddedFiles.cpp
|
||||
src/Exporter.cpp
|
||||
src/Font.cpp
|
||||
src/Format.cpp
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "TocBackend.h"
|
||||
#include "Undo.h"
|
||||
#include "version.h"
|
||||
#include "EmbeddedFiles.h"
|
||||
|
||||
#include "insets/InsetBibitem.h"
|
||||
#include "insets/InsetBibtex.h"
|
||||
@ -98,6 +99,7 @@ using std::map;
|
||||
using std::ostream;
|
||||
using std::ostringstream;
|
||||
using std::ofstream;
|
||||
using std::ifstream;
|
||||
using std::pair;
|
||||
using std::stack;
|
||||
using std::vector;
|
||||
@ -132,6 +134,7 @@ using support::subst;
|
||||
using support::tempName;
|
||||
using support::trim;
|
||||
using support::sum;
|
||||
using support::unzipToDir;
|
||||
|
||||
namespace Alert = frontend::Alert;
|
||||
namespace os = support::os;
|
||||
@ -194,6 +197,9 @@ public:
|
||||
/// Container for all sort of Buffer dependant errors.
|
||||
map<string, ErrorList> errorLists;
|
||||
|
||||
/// all embedded files of this buffer
|
||||
EmbeddedFiles embedded_files;
|
||||
|
||||
/// timestamp and checksum used to test if the file has been externally
|
||||
/// modified. (Used to properly enable 'File->Revert to saved', bug 4114).
|
||||
time_t timestamp_;
|
||||
@ -204,7 +210,7 @@ public:
|
||||
Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_)
|
||||
: lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_),
|
||||
filename(file), file_fully_loaded(false), inset(params),
|
||||
toc_backend(&parent), timestamp_(0), checksum_(0)
|
||||
toc_backend(&parent), embedded_files(&parent), timestamp_(0), checksum_(0)
|
||||
{
|
||||
inset.setAutoBreakRows(true);
|
||||
lyxvc.buffer(&parent);
|
||||
@ -351,6 +357,18 @@ TocBackend const & Buffer::tocBackend() const
|
||||
}
|
||||
|
||||
|
||||
EmbeddedFiles & Buffer::embeddedFiles()
|
||||
{
|
||||
return pimpl_->embedded_files;
|
||||
}
|
||||
|
||||
|
||||
EmbeddedFiles const & Buffer::embeddedFiles() const
|
||||
{
|
||||
return pimpl_->embedded_files;
|
||||
}
|
||||
|
||||
|
||||
string const Buffer::getLatexName(bool const no_path) const
|
||||
{
|
||||
string const name = changeExtension(makeLatexName(fileName()), ".tex");
|
||||
@ -634,8 +652,32 @@ bool Buffer::readString(std::string const & s)
|
||||
|
||||
bool Buffer::readFile(FileName const & filename)
|
||||
{
|
||||
FileName fname(filename);
|
||||
// Check if the file is compressed.
|
||||
string const format = getFormatFromContents(filename);
|
||||
string format = getFormatFromContents(filename);
|
||||
if (format == "zip") {
|
||||
// decompress to a temp directory
|
||||
LYXERR(Debug::FILES) << filename << " is in zip format. Unzip to " << temppath() << endl;
|
||||
unzipToDir(filename.toFilesystemEncoding(), temppath());
|
||||
//
|
||||
FileName manifest(addName(temppath(), "manifest.txt"));
|
||||
FileName lyxfile(addName(temppath(),
|
||||
onlyFilename(filename.toFilesystemEncoding())));
|
||||
// if both manifest.txt and file.lyx exist, this is am embedded file
|
||||
if (fs::exists(manifest.toFilesystemEncoding()) &&
|
||||
fs::exists(lyxfile.toFilesystemEncoding())) {
|
||||
params().embedded = true;
|
||||
fname = lyxfile;
|
||||
// read manifest file
|
||||
ifstream is(manifest.toFilesystemEncoding().c_str());
|
||||
is >> pimpl_->embedded_files;
|
||||
is.close();
|
||||
LYXERR(Debug::FILES) << filename << " is a embedded file. Its manifest is:\n"
|
||||
<< pimpl_->embedded_files;
|
||||
}
|
||||
}
|
||||
// The embedded lyx file can also be compressed, for backward compatibility
|
||||
format = getFormatFromContents(fname);
|
||||
if (format == "gzip" || format == "zip" || format == "compress") {
|
||||
params().compressed = true;
|
||||
}
|
||||
@ -643,8 +685,8 @@ bool Buffer::readFile(FileName const & filename)
|
||||
// remove dummy empty par
|
||||
paragraphs().clear();
|
||||
Lexer lex(0, 0);
|
||||
lex.setFile(filename);
|
||||
if (readFile(lex, filename) != success)
|
||||
lex.setFile(fname);
|
||||
if (readFile(lex, fname) != success)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -845,20 +887,34 @@ bool Buffer::writeFile(FileName const & fname) const
|
||||
|
||||
bool retval = false;
|
||||
|
||||
FileName content;
|
||||
if (params().embedded)
|
||||
// first write the .lyx file to the temporary directory
|
||||
content = FileName(addName(temppath(),
|
||||
onlyFilename(fname.toFilesystemEncoding())));
|
||||
else
|
||||
content = fname;
|
||||
|
||||
if (params().compressed) {
|
||||
gz::ogzstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
|
||||
gz::ogzstream ofs(content.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
|
||||
if (!ofs)
|
||||
return false;
|
||||
|
||||
retval = write(ofs);
|
||||
} else {
|
||||
ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
|
||||
ofstream ofs(content.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
|
||||
if (!ofs)
|
||||
return false;
|
||||
|
||||
retval = write(ofs);
|
||||
}
|
||||
|
||||
if (retval && params().embedded) {
|
||||
// write file.lyx and all the embedded files to the zip file fname
|
||||
// if embedding is enabled, and there is any embedded file
|
||||
pimpl_->embedded_files.update();
|
||||
return pimpl_->embedded_files.write(fname);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -396,6 +396,11 @@ public:
|
||||
TocBackend & tocBackend();
|
||||
TocBackend const & tocBackend() const;
|
||||
//@}
|
||||
|
||||
//@{
|
||||
EmbeddedFiles & embeddedFiles();
|
||||
EmbeddedFiles const & embeddedFiles() const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
/** Inserts a file into a document
|
||||
|
@ -353,6 +353,9 @@ BufferParams::BufferParams()
|
||||
listings_params = string();
|
||||
pagestyle = "default";
|
||||
compressed = false;
|
||||
// temporarily enable embedding for testing. Will set to false
|
||||
// when embedding GUI is added
|
||||
embedded = true;
|
||||
for (int iter = 0; iter < 4; ++iter) {
|
||||
user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
|
||||
temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
|
||||
|
@ -261,6 +261,8 @@ public:
|
||||
std::string parentname;
|
||||
///
|
||||
bool compressed;
|
||||
///
|
||||
bool embedded;
|
||||
|
||||
/// the author list for the document
|
||||
AuthorList & authors();
|
||||
|
307
src/EmbeddedFiles.cpp
Normal file
307
src/EmbeddedFiles.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
// -*- C++ -*-
|
||||
/**
|
||||
* \file EmbeddedFiles.cpp
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Bo Peng
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "EmbeddedFiles.h"
|
||||
#include "Buffer.h"
|
||||
#include "BufferParams.h"
|
||||
#include "Paragraph.h"
|
||||
#include "ParIterator.h"
|
||||
#include "debug.h"
|
||||
#include "gettext.h"
|
||||
#include "Format.h"
|
||||
|
||||
#include "frontends/alert.h"
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
#include "support/filetools.h"
|
||||
#include "support/fs_extras.h"
|
||||
#include "support/convert.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
using std::ofstream;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::pair;
|
||||
using std::make_pair;
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
using std::getline;
|
||||
using std::istringstream;
|
||||
|
||||
namespace lyx {
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace Alert = frontend::Alert;
|
||||
|
||||
using support::FileName;
|
||||
using support::DocFileName;
|
||||
using support::makeAbsPath;
|
||||
using support::addName;
|
||||
using support::onlyPath;
|
||||
using support::absolutePath;
|
||||
using support::onlyFilename;
|
||||
using support::makeRelPath;
|
||||
using support::changeExtension;
|
||||
using support::bformat;
|
||||
using support::zipFiles;
|
||||
|
||||
|
||||
EmbeddedFile::EmbeddedFile(string const & file, string const & inzip_name,
|
||||
STATUS status, ParConstIterator const & pit)
|
||||
: DocFileName(file, true), inzip_name_(inzip_name), status_(status),
|
||||
par_it_(pit), valid_(true)
|
||||
{}
|
||||
|
||||
|
||||
string EmbeddedFile::embeddedFile(Buffer const * buf) const
|
||||
{
|
||||
return addName(buf->temppath(), inzip_name_);
|
||||
}
|
||||
|
||||
|
||||
void EmbeddedFile::setParIter(ParConstIterator const & pit)
|
||||
{
|
||||
par_it_ = pit;
|
||||
}
|
||||
|
||||
|
||||
bool EmbeddedFiles::enabled() const
|
||||
{
|
||||
return buffer_->params().embedded;
|
||||
}
|
||||
|
||||
|
||||
void EmbeddedFiles::enable(bool flag)
|
||||
{
|
||||
if (enabled() != flag) {
|
||||
// file will be changed
|
||||
buffer_->markDirty();
|
||||
buffer_->params().embedded = flag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EmbeddedFiles::registerFile(string const & filename,
|
||||
EmbeddedFile::STATUS status, ParConstIterator const & pit)
|
||||
{
|
||||
string abs_filename = makeAbsPath(filename, buffer_->filePath()).absFilename();
|
||||
// try to find this file from the list
|
||||
EmbeddedFileList::iterator it = file_list_.begin();
|
||||
EmbeddedFileList::iterator it_end = file_list_.end();
|
||||
for (; it != it_end; ++it)
|
||||
if (it->absFilename() == abs_filename)
|
||||
break;
|
||||
// find this filename
|
||||
if (it != file_list_.end()) {
|
||||
it->setParIter(pit);
|
||||
it->setStatus(status);
|
||||
it->validate();
|
||||
return;
|
||||
}
|
||||
// register a new one, using relative file path as inzip_name
|
||||
string inzip_name = to_utf8(makeRelPath(from_utf8(abs_filename),
|
||||
from_utf8(buffer_->fileName())));
|
||||
// if inzip_name is an absolute path, use filename only to avoid
|
||||
// leaking of filesystem information in inzip_name
|
||||
if (absolutePath(inzip_name))
|
||||
inzip_name = onlyFilename(inzip_name);
|
||||
// if this name has been used...
|
||||
// use _1_name, _2_name etc
|
||||
if (!validInzipName(inzip_name)) {
|
||||
size_t i = 1;
|
||||
string tmp = inzip_name;
|
||||
do {
|
||||
inzip_name = convert<string>(i) + "_" + tmp;
|
||||
} while (!validInzipName(inzip_name));
|
||||
}
|
||||
file_list_.push_back(EmbeddedFile(abs_filename, inzip_name, status, pit));
|
||||
}
|
||||
|
||||
|
||||
void EmbeddedFiles::update()
|
||||
{
|
||||
// invalidate all files, obsolete files will then not be validated by the
|
||||
// following document scan. These files will still be kept though, because
|
||||
// they may be added later and their embedding status will be meaningful
|
||||
// again (thinking of cut/paste of an InsetInclude).
|
||||
EmbeddedFileList::iterator it = file_list_.begin();
|
||||
EmbeddedFileList::iterator it_end = file_list_.end();
|
||||
for (; it != it_end; ++it)
|
||||
it->invalidate();
|
||||
|
||||
ParIterator pit = buffer_->par_iterator_begin();
|
||||
ParIterator pit_end = buffer_->par_iterator_end();
|
||||
for (; pit != pit_end; ++pit) {
|
||||
// For each paragraph, traverse its insets and register embedded files
|
||||
InsetList::const_iterator iit = pit->insetlist.begin();
|
||||
InsetList::const_iterator iit_end = pit->insetlist.end();
|
||||
for (; iit != iit_end; ++iit) {
|
||||
Inset & inset = *iit->inset;
|
||||
inset.registerEmbeddedFiles(*buffer_, *this, pit);
|
||||
}
|
||||
}
|
||||
LYXERR(Debug::FILES) << "Manifest updated: " << endl
|
||||
<< *this
|
||||
<< "End Manifest" << endl;
|
||||
}
|
||||
|
||||
|
||||
bool EmbeddedFiles::write(DocFileName const & filename)
|
||||
{
|
||||
// file in the temporary path has the content
|
||||
string const content = FileName(addName(buffer_->temppath(),
|
||||
onlyFilename(filename.toFilesystemEncoding()))).toFilesystemEncoding();
|
||||
|
||||
// get a file list and write a manifest file
|
||||
vector<pair<string, string> > filenames;
|
||||
string const manifest = FileName(
|
||||
addName(buffer_->temppath(), "manifest.txt")).toFilesystemEncoding();
|
||||
|
||||
// write a manifest file
|
||||
ofstream os(manifest.c_str());
|
||||
os << *this;
|
||||
os.close();
|
||||
// prepare list of embedded file
|
||||
EmbeddedFileList::iterator it = file_list_.begin();
|
||||
EmbeddedFileList::iterator it_end = file_list_.end();
|
||||
for (; it != it_end; ++it) {
|
||||
if (it->valid() && it->embedded()) {
|
||||
// use external file if possible
|
||||
if (it->status() != EmbeddedFile::EMBEDDED && fs::exists(it->absFilename()))
|
||||
filenames.push_back(make_pair(it->absFilename(), it->inzipName()));
|
||||
// use embedded file (AUTO or EMBEDDED mode)
|
||||
else if(fs::exists(it->embeddedFile(buffer_)))
|
||||
filenames.push_back(make_pair(it->embeddedFile(buffer_), it->inzipName()));
|
||||
else
|
||||
lyxerr << "File " << it->absFilename() << " does not exist. Skip embedding it. " << endl;
|
||||
}
|
||||
}
|
||||
// add filename (.lyx) and manifest to filenames
|
||||
filenames.push_back(make_pair(content, onlyFilename(filename.toFilesystemEncoding())));
|
||||
filenames.push_back(make_pair(manifest, "manifest.txt"));
|
||||
// write a zip file with all these files. Write to a temp file first, to
|
||||
// avoid messing up the original file in case something goes terribly wrong.
|
||||
DocFileName zipfile(addName(buffer_->temppath(),
|
||||
onlyFilename(changeExtension(
|
||||
filename.toFilesystemEncoding(), ".zip"))));
|
||||
|
||||
zipFiles(zipfile, filenames);
|
||||
// copy file back
|
||||
try {
|
||||
fs::copy_file(zipfile.toFilesystemEncoding(), filename.toFilesystemEncoding(), false);
|
||||
} catch (fs::filesystem_error const & fe) {
|
||||
Alert::error(_("Save failure"),
|
||||
bformat(_("Cannot create file %1$s.\n"
|
||||
"Please check whether the directory exists and is writeable."),
|
||||
from_utf8(filename.absFilename())));
|
||||
LYXERR(Debug::DEBUG) << "Fs error: " << fe.what() << endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EmbeddedFiles::validInzipName(string const & name)
|
||||
{
|
||||
EmbeddedFileList::iterator it = file_list_.begin();
|
||||
EmbeddedFileList::iterator it_end = file_list_.end();
|
||||
for (; it != it_end; ++it)
|
||||
if (it->inzipName() == name)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
istream & operator>> (istream & is, EmbeddedFiles & files)
|
||||
{
|
||||
files.clear();
|
||||
string tmp;
|
||||
getline(is, tmp);
|
||||
// get version
|
||||
istringstream itmp(tmp);
|
||||
int version;
|
||||
itmp.ignore(string("# LyX manifest version ").size());
|
||||
itmp >> version;
|
||||
|
||||
if (version != 1) {
|
||||
lyxerr << "This version of LyX can only read LyX manifest version 1" << endl;
|
||||
return is;
|
||||
}
|
||||
|
||||
getline(is, tmp);
|
||||
if (tmp != "<manifest>") {
|
||||
lyxerr << "Invalid manifest file, lacking <manifest>" << endl;
|
||||
return is;
|
||||
}
|
||||
// manifest file may be messed up, be carefully
|
||||
while (is.good()) {
|
||||
getline(is, tmp);
|
||||
if (tmp != "<file>")
|
||||
break;
|
||||
|
||||
string fname;
|
||||
getline(is, fname);
|
||||
string inzip_name;
|
||||
getline(is, inzip_name);
|
||||
getline(is, tmp);
|
||||
istringstream itmp(tmp);
|
||||
int status;
|
||||
itmp >> status;
|
||||
|
||||
getline(is, tmp);
|
||||
if (tmp != "</file>") {
|
||||
lyxerr << "Invalid manifest file, lacking </file>" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
files.registerFile(fname, static_cast<EmbeddedFile::STATUS>(status));
|
||||
};
|
||||
// the last line must be </manifest>
|
||||
if (tmp != "</manifest>") {
|
||||
lyxerr << "Invalid manifest file, lacking </manifest>" << endl;
|
||||
return is;
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
|
||||
ostream & operator<< (ostream & os, EmbeddedFiles const & files)
|
||||
{
|
||||
// store a version so that operator >> can read later versions
|
||||
// using version information.
|
||||
os << "# lyx manifest version 1\n";
|
||||
os << "<manifest>\n";
|
||||
EmbeddedFiles::EmbeddedFileList::const_iterator it = files.begin();
|
||||
EmbeddedFiles::EmbeddedFileList::const_iterator it_end = files.end();
|
||||
for (; it != it_end; ++it) {
|
||||
if (!it->valid())
|
||||
continue;
|
||||
// use differnt lines to make reading easier.
|
||||
os << "<file>\n"
|
||||
// save the relative path
|
||||
<< to_utf8(makeRelPath(from_utf8(it->absFilename()),
|
||||
from_utf8(files.buffer_->filePath()))) << '\n'
|
||||
<< it->inzipName() << '\n'
|
||||
<< it->status() << '\n'
|
||||
<< "</file>\n";
|
||||
}
|
||||
os << "</manifest>\n";
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
239
src/EmbeddedFiles.h
Normal file
239
src/EmbeddedFiles.h
Normal file
@ -0,0 +1,239 @@
|
||||
// -*- C++ -*-
|
||||
/**
|
||||
* \file EmbeddedFiles.h
|
||||
* This file is part of LyX, the document processor.
|
||||
* Licence details can be found in the file COPYING.
|
||||
*
|
||||
* \author Bo Peng
|
||||
*
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EMBEDDEDFILES_H
|
||||
#define EMBEDDEDFILES_H
|
||||
|
||||
#include "support/FileName.h"
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "ParIterator.h"
|
||||
#include "Paragraph.h"
|
||||
|
||||
/**
|
||||
|
||||
This file, and the embedding dialog implemented in src/frontends, implements
|
||||
an 'Embedded Files' feature of lyx.
|
||||
|
||||
|
||||
Expected features:
|
||||
=========================
|
||||
|
||||
1. With embedding enabled (disabled by default), .lyx file can embed graphics,
|
||||
listings, bib file etc.
|
||||
|
||||
2. Embedding of certain files are automatic (graphics, bib etc), and
|
||||
other files can be embedded manually.
|
||||
|
||||
3. Embedded file.lyx file is a zip file, with file.lyx, manifest.txt
|
||||
and embedded files.
|
||||
|
||||
4. Embedded files can be "EMBEDDED", "EXTERNAL", or "AUTO". In the
|
||||
"AUTO" mode, external files will be used if available; otherwise the
|
||||
embedded version will be used. In this way, users can work as usual by
|
||||
modifying external listings, graphics, and do not have to worry about
|
||||
embedding. "EMBEDDED" and "EXTERNAL" modes ignore or use external files
|
||||
respectively.
|
||||
|
||||
5. An embedding dialog is provided to change embedding status (buffer
|
||||
level or individual embedded files), manually embed, extract, view
|
||||
or edit files.
|
||||
|
||||
Overall, this feature allows two ways of editing a .lyx file
|
||||
|
||||
a. The continuous use of the pure-text .lyx file format with external
|
||||
files. This is the default file format, and allows external editing
|
||||
of .lyx file and better use of version control systems.
|
||||
|
||||
b. The embedded way. Figures etc are inserted to .lyx file and will
|
||||
be embedded. These embedded files can be viewed or edited through
|
||||
the embedding dialog. This file can be shared with others more
|
||||
easily. The advantage of lyx' embedding approach is that external files
|
||||
will be automatically used and embedded if the file is in "AUTO" mode.
|
||||
|
||||
|
||||
Implementation:
|
||||
======================
|
||||
|
||||
1. An EmbeddedFiles class is implemented to keep the embedded files (
|
||||
class EmbeddedFile). (c.f. src/EmbeddedFiles.[h|cpp])
|
||||
This class keeps a manifest that has
|
||||
a. external relative filename
|
||||
b. inzip filename. It is the relative path name if the embedded file is
|
||||
in or under the document directory, or file name otherwise. Name aliasing
|
||||
is used if two external files share the same name.
|
||||
c. embedding mode.
|
||||
It also provides functions to
|
||||
a. manipulate manifest
|
||||
b. scan a buffer for embeddable files
|
||||
c. look up inzipname from external filename
|
||||
d. look up external filename from inzipname
|
||||
|
||||
2. When a file is saved, it is scanned for embedded files. (c.f.
|
||||
EmbeddedFiles::update(), Inset::registerEmbeddedFiles()).
|
||||
|
||||
3. When a lyx file file.lyx is saved, it is save to tmppath() first.
|
||||
Embedded files are compressed along with file.lyx and a manifest.txt.
|
||||
If embedding is disabled, file.lyx is saved in the usual pure-text form.
|
||||
(c.f. Buffer::writeFile(), EmbeddedFiles::write())
|
||||
|
||||
4. When a lyx file.lyx file is opened, if it is a zip file, it is
|
||||
decompressed to tmppath(). If manifest.txt and file.lyx exists in
|
||||
tmppath(), the manifest is read to buffer, and tmppath()/file.lyx is
|
||||
read as usual. If file.lyx is not a zip file, it is read as usual.
|
||||
(c.f. bool Buffer::readFile())
|
||||
|
||||
5. A menu item Document -> Embedded Files is provided to open
|
||||
a embedding dialog. It handles a EmbddedFiles point directly.
|
||||
From this dialog, a user can disable embedding, change embedding status,
|
||||
or embed other files, extract, view, edit files.
|
||||
|
||||
6. When a lyx file is loaded, Embedded files can have
|
||||
a. both external and internal copy
|
||||
b. only external copy (filename())
|
||||
c. only embedded copy (temppath()/inzipname)
|
||||
And each can have "AUTO", "EXTERNAL", "EMBEDDED" status. Proper
|
||||
handling of each case is required.
|
||||
|
||||
7. If embedding of a .lyx file with embedded files is disabled, all its
|
||||
embedded files are copied to their respective external filenames. This
|
||||
is why external filename will exist even if a file is at "EMBEDDED" status.
|
||||
|
||||
8. Individual embeddable insets should find ways to handle embedded files.
|
||||
InsetGraphics replace params().filename with its temppath()/inzipname version
|
||||
when the inset is created. The filename appears as /tmp/..../inzipname
|
||||
when lyx runs. When params().filename is saved, lyx checks if this is an
|
||||
embedded file (check path == temppath()), if so, save filename() instead.
|
||||
(c.f. InsetGraphic::read(), InsetGraphics::edit(), InsetGraphicsParams::write())
|
||||
|
||||
|
||||
*/
|
||||
|
||||
namespace lyx {
|
||||
|
||||
class Buffer;
|
||||
|
||||
class EmbeddedFile : public support::DocFileName
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Embedding status of this DocFileName.
|
||||
*/
|
||||
enum STATUS {
|
||||
// uninitialized/invalid status
|
||||
NONE,
|
||||
// If the external version of the file is available, it will be used
|
||||
// to generate output, and be embedded to the saved lyx file.
|
||||
// Otherwise, embedded version will be used.
|
||||
AUTO,
|
||||
// Always use embedded version.
|
||||
EMBEDDED,
|
||||
// Do not embed this file, always use external version.
|
||||
EXTERNAL
|
||||
};
|
||||
|
||||
EmbeddedFile(std::string const & file, std::string const & inzip_name,
|
||||
STATUS status, ParConstIterator const & pit);
|
||||
|
||||
/// filename in the zip file, usually the relative path
|
||||
std::string inzipName() const { return inzip_name_; }
|
||||
/// embedded file, equals to temppath()/inzipName()
|
||||
std::string embeddedFile(Buffer const * buf) const;
|
||||
|
||||
/// paragraph id
|
||||
void setParIter(ParConstIterator const & pit);
|
||||
int const parID() const { return par_it_->id(); }
|
||||
|
||||
/// embedding status of this file
|
||||
bool embedded() const { return status_ != EXTERNAL; }
|
||||
STATUS status() const { return status_; }
|
||||
void setStatus(STATUS status) { status_ = status; }
|
||||
|
||||
// A flag indicating whether or not this filename is valid.
|
||||
// When lyx runs, InsetGraphics etc may be added or removed so filename
|
||||
// maybe obsolete. In Buffer::updateEmbeddedFiles, the EmbeddedFiles is first
|
||||
// invalidated (c.f. invalidate()), and all insets are asked to register
|
||||
// embedded files. In this way, EmbeddedFileList will be refreshed, with
|
||||
// status setting untouched.
|
||||
bool valid() const { return valid_; }
|
||||
void validate() { valid_ = true; }
|
||||
void invalidate() { valid_ = false; }
|
||||
|
||||
private:
|
||||
/// filename in zip file
|
||||
std::string inzip_name_;
|
||||
/// the status of this docfile
|
||||
STATUS status_;
|
||||
///
|
||||
bool valid_;
|
||||
/// Current position of the item, used to locate the files
|
||||
/// A figure may be referred by several items. In this case
|
||||
/// only the last location is recorded.
|
||||
ParConstIterator par_it_;
|
||||
};
|
||||
|
||||
|
||||
class EmbeddedFiles {
|
||||
public:
|
||||
typedef std::vector<EmbeddedFile> EmbeddedFileList;
|
||||
public:
|
||||
///
|
||||
EmbeddedFiles(Buffer * buffer = NULL): file_list_(), buffer_(buffer) {}
|
||||
///
|
||||
~EmbeddedFiles() {}
|
||||
|
||||
/// return buffer params embedded flag
|
||||
bool enabled() const;
|
||||
/// set buffer params embedded flag
|
||||
void enable(bool flag);
|
||||
|
||||
/// add a file item
|
||||
void registerFile(std::string const & filename,
|
||||
EmbeddedFile::STATUS status=EmbeddedFile::AUTO,
|
||||
ParConstIterator const & pit = ParConstIterator());
|
||||
|
||||
/// scan the buffer and get a list of EmbeddedFile
|
||||
void update();
|
||||
|
||||
/// write a zip file
|
||||
bool write(support::DocFileName const & filename);
|
||||
|
||||
void clear() { file_list_.clear(); }
|
||||
|
||||
///
|
||||
EmbeddedFileList::iterator begin() { return file_list_.begin(); }
|
||||
EmbeddedFileList::iterator end() { return file_list_.end(); }
|
||||
EmbeddedFileList::const_iterator begin() const { return file_list_.begin(); }
|
||||
EmbeddedFileList::const_iterator end() const { return file_list_.end(); }
|
||||
|
||||
///
|
||||
friend std::istream & operator>> (std::istream & is, EmbeddedFiles &);
|
||||
|
||||
friend std::ostream & operator<< (std::ostream & os, EmbeddedFiles const &);
|
||||
private:
|
||||
/// if a inzip name already exists
|
||||
bool validInzipName(std::string const & name);
|
||||
/// list of embedded files
|
||||
EmbeddedFileList file_list_;
|
||||
///
|
||||
Buffer * buffer_;
|
||||
};
|
||||
|
||||
|
||||
std::istream & operator>> (std::istream & is, EmbeddedFiles &);
|
||||
|
||||
std::ostream & operator<< (std::ostream & os, EmbeddedFiles const &);
|
||||
|
||||
}
|
||||
#endif
|
@ -127,6 +127,8 @@ liblyxcore_la_SOURCES = \
|
||||
DispatchResult.h \
|
||||
DocIterator.cpp \
|
||||
DocIterator.h \
|
||||
EmbeddedFiles.h \
|
||||
EmbeddedFiles.cpp \
|
||||
Encoding.cpp \
|
||||
Encoding.h \
|
||||
ErrorList.cpp \
|
||||
|
@ -49,6 +49,7 @@ class ParConstIterator;
|
||||
class ParIterator;
|
||||
class Text;
|
||||
class TocList;
|
||||
class EmbeddedFiles;
|
||||
|
||||
|
||||
namespace graphics { class PreviewLoader; }
|
||||
@ -438,6 +439,9 @@ public:
|
||||
/// Add an entry to the TocList
|
||||
/// pit is the ParConstIterator of the paragraph containing the inset
|
||||
virtual void addToToc(TocList &, Buffer const &, ParConstIterator const &) const {}
|
||||
/// report files that can be embedded with the lyx file
|
||||
virtual void registerEmbeddedFiles(Buffer const &, EmbeddedFiles &,
|
||||
ParConstIterator const &) const {};
|
||||
/// Fill keys with BibTeX information
|
||||
virtual void fillWithBibKeys(Buffer const &,
|
||||
BiblioInfo &, InsetIterator const &) const { return; }
|
||||
|
@ -481,6 +481,13 @@ bool InsetExternal::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
}
|
||||
|
||||
|
||||
void InsetExternal::registerEmbeddedFiles(Buffer const &,
|
||||
EmbeddedFiles & files, ParConstIterator const & pit) const
|
||||
{
|
||||
files.registerFile(params_.filename.absFilename(), EmbeddedFile::AUTO, pit);
|
||||
}
|
||||
|
||||
|
||||
void InsetExternal::edit(Cursor & cur, bool)
|
||||
{
|
||||
InsetExternalMailer(*this).showDialog(&cur.bv());
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "Inset.h"
|
||||
#include "ExternalTransforms.h"
|
||||
#include "EmbeddedFiles.h"
|
||||
|
||||
#include "support/FileName.h"
|
||||
#include "support/Translator.h"
|
||||
@ -147,6 +148,9 @@ public:
|
||||
void edit(Cursor & cur, bool left);
|
||||
///
|
||||
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const;
|
||||
/// external file can be embedded
|
||||
void registerEmbeddedFiles(Buffer const &, EmbeddedFiles &,
|
||||
ParConstIterator const &) const;
|
||||
|
||||
protected:
|
||||
InsetExternal(InsetExternal const &);
|
||||
|
@ -71,6 +71,7 @@ TODO
|
||||
#include "Mover.h"
|
||||
#include "OutputParams.h"
|
||||
#include "sgml.h"
|
||||
#include "EmbeddedFiles.h"
|
||||
|
||||
#include "frontends/alert.h"
|
||||
|
||||
@ -230,6 +231,14 @@ bool InsetGraphics::getStatus(Cursor & cur, FuncRequest const & cmd,
|
||||
}
|
||||
|
||||
|
||||
void InsetGraphics::registerEmbeddedFiles(Buffer const &,
|
||||
EmbeddedFiles & files, ParConstIterator const & pit) const
|
||||
{
|
||||
files.registerFile(params().filename.absFilename(),
|
||||
EmbeddedFile::AUTO, pit);
|
||||
}
|
||||
|
||||
|
||||
void InsetGraphics::edit(Cursor & cur, bool)
|
||||
{
|
||||
InsetGraphicsMailer(*this).showDialog(&cur.bv());
|
||||
|
@ -78,6 +78,8 @@ public:
|
||||
void editGraphics(InsetGraphicsParams const &, Buffer const &) const;
|
||||
///
|
||||
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const;
|
||||
/// all graphics can be embedded
|
||||
void registerEmbeddedFiles(Buffer const &, EmbeddedFiles &, ParConstIterator const &) const;
|
||||
protected:
|
||||
InsetGraphics(InsetGraphics const &);
|
||||
///
|
||||
|
@ -958,6 +958,16 @@ void InsetInclude::updateLabels(Buffer const & buffer,
|
||||
}
|
||||
|
||||
|
||||
void InsetInclude::registerEmbeddedFiles(Buffer const & buffer,
|
||||
EmbeddedFiles & files, ParConstIterator const & pit) const
|
||||
{
|
||||
// include and input are temprarily not considered.
|
||||
if (isVerbatim(params_) || isListings(params_))
|
||||
files.registerFile(includedFilename(buffer, params_).absFilename(),
|
||||
EmbeddedFile::AUTO, pit);
|
||||
}
|
||||
|
||||
|
||||
string const InsetIncludeMailer::name_("include");
|
||||
|
||||
InsetIncludeMailer::InsetIncludeMailer(InsetInclude & inset)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "RenderButton.h"
|
||||
#include "MailInset.h"
|
||||
#include "Counters.h"
|
||||
#include "EmbeddedFiles.h"
|
||||
|
||||
#include "support/FileName.h"
|
||||
|
||||
@ -103,6 +104,9 @@ public:
|
||||
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const;
|
||||
///
|
||||
void updateLabels(Buffer const & buffer, ParIterator const &);
|
||||
/// child document can be embedded
|
||||
void registerEmbeddedFiles(Buffer const &, EmbeddedFiles &,
|
||||
ParConstIterator const &) const;
|
||||
protected:
|
||||
InsetInclude(InsetInclude const &);
|
||||
///
|
||||
|
Loading…
Reference in New Issue
Block a user