The attached patch builds on Abdel's earlier work and, I think, solves the remaining problems. Whether this is the best way to do it, I'm not sure. Abdel was talking about a more major re-organization of the code, but maybe that could wait.
What I've done is add an optional argument to LFUN_BUFFER_CHILD_OPEN indicating whether the file is being auto-loaded. (Contrary to what I said before, this is ok, since we're expecting a valid LyX filename, and one isn't going to end with "|true".) There are also corresponding booleans in LyXView::loadLyXFile and BufferView::loadLyXFile.
Abdel, I'll leave it up to you to decide what's best here. But either way, please see the long FIXME at the end of LyXView::loadLyXFile(). It looks to me as if we're doing a lot of things twice.
Richard -- ================================================================== Richard G Heck, Jr Professor of Philosophy Brown University http://frege.brown.edu/heck/ ================================================================== Get my public key from http://sks.keyserver.penguin.de Hash: 0x1DE91F1E66FFBDEC Learn how to sign your email using Thunderbird and GnuPG at: http://dudu.dyn.2-h.org/nist/gpg-enigmail-howto
Index: src/Buffer.cpp =================================================================== --- src/Buffer.cpp (revision 18803) +++ src/Buffer.cpp (working copy) @@ -1616,7 +1616,11 @@ void Buffer::setParentName(string const & name) { - params().parentname = name; + if (name == pimpl_->filename.absFilename()) + // Avoids recursive include. + params().parentname.clear(); + else + params().parentname = name; } Index: src/BufferView.cpp =================================================================== --- src/BufferView.cpp (revision 18803) +++ src/BufferView.cpp (working copy) @@ -233,8 +233,8 @@ graphics::Previews::get().generateBufferPreviews(*buffer_); } - -bool BufferView::loadLyXFile(FileName const & filename, bool tolastfiles) +// FIXME: all of this should go in a helper file in buffer_func. +Buffer * BufferView::loadLyXFile(FileName const & filename, bool auto_open) { // File already open? if (theBufferList().exists(filename.absFilename())) { @@ -246,12 +246,13 @@ text, 0, 1, _("&Revert"), _("&Switch to document")); if (ret != 0) { - setBuffer(theBufferList().getBuffer(filename.absFilename())); - return true; + Buffer * buf = theBufferList().getBuffer(filename.absFilename()); + setBuffer(buf); + return buf; } // FIXME: should be LFUN_REVERT if (!theBufferList().close(theBufferList().getBuffer(filename.absFilename()), false)) - return false; + return 0; // Fall through to new load. (Asger) buffer_ = 0; } @@ -262,7 +263,7 @@ b = theBufferList().newBuffer(filename.absFilename()); if (!lyx::loadLyXFile(b, filename)) { theBufferList().release(b); - return false; + return 0; } } else { docstring text = bformat(_("The document %1$s does not yet " @@ -274,34 +275,15 @@ if (ret == 0) { b = newFile(filename.absFilename(), string(), true); if (!b) - return false; + return 0; } else - return false; + return 0; } - setBuffer(b); - // Send the "errors" signal in case of parsing errors - b->errors("Parse"); + if (!auto_open) + setBuffer(b); - // Update the labels and section numbering. - updateLabels(*buffer_); - // scroll to the position when the file was last closed - if (lyxrc.use_lastfilepos) { - pit_type pit; - pos_type pos; - boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename); - // if successfully move to pit (returned par_id is not zero), update metrics and reset font - if (moveToPosition(pit, pos, 0, 0).get<1>()) { - if (fitCursor()) - updateMetrics(false); - buffer_->text().setCurrentFont(cursor_); - } - } - - if (tolastfiles) - LyX::ref().session().lastFiles().add(FileName(b->fileName())); - - return true; + return b; } Index: src/BufferView.h =================================================================== --- src/BufferView.h (revision 18803) +++ src/BufferView.h (working copy) @@ -94,7 +94,8 @@ void resize(); /// load a buffer into the view. - bool loadLyXFile(support::FileName const & name, bool tolastfiles = true); + /// returns the buffer or 0 if not loaded + Buffer * loadLyXFile(support::FileName const & name, bool auto_open = false); /// perform pending metrics updates. /** \c Update::FitCursor means first to do a FitCursor, and to Index: src/LyX.cpp =================================================================== --- src/LyX.cpp (revision 18803) +++ src/LyX.cpp (working copy) @@ -613,7 +613,7 @@ if (!pimpl_->files_to_load_.empty()) { for_each(pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(), - bind(&LyXView::loadLyXFile, view, _1, true)); + bind(&LyXView::loadLyXFile, view, _1, true, false, false)); // clear this list to save a few bytes of RAM pimpl_->files_to_load_.clear(); pimpl_->session_->lastOpened().clear(); @@ -628,7 +628,7 @@ // last session, and should be already there (regular files), or should // not be added at all (help files). for_each(lastopened.begin(), lastopened.end(), - bind(&LyXView::loadLyXFile, view, _1, false)); + bind(&LyXView::loadLyXFile, view, _1, false, false, false)); // clear this list to save a few bytes of RAM pimpl_->session_->lastOpened().clear(); Index: src/LyXFunc.cpp =================================================================== --- src/LyXFunc.cpp (revision 18803) +++ src/LyXFunc.cpp (working copy) @@ -1410,24 +1410,35 @@ } case LFUN_BUFFER_CHILD_OPEN: { + // takes an optional argument, "|bool", at the end + // indicating whether this file is being opened automatically + // by LyX itself, in which case we will not want to switch + // buffers after opening. The default is false, so in practice + // it is used only when true. BOOST_ASSERT(lyx_view_); - FileName const filename = - makeAbsPath(argument, lyx_view_->buffer()->filePath()); + int const arglength = argument.length(); + FileName filename; + bool autoOpen = false; + if (argument.substr(arglength - 5, 5) == "|true") { + autoOpen = true; + filename = makeAbsPath(argument.substr(0, arglength - 5), + lyx_view_->buffer()->filePath()); + } else if (argument.substr(arglength - 6, 6) == "|false") { + filename = makeAbsPath(argument.substr(0, arglength - 6), + lyx_view_->buffer()->filePath()); + } else filename = + makeAbsPath(argument, lyx_view_->buffer()->filePath()); view()->saveBookmark(false); - string const parentfilename = lyx_view_->buffer()->fileName(); - if (theBufferList().exists(filename.absFilename())) - lyx_view_->setBuffer(theBufferList().getBuffer(filename.absFilename())); - else - if (lyx_view_->loadLyXFile(filename)) { - // Set the parent name of the child document. - // This makes insertion of citations and references in the child work, - // when the target is in the parent or another child document. - lyx_view_->buffer()->setParentName(parentfilename); - setMessage(bformat(_("Opening child document %1$s..."), - makeDisplayPath(filename.absFilename()))); - } else - setMessage(_("Document not loaded.")); - break; + if (theBufferList().exists(filename.absFilename())) { + Buffer * buf = theBufferList().getBuffer(filename.absFilename()); + if (!autoOpen) + lyx_view_->setBuffer(buf, true); + else + buf->setParentName(lyx_view_->buffer()->fileName()); + } else + lyx_view_->loadLyXFile(filename, true, true, autoOpen); + + break; } case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR: Index: src/frontends/LyXView.cpp =================================================================== --- src/frontends/LyXView.cpp (revision 18803) +++ src/frontends/LyXView.cpp (working copy) @@ -20,6 +20,7 @@ #include "Gui.h" #include "Buffer.h" +#include "buffer_funcs.h" #include "BufferList.h" #include "BufferParams.h" #include "BufferView.h" @@ -31,6 +32,7 @@ #include "gettext.h" #include "Intl.h" #include "callback.h" +#include "LyX.h" #include "LyXFunc.h" #include "LyXRC.h" #include "Text.h" @@ -122,27 +124,44 @@ } -void LyXView::setBuffer(Buffer * b) +void LyXView::setBuffer(Buffer * b, bool child_document) { busy(true); BOOST_ASSERT(work_area_); - if (work_area_->bufferView().buffer()) + Buffer * oldBuffer = work_area_->bufferView().buffer(); + // parentfilename will be used in case when we switch to a child + // document (hence when child_document is true) + string parentfilename; + if (oldBuffer) { + parentfilename = oldBuffer->fileName(); disconnectBuffer(); + } if (!b && theBufferList().empty()) getDialogs().hideBufferDependent(); work_area_->bufferView().setBuffer(b); - // Make sure the TOC is updated before anything else. - updateToc(); - if (work_area_->bufferView().buffer()) { + Buffer * newBuffer = work_area_->bufferView().buffer(); + if (newBuffer) { + if (child_document && newBuffer != oldBuffer) { + // Set the parent name of the child document. + // This makes insertion of citations and references in the child work, + // when the target is in the parent or another child document. + newBuffer->setParentName(parentfilename); + // updateLabels() will emit Buffer::structureChanged() so better + // connect it before. + connectBuffer(*newBuffer); + // Update the labels and section numbering. + updateLabels(*newBuffer->getMasterBuffer()); + } else + connectBuffer(*newBuffer); + // Buffer-dependent dialogs should be updated or // hidden. This should go here because some dialogs (eg ToC) // require bv_->text. getDialogs().updateBufferDependent(true); - connectBuffer(*work_area_->bufferView().buffer()); } if (quitting) @@ -159,34 +178,82 @@ } -bool LyXView::loadLyXFile(FileName const & filename, bool tolastfiles) +bool LyXView::loadLyXFile(FileName const & filename, bool tolastfiles, + bool child_document, bool auto_open) { busy(true); BOOST_ASSERT(work_area_); - bool const hadBuffer = work_area_->bufferView().buffer(); - if (hadBuffer) - disconnectBuffer(); + string parentfilename; + Buffer * oldBuffer = work_area_->bufferView().buffer(); + if (oldBuffer) + parentfilename = oldBuffer->fileName(); - bool const loaded = - work_area_->bufferView().loadLyXFile(filename, tolastfiles); + Buffer * newBuffer = + work_area_->bufferView().loadLyXFile(filename, auto_open); - updateToc(); + if (!newBuffer) { + message(_("Document not loaded.")); + updateStatusBar(); + busy(false); + work_area_->redraw(); + return false; + } + + if (!auto_open) { + disconnectBuffer(); + connectBuffer(*newBuffer); + } + + showErrorList("Parse"); + + if (child_document && newBuffer != oldBuffer) { + // Set the parent name of the child document. + // This makes insertion of citations and references in the child work, + // when the target is in the parent or another child document. + newBuffer->setParentName(parentfilename); + message(bformat(_("Opening child document %1$s..."), + makeDisplayPath(filename.absFilename()))); + } + + // Update the labels and section numbering. + updateLabels(*newBuffer->getMasterBuffer()); + + // scroll to the position when the file was last closed + if (!auto_open && lyxrc.use_lastfilepos) { + pit_type pit; + pos_type pos; + boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename); + // if successfully move to pit (returned par_id is not zero), + // update metrics and reset font + if (work_area_->bufferView().moveToPosition(pit, pos, 0, 0).get<1>()) { + if (work_area_->bufferView().fitCursor()) + work_area_->bufferView().updateMetrics(false); + newBuffer->text().setCurrentFont(work_area_->bufferView().cursor()); + } + } + + if (tolastfiles) + LyX::ref().session().lastFiles().add(filename); + + // FIXME We definitely don't have to do all of this if auto_open... + // The question is: What do we have to do here if we've loaded a new + // file but haven't switched buffers? I'm guessing we can skip the + // layout big and the title. + // and if we have already switched buffers...won't all of this have been + // done already in setBuffer()? So why does it also need doing here? + // In fact, won't a lot of what's above already have been done? E.g., + // the connecting and disconnecting of buffers will have been done + // already in setBuffer(). updateMenubar(); updateToolbars(); updateLayoutChoice(); updateWindowTitle(); updateTab(); - if (loaded) { - connectBuffer(*work_area_->bufferView().buffer()); - showErrorList("Parse"); - } else if (hadBuffer) - //Need to reconnect the buffer if the load failed - connectBuffer(*work_area_->bufferView().buffer()); updateStatusBar(); busy(false); work_area_->redraw(); - return loaded; + return true; } @@ -230,7 +297,7 @@ closingConnection_ = buf.closing.connect( - boost::bind(&LyXView::setBuffer, this, (Buffer *)0)); + boost::bind(&LyXView::setBuffer, this, (Buffer *)0, false)); } Index: src/frontends/LyXView.h =================================================================== --- src/frontends/LyXView.h (revision 18803) +++ src/frontends/LyXView.h (working copy) @@ -142,11 +142,15 @@ //@} - /// load a buffer into the current workarea - bool loadLyXFile(support::FileName const & name, bool tolastfiles = true); + /// load a buffer into the current workarea. + bool loadLyXFile(support::FileName const & name, ///< File to load. + bool tolastfiles = true, ///< append to the "Open recent" menu? + bool child_document = false, ///< Is this a child document? + bool auto_open = false); ///< Is this being opened by LyX itself? - /// set a buffer to the current workarea - void setBuffer(Buffer * b); + /// set a buffer to the current workarea. + void setBuffer(Buffer * b, ///< \c Buffer to set. + bool child_document = false); ///< Is this a child document? /// updates the possible layouts selectable void updateLayoutChoice(); Index: src/insets/InsetInclude.cpp =================================================================== --- src/insets/InsetInclude.cpp (revision 18803) +++ src/insets/InsetInclude.cpp (working copy) @@ -52,6 +52,9 @@ namespace lyx { + +// Implementation is in LyX.cpp +extern void dispatch(FuncRequest const & action); using support::addName; using support::absolutePath; @@ -400,12 +403,10 @@ // the readonly flag can/will be wrong, not anymore I think. if (!fs::exists(included_file.toFilesystemEncoding())) return false; - buf = theBufferList().newBuffer(included_file.absFilename()); - if (!loadLyXFile(buf, included_file)) { - //close the buffer we just opened - theBufferList().close(buf, false); - return false; - } + lyx::dispatch(FuncRequest(LFUN_BUFFER_CHILD_OPEN, + included_file.absFilename() + "|true")); + buf = theBufferList().getBuffer(included_file.absFilename()); + return buf; } buf->setParentName(parentFilename(buffer)); return true;