X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fbuffer.C;h=e0877225236d80d11965fe5c15af5cddd7dcc8cb;hb=4d5282a7aca1e8d80d310ce3a3514562d6584b36;hp=76e9de907ab0623ee5621900897781554f6d971b;hpb=627b8df878fa8979c1a52827b80ea5aed5e6e92c;p=lyx.git diff --git a/src/buffer.C b/src/buffer.C index 76e9de907a..e087722523 100644 --- a/src/buffer.C +++ b/src/buffer.C @@ -41,13 +41,13 @@ #include "output.h" #include "output_docbook.h" #include "output_latex.h" -#include "output_linuxdoc.h" #include "paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" #include "pariterator.h" #include "sgml.h" #include "texrow.h" +#include "TocBackend.h" #include "undo.h" #include "version.h" @@ -56,32 +56,35 @@ #include "insets/insetinclude.h" #include "insets/insettext.h" -#include "mathed/math_macrotemplate.h" -#include "mathed/math_macrotable.h" -#include "mathed/math_support.h" +#include "mathed/MathMacroTemplate.h" +#include "mathed/MathMacroTable.h" +#include "mathed/MathSupport.h" #include "frontends/Alert.h" #include "graphics/Previews.h" +#include "support/types.h" +#include "support/lyxalgo.h" #include "support/filetools.h" #include "support/fs_extras.h" -#ifdef USE_COMPRESSION -# include "support/gzstream.h" -#endif #include "support/lyxlib.h" #include "support/os.h" #include "support/path.h" #include "support/textutils.h" #include "support/convert.h" +#include +#include +#include #include +#include #include #if defined (HAVE_UTIME_H) -# include +#include #elif defined (HAVE_SYS_UTIME_H) -# include +#include #endif #include @@ -90,43 +93,43 @@ #include -using lyx::pos_type; -using lyx::pit_type; - -using lyx::support::AddName; -using lyx::support::bformat; -using lyx::support::ChangeExtension; -using lyx::support::cmd_ret; -using lyx::support::createBufferTmpDir; -using lyx::support::destroyDir; -using lyx::support::getFormatFromContents; -using lyx::support::IsDirWriteable; -using lyx::support::LibFileSearch; -using lyx::support::latex_path; -using lyx::support::ltrim; -using lyx::support::MakeAbsPath; -using lyx::support::MakeDisplayPath; -using lyx::support::MakeLatexName; -using lyx::support::OnlyFilename; -using lyx::support::OnlyPath; -using lyx::support::Path; -using lyx::support::QuoteName; -using lyx::support::removeAutosaveFile; -using lyx::support::rename; -using lyx::support::RunCommand; -using lyx::support::split; -using lyx::support::subst; -using lyx::support::tempName; -using lyx::support::trim; - -namespace os = lyx::support::os; +namespace lyx { + +using support::addName; +using support::bformat; +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; +using support::latex_path; +using support::ltrim; +using support::makeAbsPath; +using support::makeDisplayPath; +using support::makeLatexName; +using support::onlyFilename; +using support::onlyPath; +using support::quoteName; +using support::removeAutosaveFile; +using support::rename; +using support::runCommand; +using support::split; +using support::subst; +using support::tempName; +using support::trim; + +namespace Alert = frontend::Alert; +namespace os = support::os; namespace fs = boost::filesystem; +namespace io = boost::iostreams; using std::endl; using std::for_each; using std::make_pair; -using std::ifstream; using std::ios; using std::map; using std::ostream; @@ -138,12 +141,9 @@ using std::vector; using std::string; -// all these externs should eventually be removed. -extern BufferList bufferlist; - namespace { -int const LYX_FORMAT = 242; +int const LYX_FORMAT = 255; } // namespace anon @@ -153,7 +153,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; @@ -178,10 +178,7 @@ public: bool read_only; /// name of the file the buffer is associated with. - string filename; - - /// The path to the document file. - string filepath; + FileName filename; boost::scoped_ptr messages; @@ -196,17 +193,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), filepath(OnlyPath(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.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 @@ -214,7 +215,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; } @@ -230,11 +231,12 @@ Buffer::~Buffer() if (!temppath().empty() && !destroyDir(temppath())) { Alert::warning(_("Could not remove temporary directory"), - bformat(_("Could not remove the temporary directory %1$s"), temppath())); + bformat(_("Could not remove the temporary directory %1$s"), + from_utf8(temppath()))); } // Remove any previewed LaTeX snippets associated with this buffer. - lyx::graphics::Previews::get().removeLoader(*this); + graphics::Previews::get().removeLoader(*this); } @@ -328,10 +330,22 @@ 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"); - return no_path ? OnlyFilename(name) : name; + string const name = changeExtension(makeLatexName(fileName()), ".tex"); + return no_path ? onlyFilename(name) : name; } @@ -344,23 +358,24 @@ pair const Buffer::getLogName() const string const path = temppath(); - string const fname = AddName(path, - OnlyFilename(ChangeExtension(filename, - ".log"))); - string const bname = - AddName(path, OnlyFilename( - ChangeExtension(filename, - formats.extension("literate") + ".out"))); + FileName const fname(addName(temppath(), + onlyFilename(changeExtension(filename, + ".log")))); + FileName const bname( + addName(path, onlyFilename( + changeExtension(filename, + 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()); } @@ -375,9 +390,10 @@ void Buffer::setReadonly(bool const flag) void Buffer::setFileName(string const & newfile) { - pimpl_->filename = MakeAbsPath(newfile); - pimpl_->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(); } @@ -388,8 +404,8 @@ namespace { void unknownClass(string const & unknown) { Alert::warning(_("Unknown document class"), - bformat(_("Using the default document class, because the " - "class %1$s is unknown."), unknown)); + bformat(_("Using the default document class, because the " + "class %1$s is unknown."), from_utf8(unknown))); } } // anon @@ -403,6 +419,7 @@ int Buffer::readHeader(LyXLex & lex) // Initialize parameters that may be/go lacking in header: params().branchlist().clear(); + params().preamble.erase(); params().options.erase(); params().float_placement.erase(); params().paperwidth.erase(); @@ -415,6 +432,8 @@ int Buffer::readHeader(LyXLex & lex) params().headsep.erase(); params().footskip.erase(); + ErrorList & errorList = errorLists_["Parse"]; + while (lex.isOK()) { lex.next(); string const token = lex.getString(); @@ -431,7 +450,7 @@ int Buffer::readHeader(LyXLex & lex) continue; } - lyxerr[Debug::PARSER] << "Handling header token: `" + lyxerr[Debug::PARSER] << "Handling document header token: `" << token << '\'' << endl; string unknown = params().readToken(lex, token); @@ -440,19 +459,21 @@ int Buffer::readHeader(LyXLex & lex) unknownClass(unknown); } else { ++unknown_tokens; - string const s = bformat(_("Unknown token: " - "%1$s %2$s\n"), - token, - lex.getString()); - error(ErrorItem(_("Header error"), s, - -1, 0, 0)); + docstring const s = bformat(_("Unknown token: " + "%1$s %2$s\n"), + from_utf8(token), + lex.getDocString()); + errorList.push_back(ErrorItem(_("Document header error"), + s, -1, 0, 0)); } } } if (begin_header_line) { - string const s = _("\\begin_header is missing"); - error(ErrorItem(_("Header error"), s, -1, 0, 0)); + docstring const s = _("\\begin_header is missing"); + errorList.push_back(ErrorItem(_("Document header error"), + s, -1, 0, 0)); } + return unknown_tokens; } @@ -462,45 +483,49 @@ int Buffer::readHeader(LyXLex & lex) // Returns false if "\end_document" is not read (Asger) bool Buffer::readDocument(LyXLex & lex) { + ErrorList & errorList = errorLists_["Parse"]; + errorList.clear(); + lex.next(); string const token = lex.getString(); if (token != "\\begin_document") { - string const s = _("\\begin_document is missing"); - error(ErrorItem(_("Header error"), s, -1, 0, 0)); + docstring const s = _("\\begin_document is missing"); + errorList.push_back(ErrorItem(_("Document header error"), + s, -1, 0, 0)); } - if (paragraphs().empty()) { - readHeader(lex); - if (!params().getLyXTextClass().load()) { - 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.", theclass)); - params().textclass = 0; - } - } else { - // We don't want to adopt the parameters from the - // document we insert, so read them into a temporary buffer - // and then discard it + // we are reading in a brand new document + BOOST_ASSERT(paragraphs().empty()); - Buffer tmpbuf("", false); - tmpbuf.readHeader(lex); + readHeader(lex); + if (!params().getLyXTextClass().load(filePath())) { + 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))); + params().textclass = 0; } - return text().read(*this, lex); + bool const res = text().read(*this, lex, errorList); + for_each(text().paragraphs().begin(), + text().paragraphs().end(), + bind(&Paragraph::setInsetOwner, _1, &inset())); + updateBibfilesCache(); + + return res; } // needed to insert the selection void Buffer::insertStringAsLines(ParagraphList & pars, pit_type & pit, pos_type & pos, - LyXFont const & fn, string const & str, bool autobreakrows) + LyXFont const & fn, docstring const & str, bool autobreakrows) { LyXFont font = fn; // insert the string, don't insert doublespace bool space_inserted = true; - for (string::const_iterator cit = str.begin(); + for (docstring::const_iterator cit = str.begin(); cit != str.end(); ++cit) { Paragraph & par = pars[pit]; if (*cit == '\n') { @@ -520,23 +545,23 @@ void Buffer::insertStringAsLines(ParagraphList & pars, } else if (*cit == '\t') { if (!par.isFreeSpacing()) { // tabs are like spaces here - par.insertChar(pos, ' ', font); + par.insertChar(pos, ' ', font, params().trackChanges); ++pos; space_inserted = true; } else { const pos_type n = 8 - pos % 8; for (pos_type i = 0; i < n; ++i) { - par.insertChar(pos, ' ', font); + par.insertChar(pos, ' ', font, params().trackChanges); ++pos; } space_inserted = true; } - } else if (!IsPrintable(*cit)) { + } else if (!isPrintable(*cit)) { // Ignore unprintables continue; } else { // just insert the character - par.insertChar(pos, *cit, font); + par.insertChar(pos, *cit, font, params().trackChanges); ++pos; space_inserted = (*cit == ' '); } @@ -548,29 +573,25 @@ void Buffer::insertStringAsLines(ParagraphList & pars, bool Buffer::readFile(string const & filename) { // Check if the file is compressed. - string const format = getFormatFromContents(filename); + FileName const name(makeAbsPath(filename)); + string const format = getFormatFromContents(name); if (format == "gzip" || format == "zip" || format == "compress") { params().compressed = true; } // remove dummy empty par paragraphs().clear(); - bool ret = readFile(filename, paragraphs().size()); + LyXLex lex(0, 0); + lex.setFile(name); + if (!readFile(lex, filename)) + return false; // After we have read a file, we must ensure that the buffer // language is set and used in the gui. // If you know of a better place to put this, please tell me. (Lgb) updateDocLang(params().language); - return ret; -} - - -bool Buffer::readFile(string const & filename, pit_type const pit) -{ - LyXLex lex(0, 0); - lex.setFile(filename); - return readFile(lex, filename, pit); + return true; } @@ -586,13 +607,13 @@ void Buffer::fully_loaded(bool const value) } -bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit) +bool Buffer::readFile(LyXLex & lex, string const & filename) { BOOST_ASSERT(!filename.empty()); if (!lex.isOK()) { Alert::error(_("Document could not be read"), - bformat(_("%1$s could not be read."), filename)); + bformat(_("%1$s could not be read."), from_utf8(filename))); return false; } @@ -601,7 +622,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit) if (!lex.isOK()) { Alert::error(_("Document could not be read"), - bformat(_("%1$s could not be read."), filename)); + bformat(_("%1$s could not be read."), from_utf8(filename))); return false; } @@ -611,7 +632,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit) Alert::error(_("Document format failure"), bformat(_("%1$s is not a LyX document."), - filename)); + from_utf8(filename))); return false; } @@ -633,41 +654,41 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit) bformat(_("%1$s is from an earlier" " version of LyX, but a temporary" " file for converting it could" - " not be created."), - filename)); + " not be created."), + from_utf8(filename))); 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."), - filename)); + " could not be found."), + from_utf8(filename))); return false; } ostringstream command; - command << "python " << QuoteName(lyx2lyx) + command << os::python() << ' ' << quoteName(lyx2lyx.toFilesystemEncoding()) << " -t " << convert(LYX_FORMAT) - << " -o " << QuoteName(tmpfile) << ' ' - << QuoteName(filename); + << " -o " << quoteName(tmpfile) << ' ' + << quoteName(filename); string const command_str = command.str(); lyxerr[Debug::INFO] << "Running '" << command_str << '\'' << endl; - cmd_ret const ret = RunCommand(command_str); + cmd_ret const ret = runCommand(command_str); if (ret.first != 0) { Alert::error(_("Conversion script failed"), bformat(_("%1$s is from an earlier version" " of LyX, but the lyx2lyx script" - " failed to convert it."), - filename)); + " failed to convert it."), + from_utf8(filename))); return false; } else { - bool const ret = readFile(tmpfile, pit); + bool const ret = readFile(tmpfile); // Do stuff with tmpfile name and buffer name here. return ret; } @@ -677,14 +698,13 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, pit_type const pit) if (readDocument(lex)) { Alert::error(_("Document format failure"), bformat(_("%1$s ended unexpectedly, which means" - " that it is probably corrupted."), - filename)); + " that it is probably corrupted."), + from_utf8(filename))); } //lyxerr << "removing " << MacroTable::localMacros().size() // << " temporary macro entries" << endl; //MacroTable::localMacros().clear(); - params().setPaperStuff(); pimpl_->file_fully_loaded = true; return true; @@ -697,61 +717,59 @@ 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, + s = addName(lyxrc.backupdir_path, subst(os::internal_path(s),'/','!')); // It might very well be that this variant is just // good enough. (Lgb) // But to use this we need fs::copy_file to actually do a copy, // even when the target file exists. (Lgb) - if (fs::exists(fileName()) && fs::is_writable(fs::path(fileName()).branch_path())) { - //try { - fs::copy_file(fileName(), s, false); - //} - //catch (fs::filesystem_error const & fe) { - //lyxerr << "LyX was not able to make backup copy. Beware.\n" - // << fe.what() << endl; - //} + try { + fs::copy_file(pimpl_->filename.toFilesystemEncoding(), s, false); + } + catch (fs::filesystem_error const & fe) { + Alert::error(_("Backup failure"), + bformat(_("LyX was not able to make a backup copy in %1$s.\n" + "Please check if the directory exists and is writeable."), + from_utf8(fs::path(s).branch_path().native_directory_string()))); + lyxerr[Debug::DEBUG] << "Fs error: " + << fe.what() << endl; } } - 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) { -#ifdef USE_COMPRESSION - gz::ogzstream ofs(fname.c_str(), ios::out|ios::trunc); + io::filtering_ostream ofs(io::gzip_compressor() | io::file_sink(fname.toFilesystemEncoding())); if (!ofs) return false; retval = do_writeFile(ofs); -#else - return false; -#endif } else { - ofstream ofs(fname.c_str(), ios::out|ios::trunc); + ofstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc); if (!ofs) return false; @@ -811,27 +829,59 @@ bool Buffer::do_writeFile(ostream & ofs) const } -void Buffer::makeLaTeXFile(string const & fname, +bool Buffer::makeLaTeXFile(string const & fname, string const & original_path, OutputParams const & runparams, bool output_preamble, bool output_body) { - lyxerr[Debug::LATEX] << "makeLaTeXFile..." << endl; + string encoding; + if (params().inputenc == "auto") + encoding = params().language->encoding()->iconvName(); + else { + Encoding const * enc = encodings.getFromLaTeXName(params().inputenc); + if (enc) + encoding = enc->iconvName(); + else { + lyxerr << "Unknown inputenc value `" + << params().inputenc + << "'. Using `auto' instead." << endl; + encoding = params().language->encoding()->iconvName(); + } + } + lyxerr[Debug::LATEX] << "makeLaTeXFile encoding: " + << encoding << "..." << endl; - ofstream ofs; + odocfstream ofs(encoding); if (!openFileWrite(ofs, fname)) - return; + return false; - makeLaTeXFile(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; } -void Buffer::makeLaTeXFile(ostream & os, +void Buffer::writeLaTeXSource(odocstream & os, string const & original_path, OutputParams const & runparams_in, bool const output_preamble, bool const output_body) @@ -840,7 +890,7 @@ void Buffer::makeLaTeXFile(ostream & os, // validate the buffer. lyxerr[Debug::LATEX] << " Validating buffer..." << endl; - LaTeXFeatures features(*this, params(), runparams.nice); + LaTeXFeatures features(*this, params(), runparams); validate(features); lyxerr[Debug::LATEX] << " Buffer validation done." << endl; @@ -858,7 +908,7 @@ void Buffer::makeLaTeXFile(ostream & os, texrow().newline(); texrow().newline(); } - lyxerr[Debug::INFO] << "lyx header finished" << endl; + lyxerr[Debug::INFO] << "lyx document header finished" << endl; // 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 @@ -877,11 +927,13 @@ void Buffer::makeLaTeXFile(ostream & os, texrow().newline(); } if (!original_path.empty()) { - string const inputpath = latex_path(original_path); + // FIXME UNICODE + // We don't know the encoding of inputpath + docstring const inputpath = from_utf8(latex_path(original_path)); os << "\\makeatletter\n" - << "\\def\\input@path{{" - << inputpath << "/}}\n" - << "\\makeatother\n"; + << "\\def\\input@path{{" + << inputpath << "/}}\n" + << "\\makeatother\n"; texrow().newline(); texrow().newline(); texrow().newline(); @@ -900,9 +952,11 @@ void Buffer::makeLaTeXFile(ostream & os, lyxerr[Debug::INFO] << "preamble finished, now the body." << endl; if (!lyxrc.language_auto_begin) { - os << subst(lyxrc.language_command_begin, "$$lang", - params().language->babel()) - << endl; + // FIXME UNICODE + os << from_utf8(subst(lyxrc.language_command_begin, + "$$lang", + params().language->babel())) + << '\n'; texrow().newline(); } @@ -927,9 +981,10 @@ void Buffer::makeLaTeXFile(ostream & os, texrow().newline(); if (!lyxrc.language_auto_end) { - os << subst(lyxrc.language_command_end, "$$lang", - params().language->babel()) - << endl; + os << from_utf8(subst(lyxrc.language_command_end, + "$$lang", + params().language->babel())) + << '\n'; texrow().newline(); } @@ -958,12 +1013,6 @@ bool Buffer::isLatex() const } -bool Buffer::isLinuxDoc() const -{ - return params().getLyXTextClass().outputType() == LINUXDOC; -} - - bool Buffer::isLiterate() const { return params().getLyXTextClass().outputType() == LITERATE; @@ -976,66 +1025,18 @@ bool Buffer::isDocBook() const } -bool Buffer::isSGML() const -{ - LyXTextClass const & tclass = params().getLyXTextClass(); - - return tclass.outputType() == LINUXDOC || - tclass.outputType() == DOCBOOK; -} - - -void Buffer::makeLinuxDocFile(string const & fname, +void Buffer::makeDocBookFile(string const & fname, OutputParams const & runparams, bool const body_only) { - ofstream ofs; + lyxerr[Debug::LATEX] << "makeDocBookFile..." << endl; + + //ofstream ofs; + odocfstream ofs; if (!openFileWrite(ofs, fname)) return; - LaTeXFeatures features(*this, params(), runparams.nice); - validate(features); - - texrow().reset(); - - LyXTextClass const & tclass = params().getLyXTextClass(); - - string const & top_element = tclass.latexname(); - - if (!body_only) { - ofs << tclass.class_header(); - - string preamble = params().preamble; - string const name = runparams.nice ? ChangeExtension(pimpl_->filename, ".sgml") - : fname; - preamble += features.getIncludedFiles(name); - preamble += features.getLyXSGMLEntities(); - - if (!preamble.empty()) { - ofs << " [ " << preamble << " ]"; - } - ofs << ">\n\n"; - - if (params().options.empty()) - sgml::openTag(ofs, top_element); - else { - string top = top_element; - top += ' '; - top += params().options; - sgml::openTag(ofs, top); - } - } - - ofs << "\n"; - - linuxdocParagraphs(*this, paragraphs(), ofs, runparams); - - if (!body_only) { - ofs << "\n\n"; - sgml::closeTag(ofs, top_element); - } + writeDocBookSource(ofs, fname, runparams, body_only); ofs.close(); if (ofs.fail()) @@ -1043,37 +1044,35 @@ void Buffer::makeLinuxDocFile(string const & fname, } -void Buffer::makeDocBookFile(string const & fname, +void Buffer::writeDocBookSource(odocstream & os, string const & fname, OutputParams const & runparams, bool const only_body) { - ofstream ofs; - if (!openFileWrite(ofs, fname)) - return; - - LaTeXFeatures features(*this, params(), runparams.nice); + LaTeXFeatures features(*this, params(), runparams); validate(features); texrow().reset(); LyXTextClass const & tclass = params().getLyXTextClass(); - string const & top_element = tclass.latexname(); + string const top_element = tclass.latexname(); if (!only_body) { if (runparams.flavor == OutputParams::XML) - ofs << "encoding()->Name() << "\"?>\n"; + os << "\n"; - ofs << "\n"; preamble += "\n"; @@ -1081,15 +1080,15 @@ void Buffer::makeDocBookFile(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()) { - ofs << "\n [ " << preamble << " ]"; + os << "\n [ " << preamble << " ]"; } - ofs << ">\n\n"; + os << ">\n\n"; } string top = top_element; @@ -1105,20 +1104,16 @@ void Buffer::makeDocBookFile(string const & fname, top += params().options; } - ofs << "\n"; params().getLyXTextClass().counters().reset(); - sgml::openTag(ofs, top); - ofs << '\n'; - docbookParagraphs(paragraphs(), *this, ofs, runparams); - sgml::closeTag(ofs, top_element); - - ofs.close(); - if (ofs.fail()) - lyxerr << "File '" << fname << "' was not closed properly." << endl; + sgml::openTag(os, top); + os << '\n'; + docbookParagraphs(paragraphs(), *this, os, runparams); + sgml::closeTag(os, top_element); } @@ -1133,7 +1128,7 @@ int Buffer::runChktex() string const path = temppath(); string const org_path = filePath(); - Path p(path); // path to LaTeX file + support::Path p(path); // path to LaTeX file message(_("Running chktex...")); // Generate the LaTeX file if neccessary @@ -1150,12 +1145,14 @@ int Buffer::runChktex() Alert::error(_("chktex failure"), _("Could not run chktex successfully.")); } else if (res > 0) { - // Insert all errors as errors boxes - bufferErrors(*this, terr); + // Fill-in the error list with the TeX errors + bufferErrors(*this, terr, errorLists_["ChkTex"]); } busy(false); + errors("ChkTeX"); + return res; } @@ -1164,16 +1161,15 @@ void Buffer::validate(LaTeXFeatures & features) const { LyXTextClass const & tclass = params().getLyXTextClass(); - if (features.isAvailable("dvipost") && params().tracking_changes - && params().output_changes) { + if (features.isAvailable("dvipost") && params().outputChanges) features.require("dvipost"); - features.require("color"); - } // 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))); @@ -1208,7 +1204,7 @@ void Buffer::validate(LaTeXFeatures & features) const } -void Buffer::getLabelList(vector & list) const +void Buffer::getLabelList(vector & list) const { /// if this is a child document and the parent is already loaded /// Use the parent's list instead [ale990407] @@ -1262,6 +1258,53 @@ void Buffer::fillWithBibKeys(vector > & keys) } +void Buffer::updateBibfilesCache() +{ + // if this is a child document and the parent is already loaded + // update the parent's cache instead + Buffer * tmp = getMasterBuffer(); + BOOST_ASSERT(tmp); + if (tmp != this) { + tmp->updateBibfilesCache(); + return; + } + + bibfilesCache_.clear(); + for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) { + if (it->lyxCode() == InsetBase::BIBTEX_CODE) { + InsetBibtex const & inset = + dynamic_cast(*it); + vector const bibfiles = inset.getFiles(*this); + bibfilesCache_.insert(bibfilesCache_.end(), + bibfiles.begin(), + bibfiles.end()); + } else if (it->lyxCode() == InsetBase::INCLUDE_CODE) { + InsetInclude & inset = + dynamic_cast(*it); + inset.updateBibfilesCache(*this); + vector const & bibfiles = + inset.getBibfilesCache(*this); + bibfilesCache_.insert(bibfilesCache_.end(), + bibfiles.begin(), + bibfiles.end()); + } + } +} + + +vector const & Buffer::getBibfilesCache() const +{ + // if this is a child document and the parent is already loaded + // use the parent's cache instead + Buffer const * tmp = getMasterBuffer(); + BOOST_ASSERT(tmp); + if (tmp != this) + return tmp->getBibfilesCache(); + + return bibfilesCache_; +} + + bool Buffer::isDepClean(string const & name) const { DepClean::const_iterator const it = pimpl_->dep_clean.find(name); @@ -1288,8 +1331,8 @@ bool Buffer::dispatch(FuncRequest const & func, bool * result) bool dispatched = true; switch (func.action) { - case LFUN_EXPORT: { - bool const tmp = Exporter::Export(this, func.argument, false); + case LFUN_BUFFER_EXPORT: { + bool const tmp = Exporter::Export(this, to_utf8(func.argument()), false); if (result) *result = tmp; break; @@ -1307,14 +1350,15 @@ void Buffer::changeLanguage(Language const * from, Language const * to) BOOST_ASSERT(from); BOOST_ASSERT(to); - lyxerr << "Changing Language!" << endl; - // Take care of l10n/i18n updateDocLang(to); for_each(par_iterator_begin(), par_iterator_end(), bind(&Paragraph::changeLanguage, _1, params(), from, to)); + + text().current_font.setLanguage(to); + text().real_current_font.setLanguage(to); } @@ -1323,6 +1367,8 @@ void Buffer::updateDocLang(Language const * nlang) BOOST_ASSERT(nlang); pimpl_->messages.reset(new Messages(nlang->code())); + + updateLabels(*this); } @@ -1365,25 +1411,25 @@ bool Buffer::hasParWithID(int const id) const ParIterator Buffer::par_iterator_begin() { - return ::par_iterator_begin(inset()); + return lyx::par_iterator_begin(inset()); } ParIterator Buffer::par_iterator_end() { - return ::par_iterator_end(inset()); + return lyx::par_iterator_end(inset()); } ParConstIterator Buffer::par_iterator_begin() const { - return ::par_const_iterator_begin(inset()); + return lyx::par_const_iterator_begin(inset()); } ParConstIterator Buffer::par_iterator_end() const { - return ::par_const_iterator_end(inset()); + return lyx::par_const_iterator_end(inset()); } @@ -1393,16 +1439,27 @@ Language const * Buffer::getLanguage() const } -string const Buffer::B_(string const & l10n) const +docstring const Buffer::B_(string const & l10n) const { - if (pimpl_->messages.get()) { + if (pimpl_->messages.get()) return pimpl_->messages->get(l10n); - } return _(l10n); } +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; @@ -1459,21 +1516,20 @@ void Buffer::markDirty() DepClean::iterator it = pimpl_->dep_clean.begin(); DepClean::const_iterator const end = pimpl_->dep_clean.end(); - for (; it != end; ++it) { + for (; it != end; ++it) it->second = false; - } } -string const & Buffer::fileName() const +string const Buffer::fileName() const { - return pimpl_->filename; + return pimpl_->filename.absFilename(); } string const & Buffer::filePath() const { - return pimpl_->filepath; + return params().filepath; } @@ -1492,8 +1548,8 @@ void Buffer::setParentName(string const & name) Buffer const * Buffer::getMasterBuffer() const { if (!params().parentname.empty() - && bufferlist.exists(params().parentname)) { - Buffer const * buf = bufferlist.getBuffer(params().parentname); + && theBufferList().exists(params().parentname)) { + Buffer const * buf = theBufferList().getBuffer(params().parentname); if (buf) return buf->getMasterBuffer(); } @@ -1502,19 +1558,32 @@ Buffer const * Buffer::getMasterBuffer() const } -MacroData const & Buffer::getMacro(std::string const & name) const +Buffer * Buffer::getMasterBuffer() +{ + if (!params().parentname.empty() + && theBufferList().exists(params().parentname)) { + Buffer * buf = theBufferList().getBuffer(params().parentname); + if (buf) + return buf->getMasterBuffer(); + } + + return this; +} + + +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); @@ -1527,19 +1596,117 @@ void Buffer::buildMacros() pimpl_->macros = MacroTable::globalMacros(); // Now add our own. - ParagraphList & pars = text().paragraphs(); + ParagraphList const & pars = text().paragraphs(); for (size_t i = 0, n = pars.size(); i != n; ++i) { //lyxerr << "searching main par " << i // << " for macro definitions" << std::endl; - InsetList::iterator it = pars[i].insetlist.begin(); - InsetList::iterator end = pars[i].insetlist.end(); + InsetList const & insets = pars[i].insetlist; + InsetList::const_iterator it = insets.begin(); + InsetList::const_iterator end = insets.end(); for ( ; it != end; ++it) { //lyxerr << "found inset code " << it->inset->lyxCode() << std::endl; if (it->inset->lyxCode() == InsetBase::MATHMACRO_CODE) { - MathMacroTemplate & mac - = static_cast(*it->inset); + MathMacroTemplate const & mac + = static_cast(*it->inset); insertMacro(mac.name(), mac.asMacroData()); } } } } + + +void Buffer::saveCursor(StableDocIterator cur, StableDocIterator anc) +{ + cursor_ = cur; + anchor_ = anc; +} + + +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); + // Check if the label 'from' appears more than once + vector labels; + + if (code == InsetBase::CITE_CODE) { + vector > keys; + fillWithBibKeys(keys); + vector >::const_iterator bit = keys.begin(); + vector >::const_iterator bend = keys.end(); + + for (; bit != bend; ++bit) + // FIXME UNICODE + labels.push_back(from_utf8(bit->first)); + } else + getLabelList(labels); + + 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(to_utf8(from), to_utf8(to)); + } + } +} + + +void Buffer::getSourceCode(odocstream & os, pit_type par_begin, + pit_type par_end, bool full_source) +{ + OutputParams runparams; + runparams.nice = true; + runparams.flavor = OutputParams::LATEX; + runparams.linelen = lyxrc.ascii_linelen; + // No side effect of file copying and image conversion + runparams.dryrun = true; + + /* Support for docbook temprarily commented out. */ + if (full_source) { + os << "% Preview source code\n\n"; + if (isLatex()) + writeLaTeXSource(os, filePath(), runparams, true, true); + else { + writeDocBookSource(os, fileName(), runparams, false); + } + } else { + runparams.par_begin = par_begin; + runparams.par_end = 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"; + // output paragraphs + if (isLatex()) { + texrow().reset(); + latexParagraphs(*this, paragraphs(), os, texrow(), runparams); + } else { + // DocBook + docbookParagraphs(paragraphs(), *this, os, runparams); + } + } +} + + +ErrorList const & Buffer::errorList(string const & type) const +{ + static ErrorList const emptyErrorList; + std::map::const_iterator I = errorLists_.find(type); + if (I == errorLists_.end()) + return emptyErrorList; + + return I->second; +} + + +ErrorList & Buffer::errorList(string const & type) +{ + return errorLists_[type]; +} + + +} // namespace lyx