#include "Converter.h"
#include "Counters.h"
#include "DocIterator.h"
-#include "EmbeddedFiles.h"
#include "Encoding.h"
#include "ErrorList.h"
#include "Exporter.h"
#include "graphics/Previews.h"
-#include "support/assert.h"
+#include "support/lassert.h"
#include "support/convert.h"
#include "support/debug.h"
#include "support/ExceptionMessage.h"
#include "support/Path.h"
#include "support/textutils.h"
#include "support/types.h"
-#include "support/FileZipListDir.h"
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
namespace {
-int const LYX_FORMAT = 328;
+int const LYX_FORMAT = 340; //jamatos: add plain layout
typedef map<string, bool> DepClean;
typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;
wa_->closeAll();
delete wa_;
}
+ delete inset;
}
-
+
BufferParams params;
LyXVC lyxvc;
FileName temppath;
/// which maps the macro definition position to the scope and the MacroData.
NamePositionScopeMacroMap macros;
bool macro_lock;
-
+
/// positions of child buffers in the buffer
typedef map<Buffer const * const, DocIterator> BufferPositionMap;
typedef pair<DocIterator, Buffer const *> ScopeBuffer;
/// Container for all sort of Buffer dependant errors.
map<string, ErrorList> errorLists;
- /// all embedded files of this buffer
- EmbeddedFileList 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_;
/// documents), needed for appropriate update of natbib labels.
mutable support::FileNameList bibfilesCache_;
+ // FIXME The caching mechanism could be improved. At present, we have a
+ // cache for each Buffer, that caches all the bibliography info for that
+ // Buffer. A more efficient solution would be to have a global cache per
+ // file, and then to construct the Buffer's bibinfo from that.
+ /// A cache for bibliography info
+ mutable BiblioInfo bibinfo_;
+ /// whether the bibinfo cache is valid
+ bool bibinfoCacheValid_;
+ /// Cache of timestamps of .bib files
+ map<FileName, time_t> bibfileStatus_;
+
mutable RefCache ref_cache_;
/// our Text that should be wrapped in an InsetText
- InsetText inset;
+ InsetText * inset;
};
Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_)
: parent_buffer(0), lyx_clean(true), bak_clean(true), unnamed(false),
read_only(readonly_), filename(file), file_fully_loaded(false),
- toc_backend(&parent), macro_lock(false),
- embedded_files(), timestamp_(0), checksum_(0), wa_(0),
- undo_(parent)
+ toc_backend(&parent), macro_lock(false), timestamp_(0),
+ checksum_(0), wa_(0), undo_(parent), bibinfoCacheValid_(false)
{
temppath = createBufferTmpDir();
lyxvc.setBuffer(&parent);
{
LYXERR(Debug::INFO, "Buffer::Buffer()");
- d->inset.setBuffer(*this);
- d->inset.initParagraphs(*this);
- d->inset.setAutoBreakRows(true);
- d->inset.getText(0)->setMacrocontextPosition(par_iterator_begin());
+ d->inset = new InsetText(*this);
+ d->inset->setAutoBreakRows(true);
+ d->inset->getText(0)->setMacrocontextPosition(par_iterator_begin());
}
// GuiView already destroyed
gui_ = 0;
+
+ // loop over children
+ Impl::BufferPositionMap::iterator it = d->children_positions.begin();
+ Impl::BufferPositionMap::iterator end = d->children_positions.end();
+ for (; it != end; ++it)
+ theBufferList().releaseChild(this, const_cast<Buffer *>(it->first));
+
// clear references to children in macro tables
d->children_positions.clear();
d->position_to_children.clear();
}
// Remove any previewed LaTeX snippets associated with this buffer.
- graphics::Previews::get().removeLoader(*this);
+ thePreviews().removeLoader(*this);
delete d;
}
Text & Buffer::text() const
{
- return const_cast<Text &>(d->inset.text_);
+ return d->inset->text();
}
Inset & Buffer::inset() const
{
- return const_cast<InsetText &>(d->inset);
+ return *d->inset;
}
}
-EmbeddedFileList & Buffer::embeddedFiles()
-{
- return d->embedded_files;
-}
-
-
-EmbeddedFileList const & Buffer::embeddedFiles() const
-{
- return d->embedded_files;
-}
-
-
-bool Buffer::embedded() const
-{
- return params().embedded;
-}
-
-
Undo & Buffer::undo()
{
return d->undo_;
params().branchlist().clear();
params().preamble.erase();
params().options.erase();
+ params().master.erase();
params().float_placement.erase();
params().paperwidth.erase();
params().paperheight.erase();
params().headsep.erase();
params().footskip.erase();
params().columnsep.erase();
+ params().fontsCJK.erase();
params().listings_params.clear();
params().clearLayoutModules();
+ params().clearRemovedModules();
params().pdfoptions().clear();
-
+
for (int i = 0; i < 4; ++i) {
params().user_defined_bullet(i) = ITEMIZE_DEFAULTS[i];
params().temp_bullet(i) = ITEMIZE_DEFAULTS[i];
LYXERR(Debug::PARSER, "Handling document header token: `"
<< token << '\'');
- string unknown = params().readToken(lex, token, d->filename.onlyPath(),
- d->temppath);
+ string unknown = params().readToken(lex, token, d->filename.onlyPath());
if (!unknown.empty()) {
if (unknown[0] != '\\' && token == "\\textclass") {
Alert::warning(_("Unknown document class"),
errorList.push_back(ErrorItem(_("Document header error"),
s, -1, 0, 0));
}
-
+
params().makeDocumentClass();
return unknown_tokens;
}
}
- // read main text
- bool const res = text().read(*this, lex, errorList, &(d->inset));
-
- // 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;
+ if (!params().master.empty()) {
+ FileName const master_file = makeAbsPath(params().master,
+ onlyPath(absFileName()));
+ if (isLyXFilename(master_file.absFilename())) {
+ Buffer * master = checkAndLoadLyXFile(master_file);
+ d->parent_buffer = master;
+ }
}
+ // read main text
+ bool const res = text().read(*this, lex, errorList, d->inset);
+
updateMacros();
updateMacroInstances();
return res;
Lexer lex;
istringstream is(s);
lex.setStream(is);
- FileName const name = FileName::tempName();
+ FileName const name = FileName::tempName("Buffer_readString");
switch (readFile(lex, name, true)) {
case failure:
return false;
bool Buffer::readFile(FileName const & filename)
{
FileName fname(filename);
- // Check if the file is compressed.
- string format = filename.guessFormatFromContents();
- if (format == "zip") {
- // decompress to a temp directory
- LYXERR(Debug::FILES, filename << " is in zip format. Unzip to " << temppath());
- ::unzipToDir(filename.toFilesystemEncoding(), temppath());
- //
- FileName lyxfile(addName(temppath(), "content.lyx"));
- // if both manifest.txt and file.lyx exist, this is am embedded file
- if (lyxfile.exists()) {
- // if in bundled format, save checksum of the compressed file, not content.lyx
- saveCheckSum(filename);
- params().embedded = true;
- fname = lyxfile;
- }
- }
- // The embedded lyx file can also be compressed, for backward compatibility
- format = fname.guessFormatFromContents();
- if (format == "gzip" || format == "zip" || format == "compress")
- params().compressed = true;
// remove dummy empty par
paragraphs().clear();
// lyx2lyx would fail
return wrongversion;
- FileName const tmpfile = FileName::tempName();
+ FileName const tmpfile = FileName::tempName("Buffer_readFile");
if (tmpfile.empty()) {
Alert::error(_("Conversion failed"),
bformat(_("%1$s is from a different"
bool retval = false;
- FileName content;
- if (params().embedded)
- // first write the .lyx file to the temporary directory
- content = FileName(addName(temppath(), "content.lyx"));
- else
- content = fname;
-
docstring const str = bformat(_("Saving document %1$s..."),
- makeDisplayPath(content.absFilename()));
+ makeDisplayPath(fname.absFilename()));
message(str);
if (params().compressed) {
- gz::ogzstream ofs(content.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
+ gz::ogzstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
retval = ofs && write(ofs);
} else {
- ofstream ofs(content.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
+ ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc);
retval = ofs && write(ofs);
}
removeAutosaveFile(d->filename.absFilename());
- if (params().embedded) {
- message(str + _(" writing embedded files."));
- // if embedding is enabled, write file.lyx and all the embedded files
- // to the zip file fname.
- if (!d->embedded_files.writeFile(fname, *this)) {
- message(str + _(" could not write embedded files!"));
- return false;
- }
- }
saveCheckSum(d->filename);
message(str + _(" done."));
"representable in the chosen encoding.\n"
"Changing the document encoding to utf8 could help."),
e.par_id, e.pos, e.pos + 1));
- failed_export = true;
+ failed_export = true;
}
catch (iconv_codecvt_facet_exception & e) {
errorList.push_back(ErrorItem(_("iconv conversion failed"),
}
catch (...) {
lyxerr << "Caught some really weird exception..." << endl;
- LyX::cref().exit(1);
+ lyx_exit(1);
}
ofs.close();
// because then the macros will not get the right "redefinition"
// flag as they don't see the parent macros which are output before.
updateMacros();
-
+
// fold macros if possible, still with parent buffer as the
// macros will be put in the prefix anyway.
updateMacroInstances();
-
+
// There are a few differences between nice LaTeX and usual files:
// usual is \batchmode and has a
// special input@path to allow the including of figures
// Write the preamble
runparams.use_babel = params().writeLaTeX(os, features, d->texrow);
+ runparams.use_japanese = features.isRequired("japanese");
+
if (!output_body)
return;
// make the body.
os << "\\begin{document}\n";
d->texrow.newline();
-
+
// output the parent macros
MacroSet::iterator it = parentMacros.begin();
MacroSet::iterator end = parentMacros.end();
for (; it != end; ++it)
- (*it)->write(os, true);
+ (*it)->write(os, true);
} // output_preamble
d->texrow.start(paragraphs().begin()->id(), 0);
-
+
LYXERR(Debug::INFO, "preamble finished, now the body.");
// if we are doing a real file with body, even if this is the
if (runparams.flavor == OutputParams::XML)
top += params().language->code();
else
- top += params().language->code().substr(0,2);
+ top += params().language->code().substr(0, 2);
top += '"';
if (!params().options.empty()) {
bibfiles.end());
}
}
+ // the bibinfo cache is now invalid
+ d->bibinfoCacheValid_ = false;
+}
+
+
+void Buffer::invalidateBibinfoCache()
+{
+ d->bibinfoCacheValid_ = false;
}
}
+BiblioInfo const & Buffer::masterBibInfo() const
+{
+ // if this is a child document and the parent is already loaded
+ // use the parent's list instead [ale990412]
+ Buffer const * const tmp = masterBuffer();
+ LASSERT(tmp, /**/);
+ if (tmp != this)
+ return tmp->masterBibInfo();
+ return localBibInfo();
+}
+
+
+BiblioInfo const & Buffer::localBibInfo() const
+{
+ if (d->bibinfoCacheValid_) {
+ support::FileNameList const & bibfilesCache = getBibfilesCache();
+ // compare the cached timestamps with the actual ones.
+ support::FileNameList::const_iterator ei = bibfilesCache.begin();
+ support::FileNameList::const_iterator en = bibfilesCache.end();
+ for (; ei != en; ++ ei) {
+ time_t lastw = ei->lastModified();
+ if (lastw != d->bibfileStatus_[*ei]) {
+ d->bibinfoCacheValid_ = false;
+ d->bibfileStatus_[*ei] = lastw;
+ break;
+ }
+ }
+ }
+
+ if (!d->bibinfoCacheValid_) {
+ d->bibinfo_.clear();
+ for (InsetIterator it = inset_iterator_begin(inset()); it; ++it)
+ it->fillWithBibKeys(d->bibinfo_, it);
+ d->bibinfoCacheValid_ = true;
+ }
+ return d->bibinfo_;
+}
+
+
bool Buffer::isDepClean(string const & name) const
{
DepClean::const_iterator const it = d->dep_clean.find(name);
break;
}
+ case LFUN_BRANCH_ACTIVATE:
+ case LFUN_BRANCH_DEACTIVATE: {
+ BranchList & branchList = params().branchlist();
+ docstring const branchName = func.argument();
+ Branch * branch = branchList.find(branchName);
+ if (!branch)
+ LYXERR0("Branch " << branchName << " does not exist.");
+ else
+ branch->setSelected(func.action == LFUN_BRANCH_ACTIVATE);
+ if (result)
+ *result = true;
+ }
+
default:
dispatched = false;
}
{
LASSERT(d->filename.exists(), /**/);
// if method == timestamp, check timestamp before checksum
- return (method == checksum_method
+ return (method == checksum_method
|| d->timestamp_ != d->filename.lastModified())
&& d->checksum_ != d->filename.checksum();
}
{
if (!d->parent_buffer)
return this;
-
+
return d->parent_buffer->masterBuffer();
}
+bool Buffer::isChild(Buffer * child) const
+{
+ return d->children_positions.find(child) != d->children_positions.end();
+}
+
+
template<typename M>
typename M::iterator greatest_below(M & m, typename M::key_type const & x)
{
return m.end();
it--;
- return it;
+ return it;
}
-MacroData const * Buffer::getBufferMacro(docstring const & name,
+MacroData const * Buffer::getBufferMacro(docstring const & name,
DocIterator const & pos) const
{
LYXERR(Debug::MACROS, "Searching for " << to_ascii(name) << " at " << pos);
// we haven't found anything yet
DocIterator bestPos = par_iterator_begin();
MacroData const * bestData = 0;
-
+
// find macro definitions for name
Impl::NamePositionScopeMacroMap::iterator nameIt
= d->macros.find(name);
bestData = &it->second.second;
break;
}
-
+
// try previous macro if there is one
if (it == nameIt->second.begin())
break;
break;
--it;
}
-
+
// return the best macro we have found
return bestData;
}
DocIterator const & pos, bool global) const
{
if (d->macro_lock)
- return 0;
+ return 0;
// query buffer macros
MacroData const * data = getBufferMacro(name, pos);
InsetList::const_iterator end = insets.end();
for (; iit != end; ++iit) {
it.pos() = iit->pos;
-
+
// is it a nested text inset?
if (iit->inset->asInsetText()) {
// Inset needs its own scope?
- InsetText const * itext
+ InsetText const * itext
= iit->inset->asInsetText();
bool newScope = itext->isMacroScope();
- // scope which ends just behind the inset
+ // scope which ends just behind the inset
DocIterator insetScope = it;
++insetScope.pos();
it.pop_back();
continue;
}
-
+
// is it an external file?
if (iit->inset->lyxCode() == INCLUDE_CODE) {
// get buffer of external file
- InsetCommand const & inset
+ InsetCommand const & inset
= static_cast<InsetCommand const &>(*iit->inset);
InsetCommandParams const & ip = inset.params();
d->macro_lock = true;
Buffer * child = loadIfNeeded(*this, ip);
d->macro_lock = false;
if (!child)
- continue;
+ continue;
// register its position, but only when it is
// included first in the buffer
if (d->children_positions.find(child)
== d->children_positions.end())
d->children_positions[child] = it;
-
+
// register child with its scope
d->position_to_children[it] = Impl::ScopeBuffer(scope, child);
continue;
if (iit->inset->lyxCode() != MATHMACRO_CODE)
continue;
-
+
// get macro data
MathMacroTemplate & macroTemplate
= static_cast<MathMacroTemplate &>(*iit->inset);
return;
d->macro_lock = true;
-
+
// loop over macro names
Impl::NamePositionScopeMacroMap::iterator nameIt = d->macros.begin();
Impl::NamePositionScopeMacroMap::iterator nameEnd = d->macros.end();
if (d->parent_buffer)
d->parent_buffer->listMacroNames(macros);
- d->macro_lock = false;
+ d->macro_lock = false;
}
{
if (!d->parent_buffer)
return;
-
+
MacroNameSet names;
d->parent_buffer->listMacroNames(names);
-
+
// resolve macros
MacroNameSet::iterator it = names.begin();
MacroNameSet::iterator end = names.end();
for (; it != end; ++it) {
// defined?
- MacroData const * data =
+ MacroData const * data =
d->parent_buffer->getMacro(*it, *this, false);
if (data) {
macros.insert(data);
-
+
// we cannot access the original MathMacroTemplate anymore
// here to calls validate method. So we do its work here manually.
// FIXME: somehow make the template accessible here.
// Check if the label 'from' appears more than once
vector<docstring> labels;
string paramName;
- BiblioInfo keys;
- keys.fillWithBibKeys(this);
+ BiblioInfo const & keys = masterBibInfo();
BiblioInfo::const_iterator bit = keys.begin();
BiblioInfo::const_iterator bend = keys.end();
///
int start()
{
- command_ = to_utf8(bformat(_("Auto-saving %1$s"),
+ command_ = to_utf8(bformat(_("Auto-saving %1$s"),
from_utf8(fname_.absFilename())));
return run(DontWait);
}
return "docbook";
if (isLiterate())
return "literate";
+ if (params().encoding().package() == Encoding::japanese)
+ return "platex";
return "latex";
}
string const error_type = (format == "program")
? "Build" : bufferFormat();
+ ErrorList & error_list = d->errorLists[error_type];
string const ext = formats.extension(format);
FileName const tmp_result_file(changeExtension(filename, ext));
bool const success = theConverters().convert(this, FileName(filename),
tmp_result_file, FileName(absFileName()), backend_format, format,
- errorList(error_type));
+ error_list);
// Emit the signal to show the error list.
if (format != backend_format)
errors(error_type);
}
}
+
} // namespace lyx