X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fbuffer.C;h=0e7944a17679fdc4efa4b75ebf8a803c88347575;hb=29b6f5cad958e3298fc76d8ca6af6b721fa038cb;hp=e500fab155a750dd949a1f129524804590139b1f;hpb=6c300f72a217722652dc27db9108e1050028979c;p=lyx.git diff --git a/src/buffer.C b/src/buffer.C index e500fab155..0e7944a176 100644 --- a/src/buffer.C +++ b/src/buffer.C @@ -36,7 +36,6 @@ #include "lyxtext.h" #include "lyxrc.h" #include "lyxvc.h" -#include "lyx_main.h" #include "messages.h" #include "output.h" #include "output_docbook.h" @@ -47,6 +46,7 @@ #include "pariterator.h" #include "sgml.h" #include "texrow.h" +#include "TocBackend.h" #include "undo.h" #include "version.h" @@ -100,6 +100,7 @@ using support::changeExtension; using support::cmd_ret; using support::createBufferTmpDir; using support::destroyDir; +using support::FileName; using support::getFormatFromContents; using support::isDirWriteable; using support::libFileSearch; @@ -128,7 +129,6 @@ using std::endl; using std::for_each; using std::make_pair; -using std::ifstream; using std::ios; using std::map; using std::ostream; @@ -142,7 +142,7 @@ using std::string; namespace { -int const LYX_FORMAT = 252; +int const LYX_FORMAT = 255; } // namespace anon @@ -152,7 +152,7 @@ typedef std::map DepClean; class Buffer::Impl { public: - Impl(Buffer & parent, string const & file, bool readonly); + Impl(Buffer & parent, FileName const & file, bool readonly); limited_stack undostack; limited_stack redostack; @@ -177,7 +177,7 @@ public: bool read_only; /// name of the file the buffer is associated with. - string filename; + FileName filename; boost::scoped_ptr messages; @@ -192,18 +192,21 @@ public: /// MacroTable macros; + + /// + TocBackend toc_backend; }; -Buffer::Impl::Impl(Buffer & parent, string const & file, bool readonly_) +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) + filename(file), file_fully_loaded(false), inset(params), + toc_backend(&parent) { inset.setAutoBreakRows(true); lyxvc.buffer(&parent); temppath = createBufferTmpDir(); - params.filepath = onlyPath(file); + params.filepath = onlyPath(file.absFilename()); // FIXME: And now do something if temppath == string(), because we // assume from now on that temppath points to a valid temp dir. // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg67406.html @@ -211,7 +214,7 @@ Buffer::Impl::Impl(Buffer & parent, string const & file, bool readonly_) Buffer::Buffer(string const & file, bool readonly) - : pimpl_(new Impl(*this, file, readonly)) + : pimpl_(new Impl(*this, FileName(file), readonly)) { lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl; } @@ -225,7 +228,7 @@ Buffer::~Buffer() closing(); - if (!temppath().empty() && !destroyDir(temppath())) { + if (!temppath().empty() && !destroyDir(FileName(temppath()))) { Alert::warning(_("Could not remove temporary directory"), bformat(_("Could not remove the temporary directory %1$s"), from_utf8(temppath()))); @@ -326,6 +329,18 @@ TexRow const & Buffer::texrow() const } +TocBackend & Buffer::tocBackend() +{ + return pimpl_->toc_backend; +} + + +TocBackend const & Buffer::tocBackend() const +{ + return pimpl_->toc_backend; +} + + string const Buffer::getLatexName(bool const no_path) const { string const name = changeExtension(makeLatexName(fileName()), ".tex"); @@ -342,23 +357,24 @@ pair const Buffer::getLogName() const string const path = temppath(); - string const fname = addName(path, + FileName const fname(addName(temppath(), onlyFilename(changeExtension(filename, - ".log"))); - string const bname = + ".log")))); + FileName const bname( addName(path, onlyFilename( changeExtension(filename, - formats.extension("literate") + ".out"))); + formats.extension("literate") + ".out")))); // If no Latex log or Build log is newer, show Build log - if (fs::exists(bname) && - (!fs::exists(fname) || fs::last_write_time(fname) < fs::last_write_time(bname))) { + if (fs::exists(bname.toFilesystemEncoding()) && + (!fs::exists(fname.toFilesystemEncoding()) || + fs::last_write_time(fname.toFilesystemEncoding()) < fs::last_write_time(bname.toFilesystemEncoding()))) { lyxerr[Debug::FILES] << "Log name calculated as: " << bname << endl; - return make_pair(Buffer::buildlog, bname); + return make_pair(Buffer::buildlog, bname.absFilename()); } lyxerr[Debug::FILES] << "Log name calculated as: " << fname << endl; - return make_pair(Buffer::latexlog, fname); + return make_pair(Buffer::latexlog, fname.absFilename()); } @@ -373,9 +389,10 @@ void Buffer::setReadonly(bool const flag) void Buffer::setFileName(string const & newfile) { - pimpl_->filename = makeAbsPath(newfile); - params().filepath = onlyPath(pimpl_->filename); - setReadonly(fs::is_readonly(pimpl_->filename)); + string const filename = makeAbsPath(newfile); + pimpl_->filename = FileName(filename); + params().filepath = onlyPath(filename); + setReadonly(fs::is_readonly(pimpl_->filename.toFilesystemEncoding())); updateTitles(); } @@ -444,7 +461,7 @@ int Buffer::readHeader(LyXLex & lex) docstring const s = bformat(_("Unknown token: " "%1$s %2$s\n"), from_utf8(token), - from_utf8(lex.getString())); + lex.getDocString()); errorList.push_back(ErrorItem(_("Document header error"), s, -1, 0, 0)); } @@ -484,7 +501,7 @@ bool Buffer::readDocument(LyXLex & lex) string theclass = params().getLyXTextClass().name(); Alert::error(_("Can't load document class"), bformat( _("Using the default document class, because the " - " class %1$s could not be loaded."), from_utf8(theclass))); + "class %1$s could not be loaded."), from_utf8(theclass))); params().textclass = 0; } @@ -538,11 +555,9 @@ void Buffer::insertStringAsLines(ParagraphList & pars, } space_inserted = true; } -/* FIXME: not needed anymore? } else if (!isPrintable(*cit)) { // Ignore unprintables continue; -*/ } else { // just insert the character par.insertChar(pos, *cit, font, params().trackChanges); @@ -554,7 +569,7 @@ void Buffer::insertStringAsLines(ParagraphList & pars, } -bool Buffer::readFile(string const & filename) +bool Buffer::readFile(FileName const & filename) { // Check if the file is compressed. string const format = getFormatFromContents(filename); @@ -590,13 +605,13 @@ void Buffer::fully_loaded(bool const value) } -bool Buffer::readFile(LyXLex & lex, string const & filename) +bool Buffer::readFile(LyXLex & lex, FileName const & filename) { BOOST_ASSERT(!filename.empty()); if (!lex.isOK()) { Alert::error(_("Document could not be read"), - bformat(_("%1$s could not be read."), from_utf8(filename))); + bformat(_("%1$s could not be read."), from_utf8(filename.absFilename()))); return false; } @@ -605,7 +620,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename) if (!lex.isOK()) { Alert::error(_("Document could not be read"), - bformat(_("%1$s could not be read."), from_utf8(filename))); + bformat(_("%1$s could not be read."), from_utf8(filename.absFilename()))); return false; } @@ -615,7 +630,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename) Alert::error(_("Document format failure"), bformat(_("%1$s is not a LyX document."), - from_utf8(filename))); + from_utf8(filename.absFilename()))); return false; } @@ -631,31 +646,32 @@ bool Buffer::readFile(LyXLex & lex, string const & filename) //lyxerr << "format: " << file_format << endl; if (file_format != LYX_FORMAT) { - string const tmpfile = tempName(); + FileName const tmpfile(tempName()); if (tmpfile.empty()) { Alert::error(_("Conversion failed"), bformat(_("%1$s is from an earlier" " version of LyX, but a temporary" " file for converting it could" " not be created."), - from_utf8(filename))); + from_utf8(filename.absFilename()))); return false; } - string const lyx2lyx = libFileSearch("lyx2lyx", "lyx2lyx"); + FileName const lyx2lyx = libFileSearch("lyx2lyx", "lyx2lyx"); if (lyx2lyx.empty()) { Alert::error(_("Conversion script not found"), bformat(_("%1$s is from an earlier" " version of LyX, but the" " conversion script lyx2lyx" " could not be found."), - from_utf8(filename))); + from_utf8(filename.absFilename()))); return false; } ostringstream command; - command << os::python() << ' ' << quoteName(lyx2lyx) - << " -t " << convert(LYX_FORMAT) - << " -o " << quoteName(tmpfile) << ' ' - << quoteName(filename); + command << os::python() + << ' ' << quoteName(lyx2lyx.toFilesystemEncoding()) + << " -t " << convert(LYX_FORMAT) + << " -o " << quoteName(tmpfile.toFilesystemEncoding()) + << ' ' << quoteName(filename.toFilesystemEncoding()); string const command_str = command.str(); lyxerr[Debug::INFO] << "Running '" @@ -668,7 +684,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename) bformat(_("%1$s is from an earlier version" " of LyX, but the lyx2lyx script" " failed to convert it."), - from_utf8(filename))); + from_utf8(filename.absFilename()))); return false; } else { bool const ret = readFile(tmpfile); @@ -682,7 +698,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename) Alert::error(_("Document format failure"), bformat(_("%1$s ended unexpectedly, which means" " that it is probably corrupted."), - from_utf8(filename))); + from_utf8(filename.absFilename()))); } //lyxerr << "removing " << MacroTable::localMacros().size() @@ -700,9 +716,9 @@ bool Buffer::save() const // We don't need autosaves in the immediate future. (Asger) resetAutosaveTimers(); - // make a backup + // make a backup if the file already exists string s; - if (lyxrc.make_backup) { + if (lyxrc.make_backup && fs::exists(pimpl_->filename.toFilesystemEncoding())) { s = fileName() + '~'; if (!lyxrc.backupdir_path.empty()) s = addName(lyxrc.backupdir_path, @@ -713,7 +729,7 @@ bool Buffer::save() const // But to use this we need fs::copy_file to actually do a copy, // even when the target file exists. (Lgb) try { - fs::copy_file(fileName(), s, false); + fs::copy_file(pimpl_->filename.toFilesystemEncoding(), s, false); } catch (fs::filesystem_error const & fe) { Alert::error(_("Backup failure"), @@ -725,34 +741,34 @@ bool Buffer::save() const } } - if (writeFile(fileName())) { + if (writeFile(pimpl_->filename)) { markClean(); removeAutosaveFile(fileName()); } else { // Saving failed, so backup is not backup if (lyxrc.make_backup) - rename(s, fileName()); + rename(FileName(s), pimpl_->filename); return false; } return true; } -bool Buffer::writeFile(string const & fname) const +bool Buffer::writeFile(FileName const & fname) const { - if (pimpl_->read_only && fname == fileName()) + if (pimpl_->read_only && fname == pimpl_->filename) return false; bool retval = false; if (params().compressed) { - io::filtering_ostream ofs(io::gzip_compressor() | io::file_sink(fname)); + io::filtering_ostream ofs(io::gzip_compressor() | io::file_sink(fname.toFilesystemEncoding())); if (!ofs) return false; retval = do_writeFile(ofs); } else { - ofstream ofs(fname.c_str(), ios::out|ios::trunc); + ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc); if (!ofs) return false; @@ -812,26 +828,42 @@ bool Buffer::do_writeFile(ostream & ofs) const } -void Buffer::makeLaTeXFile(string const & fname, +bool Buffer::makeLaTeXFile(FileName const & fname, string const & original_path, OutputParams const & runparams, bool output_preamble, bool output_body) { - lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl; + string const encoding = params().encoding().iconvName(); + lyxerr[Debug::LATEX] << "makeLaTeXFile encoding: " + << encoding << "..." << endl; - // FIXME UNICODE - // This creates an utf8 encoded file, but the inputenc commands - // specify other encodings - odocfstream ofs; + odocfstream ofs(encoding); if (!openFileWrite(ofs, fname)) - return; + return false; - writeLaTeXSource(ofs, original_path, + try { + writeLaTeXSource(ofs, original_path, runparams, output_preamble, output_body); + } + catch (iconv_codecvt_facet_exception &) { + Alert::error(_("Encoding error"), + _("Some characters of your document are not " + "representable in the chosen encoding.\n" + "Changing the document encoding to utf8 could help.")); + return false; + } ofs.close(); - if (ofs.fail()) + if (ofs.fail()) { lyxerr << "File '" << fname << "' was not closed properly." << endl; + Alert::error(_("Error closing file"), + _("The output file could not be closed properly.\n" + " Probably some characters of your document are not " + "representable in the chosen encoding.\n" + "Changing the document encoding to utf8 could help.")); + return false; + } + return true; } @@ -979,7 +1011,7 @@ bool Buffer::isDocBook() const } -void Buffer::makeDocBookFile(string const & fname, +void Buffer::makeDocBookFile(FileName const & fname, OutputParams const & runparams, bool const body_only) { @@ -990,7 +1022,7 @@ void Buffer::makeDocBookFile(string const & fname, if (!openFileWrite(ofs, fname)) return; - writeDocBookSource(ofs, fname, runparams, body_only); + writeDocBookSource(ofs, fname.absFilename(), runparams, body_only); ofs.close(); if (ofs.fail()) @@ -1026,7 +1058,7 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, else os << " PUBLIC \"-//OASIS//DTD DocBook V4.2//EN\""; - string preamble = params().preamble; + docstring preamble = from_utf8(params().preamble); if (runparams.flavor != OutputParams::XML ) { preamble += "\n"; preamble += "\n"; @@ -1034,13 +1066,13 @@ void Buffer::writeDocBookSource(odocstream & os, string const & fname, preamble += "\n"; } - string const name = runparams.nice ? changeExtension(pimpl_->filename, ".sgml") + string const name = runparams.nice ? changeExtension(fileName(), ".sgml") : fname; preamble += features.getIncludedFiles(name); preamble += features.getLyXSGMLEntities(); if (!preamble.empty()) { - os << "\n [ " << from_ascii(preamble) << " ]"; + os << "\n [ " << preamble << " ]"; } os << ">\n\n"; } @@ -1078,7 +1110,7 @@ int Buffer::runChktex() busy(true); // get LaTeX-Filename - string const name = getLatexName(); + string const name = getLatexName(false); string const path = temppath(); string const org_path = filePath(); @@ -1089,10 +1121,10 @@ int Buffer::runChktex() OutputParams runparams; runparams.flavor = OutputParams::LATEX; runparams.nice = false; - makeLaTeXFile(name, org_path, runparams); + makeLaTeXFile(FileName(name), org_path, runparams); TeXErrors terr; - Chktex chktex(lyxrc.chktex_command, name, filePath()); + Chktex chktex(lyxrc.chktex_command, onlyFilename(name), filePath()); int const res = chktex.run(terr); // run chktex if (res == -1) { @@ -1119,9 +1151,11 @@ void Buffer::validate(LaTeXFeatures & features) const features.require("dvipost"); // AMS Style is at document level - if (params().use_amsmath == BufferParams::AMS_ON + if (params().use_amsmath == BufferParams::package_on || tclass.provides(LyXTextClass::amsmath)) features.require("amsmath"); + if (params().use_esint == BufferParams::package_on) + features.require("esint"); for_each(paragraphs().begin(), paragraphs().end(), boost::bind(&Paragraph::validate, _1, boost::ref(features))); @@ -1176,7 +1210,7 @@ void Buffer::getLabelList(vector & list) const // This is also a buffer property (ale) -void Buffer::fillWithBibKeys(vector > & keys) +void Buffer::fillWithBibKeys(vector > & keys) const { /// if this is a child document and the parent is already loaded @@ -1200,11 +1234,12 @@ void Buffer::fillWithBibKeys(vector > & keys) } else if (it->lyxCode() == InsetBase::BIBITEM_CODE) { InsetBibitem const & inset = dynamic_cast(*it); - string const key = inset.getContents(); - string const opt = inset.getOptions(); - string const ref; // = pit->asString(this, false); - string const info = opt + "TheBibliographyRef" + ref; - keys.push_back(pair(key, info)); + // FIXME UNICODE + string const key = to_utf8(inset.getParam("key")); + docstring const label = inset.getParam("label"); + docstring const ref; // = pit->asString(this, false); + docstring const info = label + "TheBibliographyRef" + ref; + keys.push_back(pair(key, info)); } } } @@ -1226,7 +1261,7 @@ void Buffer::updateBibfilesCache() if (it->lyxCode() == InsetBase::BIBTEX_CODE) { InsetBibtex const & inset = dynamic_cast(*it); - vector const bibfiles = inset.getFiles(*this); + vector const bibfiles = inset.getFiles(*this); bibfilesCache_.insert(bibfilesCache_.end(), bibfiles.begin(), bibfiles.end()); @@ -1234,7 +1269,7 @@ void Buffer::updateBibfilesCache() InsetInclude & inset = dynamic_cast(*it); inset.updateBibfilesCache(*this); - vector const & bibfiles = + vector const & bibfiles = inset.getBibfilesCache(*this); bibfilesCache_.insert(bibfilesCache_.end(), bibfiles.begin(), @@ -1244,7 +1279,7 @@ void Buffer::updateBibfilesCache() } -vector const & Buffer::getBibfilesCache() const +vector const & Buffer::getBibfilesCache() const { // if this is a child document and the parent is already loaded // use the parent's cache instead @@ -1400,6 +1435,18 @@ docstring const Buffer::B_(string const & l10n) const } +docstring const Buffer::translateLabel(docstring const & label) const +{ + if (support::isAscii(label)) + // Probably standard layout, try to translate + return B_(to_ascii(label)); + else + // This must be a user defined layout. We cannot translate + // this, since gettext accepts only ascii keys. + return label; +} + + bool Buffer::isClean() const { return pimpl_->lyx_clean; @@ -1461,9 +1508,9 @@ void Buffer::markDirty() } -string const & Buffer::fileName() const +string const Buffer::fileName() const { - return pimpl_->filename; + return pimpl_->filename.absFilename(); } @@ -1511,19 +1558,19 @@ Buffer * Buffer::getMasterBuffer() } -MacroData const & Buffer::getMacro(std::string const & name) const +MacroData const & Buffer::getMacro(docstring const & name) const { return pimpl_->macros.get(name); } -bool Buffer::hasMacro(string const & name) const +bool Buffer::hasMacro(docstring const & name) const { return pimpl_->macros.has(name); } -void Buffer::insertMacro(string const & name, MacroData const & data) +void Buffer::insertMacro(docstring const & name, MacroData const & data) { MacroTable::globalMacros().insert(name, data); pimpl_->macros.insert(name, data); @@ -1562,7 +1609,8 @@ void Buffer::saveCursor(StableDocIterator cur, StableDocIterator anc) } -void Buffer::changeRefsIfUnique(string const & from, string const & to, InsetBase::Code code) +void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to, + InsetBase::Code code) { //FIXME: This does not work for child documents yet. BOOST_ASSERT(code == InsetBase::CITE_CODE || code == InsetBase::REF_CODE); @@ -1570,10 +1618,10 @@ void Buffer::changeRefsIfUnique(string const & from, string const & to, InsetBas vector labels; if (code == InsetBase::CITE_CODE) { - vector > keys; + vector > keys; fillWithBibKeys(keys); - vector >::const_iterator bit = keys.begin(); - vector >::const_iterator bend = keys.end(); + vector >::const_iterator bit = keys.begin(); + vector >::const_iterator bend = keys.end(); for (; bit != bend; ++bit) // FIXME UNICODE @@ -1581,20 +1629,20 @@ void Buffer::changeRefsIfUnique(string const & from, string const & to, InsetBas } else getLabelList(labels); - // FIXME UNICODE - if (lyx::count(labels.begin(), labels.end(), from_utf8(from)) > 1) + if (lyx::count(labels.begin(), labels.end(), from) > 1) return; for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { if (it->lyxCode() == code) { InsetCommand & inset = dynamic_cast(*it); - inset.replaceContents(from, to); + inset.replaceContents(to_utf8(from), to_utf8(to)); } } } -void Buffer::getSourceCode(odocstream & os, pit_type par_begin, pit_type par_end, bool full_source) +void Buffer::getSourceCode(odocstream & os, pit_type par_begin, + pit_type par_end, bool full_source) { OutputParams runparams; runparams.nice = true; @@ -1617,7 +1665,8 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, pit_type par_end if (par_begin + 1 == par_end) os << "% Preview source code for paragraph " << par_begin << "\n\n"; else - os << "% Preview source code from paragraph " << par_begin << " to " << par_end - 1 << "\n\n"; + os << "% Preview source code from paragraph " << par_begin + << " to " << par_end - 1 << "\n\n"; // output paragraphs if (isLatex()) { texrow().reset(); @@ -1633,7 +1682,7 @@ void Buffer::getSourceCode(odocstream & os, pit_type par_begin, pit_type par_end ErrorList const & Buffer::errorList(string const & type) const { static ErrorList const emptyErrorList; - std::map::const_iterator I = errorLists_.find(type); + std::map::const_iterator I = errorLists_.find(type); if (I == errorLists_.end()) return emptyErrorList;