From 1356543c457436fc8130b9c147bd403b7a82c7e9 Mon Sep 17 00:00:00 2001 From: Abdelrazak Younes Date: Tue, 21 Aug 2007 07:33:46 +0000 Subject: [PATCH] The BufferView/WorkArea/LyXView reorg a.k.a Multiple WorkAreas: * Buffer: - get rid of cursor_ and anchor_ - ~Buffer(): update the labels of its master buffer before closing - closing(): pass the Buffer address. * BufferView(): - BufferView(): needs a valid Buffer (should be const in the future. - most of the change is about removing all test of buffer_ nullity. - resize(): deleted. - setBuffer(): deleted. * Application: - newLyXView(): simplification - updated design description in Application.h * Gui/GuiImplementation: remove all WorkAreas and BufferView creation/Deletion. Workareas are directly handled by LyXView/GuiView and BufferView is created/delete by WorkArea. * LyXView/GuiView: implement the new design What is not working yet: - the close tab button: it is implemented but does not show up. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19686 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/Buffer.cpp | 17 +- src/Buffer.h | 15 +- src/BufferView.cpp | 308 ++++++------------- src/BufferView.h | 16 +- src/Importer.cpp | 10 +- src/LyX.cpp | 42 ++- src/LyXAction.cpp | 2 +- src/LyXFunc.cpp | 130 +++++--- src/frontends/Application.cpp | 5 +- src/frontends/Application.h | 90 ++++-- src/frontends/Gui.h | 5 - src/frontends/LyXView.cpp | 258 ++++++---------- src/frontends/LyXView.h | 70 ++--- src/frontends/WorkArea.cpp | 141 +++++---- src/frontends/WorkArea.h | 37 +-- src/frontends/qt4/GuiApplication.cpp | 5 + src/frontends/qt4/GuiImplementation.cpp | 55 +--- src/frontends/qt4/GuiImplementation.h | 20 -- src/frontends/qt4/GuiView.cpp | 381 +++++++++++++++--------- src/frontends/qt4/GuiView.h | 17 +- src/frontends/qt4/GuiWorkArea.cpp | 76 +---- src/frontends/qt4/GuiWorkArea.h | 3 +- src/insets/InsetInclude.cpp | 41 ++- 23 files changed, 773 insertions(+), 971 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index f9d11689bb..5f73e27f6b 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -22,6 +22,7 @@ #include "Bullet.h" #include "Chktex.h" #include "debug.h" +#include "DocIterator.h" #include "Encoding.h" #include "ErrorList.h" #include "Exporter.h" @@ -227,7 +228,12 @@ Buffer::~Buffer() // here the buffer should take care that it is // saved properly, before it goes into the void. - closing(); + Buffer * master = getMasterBuffer(); + if (master != this && use_gui) + // We are closing buf which was a child document so we + // must update the labels and section numbering of its master + // Buffer. + updateLabels(*master); if (!temppath().empty() && !destroyDir(FileName(temppath()))) { Alert::warning(_("Could not remove temporary directory"), @@ -237,6 +243,8 @@ Buffer::~Buffer() // Remove any previewed LaTeX snippets associated with this buffer. graphics::Previews::get().removeLoader(*this); + + closing(this); } @@ -1707,13 +1715,6 @@ void Buffer::buildMacros() } -void Buffer::saveCursor(StableDocIterator cur, StableDocIterator anc) -{ - cursor_ = cur; - anchor_ = anc; -} - - void Buffer::changeRefsIfUnique(docstring const & from, docstring const & to, Inset::Code code) { diff --git a/src/Buffer.h b/src/Buffer.h index 7db748fb1e..450622043e 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -50,7 +49,6 @@ class OutputParams; class ParConstIterator; class ParIterator; class ParagraphList; -class StableDocIterator; class TeXErrors; class TexRow; class TocBackend; @@ -159,7 +157,7 @@ public: /// Reset autosave timers for all users. boost::signal resetAutosaveTimers; /// This signal is emitting if the buffer is being closed. - boost::signal closing; + boost::signal closing; /** Save file. @@ -381,12 +379,6 @@ public: /// void insertMacro(docstring const & name, MacroData const & data); - /// - void saveCursor(StableDocIterator cursor, StableDocIterator anchor); - /// - StableDocIterator getCursor() const { return cursor_; } - /// - StableDocIterator getAnchor() const { return anchor_; } /// void changeRefsIfUnique(docstring const & from, docstring const & to, Inset::Code code); @@ -417,11 +409,6 @@ private: /// The pointer never changes although *pimpl_'s contents may. boost::scoped_ptr const pimpl_; - /// Save the cursor Position on Buffer switch - /// this would not be needed if every Buffer would have - /// it's BufferView, this should be FIXED in future. - StableDocIterator cursor_; - StableDocIterator anchor_; /// A cache for the bibfiles (including bibfiles of loaded child /// documents), needed for appropriate update of natbib labels. mutable std::vector bibfilesCache_; diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 5ee6410efc..75566e54e0 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -122,140 +122,38 @@ T * getInsetByCode(Cursor & cur, Inset::Code code) } // anon namespace -BufferView::BufferView() - : width_(0), height_(0), buffer_(0), wh_(0), +BufferView::BufferView(Buffer & buf) + : width_(0), height_(0), buffer_(buf), wh_(0), cursor_(*this), multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0), intl_(new Intl), last_inset_(0) { xsel_cache_.set = false; intl_->initKeyMapper(lyxrc.use_kbmap); -} + cursor_.push(buffer_.inset()); + cursor_.resetAnchor(); + buffer_.text().setCurrentFont(cursor_); -BufferView::~BufferView() -{ + if (graphics::Previews::status() != LyXRC::PREVIEW_OFF) + graphics::Previews::get().generateBufferPreviews(buffer_); } -Buffer * BufferView::buffer() const +BufferView::~BufferView() { - return buffer_; } -Buffer * BufferView::setBuffer(Buffer * b) +Buffer * BufferView::buffer() { - LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION - << "[ b = " << b << "]" << endl; - - if (buffer_) { - // Save the current selection if any - cap::saveSelection(cursor_); - // Save the actual cursor position and anchor inside the - // buffer so that it can be restored in case we rechange - // to this buffer later on. - buffer_->saveCursor(cursor_.selectionBegin(), - cursor_.selectionEnd()); - // update bookmark pit of the current buffer before switch - for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i) { - BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(i); - if (buffer()->fileName() != bm.filename.absFilename()) - continue; - // if top_id or bottom_pit, bottom_pos has been changed, update bookmark - // see http://bugzilla.lyx.org/show_bug.cgi?id=3092 - pit_type new_pit; - pos_type new_pos; - int new_id; - boost::tie(new_pit, new_pos, new_id) = moveToPosition(bm.bottom_pit, bm.bottom_pos, bm.top_id, bm.top_pos); - if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos || bm.top_id != new_id ) - const_cast(bm).updatePos(new_pit, new_pos, new_id); - } - // current buffer is going to be switched-off, save cursor pos - // Ideally, the whole cursor stack should be saved, but session - // currently can only handle bottom (whole document) level pit and pos. - // That is to say, if a cursor is in a nested inset, it will be - // restore to the left of the top level inset. - LyX::ref().session().lastFilePos().save(FileName(buffer_->fileName()), - boost::tie(cursor_.bottom().pit(), cursor_.bottom().pos()) ); - } - - // If we're quitting lyx, don't bother updating stuff - if (quitting) { - buffer_ = 0; - return 0; - } - - //FIXME Fix for bug 3440 is here. - // If we are closing current buffer, switch to the first in - // buffer list. - if (!b) { - LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION - << " No Buffer!" << endl; - // We are closing the buffer, use the first buffer as current - //FIXME 3440 - // if (last_buffer_) buffer_ = last_buffer_; - // also check that this is in theBufferList()? - buffer_ = theBufferList().first(); - } else { - //FIXME 3440 - // last_buffer = buffer_; - // Set current buffer - buffer_ = b; - } - - // Reset old cursor - cursor_ = Cursor(*this); - anchor_ref_ = 0; - offset_ref_ = 0; - - if (!buffer_) - return 0; - - LYXERR(Debug::INFO) << BOOST_CURRENT_FUNCTION - << "Buffer addr: " << buffer_ << endl; - cursor_.push(buffer_->inset()); - cursor_.resetAnchor(); - buffer_->text().setCurrentFont(cursor_); - - // Update the metrics now that we have a proper Cursor. - updateMetrics(false); - - // FIXME: This code won't be needed once we switch to - // "one Buffer" / "one BufferView". - if (buffer_->getCursor().size() > 0 && - buffer_->getAnchor().size() > 0) - { - cursor_.setCursor(buffer_->getAnchor().asDocIterator(&(buffer_->inset()))); - cursor_.resetAnchor(); - cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset()))); - cursor_.setSelection(); - // do not set selection to the new buffer because we - // only paste recent selection. - - // Make sure that the restored cursor is not broken. This can happen for - // example if this Buffer has been modified by another view. - cursor_.fixIfBroken(); - - if (fitCursor()) - // Update the metrics if the cursor new position was off screen. - updateMetrics(false); - } - - if (graphics::Previews::status() != LyXRC::PREVIEW_OFF) - graphics::Previews::get().generateBufferPreviews(*buffer_); - return buffer_; + return &buffer_; } -void BufferView::resize() +Buffer const * BufferView::buffer() const { - if (!buffer_) - return; - - LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION << endl; - - updateMetrics(false); + return &buffer_; } @@ -298,17 +196,11 @@ bool BufferView::update(Update::flags flags) << "[fitcursor = " << (flags & Update::FitCursor) << ", forceupdate = " << (flags & Update::Force) << ", singlepar = " << (flags & Update::SinglePar) - << "] buffer: " << buffer_ << endl; - - // Check needed to survive LyX startup - if (!buffer_) - return false; - - LYXERR(Debug::WORKAREA) << "BufferView::update" << std::endl; + << "] buffer: " << &buffer_ << endl; // Update macro store if (!(cursor().inMathed() && cursor().inMacroMode())) - buffer_->buildMacros(); + buffer_.buildMacros(); // Now do the first drawing step if needed. This consists on updating // the CoordCache in updateMetrics(). @@ -360,14 +252,7 @@ bool BufferView::update(Update::flags flags) void BufferView::updateScrollbar() { - if (!buffer_) { - LYXERR(Debug::DEBUG) << BOOST_CURRENT_FUNCTION - << " no text in updateScrollbar" << endl; - scrollbarParameters_.reset(); - return; - } - - Text & t = buffer_->text(); + Text & t = buffer_.text(); TextMetrics & tm = text_metrics_[&t]; int const parsize = int(t.paragraphs().size() - 1); @@ -432,10 +317,7 @@ void BufferView::scrollDocView(int value) LYXERR(Debug::GUI) << BOOST_CURRENT_FUNCTION << "[ value = " << value << "]" << endl; - if (!buffer_) - return; - - Text & t = buffer_->text(); + Text & t = buffer_.text(); TextMetrics & tm = text_metrics_[&t]; float const bar = value / float(wh_ * t.paragraphs().size()); @@ -453,10 +335,7 @@ void BufferView::scrollDocView(int value) void BufferView::setCursorFromScrollbar() { - if (!buffer_) - return; - - Text & t = buffer_->text(); + Text & t = buffer_.text(); int const height = 2 * defaultRowHeight(); int const first = height; @@ -469,14 +348,14 @@ void BufferView::setCursorFromScrollbar() case bv_funcs::CUR_ABOVE: // We reset the cursor because bv_funcs::status() does not // work when the cursor is within mathed. - cur.reset(buffer_->inset()); + cur.reset(buffer_.inset()); t.setCursorFromCoordinates(cur, 0, first); cur.clearSelection(); break; case bv_funcs::CUR_BELOW: // We reset the cursor because bv_funcs::status() does not // work when the cursor is within mathed. - cur.reset(buffer_->inset()); + cur.reset(buffer_.inset()); t.setCursorFromCoordinates(cur, 0, last); cur.clearSelection(); break; @@ -484,7 +363,7 @@ void BufferView::setCursorFromScrollbar() int const y = bv_funcs::getPos(*this, cur, cur.boundary()).y_; int const newy = min(last, max(y, first)); if (y != newy) { - cur.reset(buffer_->inset()); + cur.reset(buffer_.inset()); t.setCursorFromCoordinates(cur, 0, newy); } } @@ -508,7 +387,7 @@ void BufferView::saveBookmark(unsigned int idx) // pit and pos will be updated with bottom level pit/pos // when lyx exits. LyX::ref().session().bookmarks().save( - FileName(buffer_->fileName()), + FileName(buffer_.fileName()), cursor_.bottom().pit(), cursor_.bottom().pos(), cursor_.paragraph().id(), @@ -530,8 +409,8 @@ boost::tuple BufferView::moveToPosition(pit_type bottom // This is the case for a 'live' bookmark when unique paragraph ID // is used to track bookmarks. if (top_id > 0) { - ParIterator par = buffer_->getParFromID(top_id); - if (par != buffer_->par_iterator_end()) { + ParIterator par = buffer_.getParFromID(top_id); + if (par != buffer_.par_iterator_end()) { DocIterator dit = makeDocIterator(par, min(par->size(), top_pos)); // Some slices of the iterator may not be // reachable (e.g. closed collapsable inset) @@ -556,8 +435,8 @@ boost::tuple BufferView::moveToPosition(pit_type bottom // restoration is inaccurate. If a bookmark was within an inset, // it will be restored to the left of the outmost inset that contains // the bookmark. - if (static_cast(bottom_pit) < buffer_->paragraphs().size()) { - DocIterator it = doc_iterator_begin(buffer_->inset()); + if (static_cast(bottom_pit) < buffer_.paragraphs().size()) { + DocIterator it = doc_iterator_begin(buffer_.inset()); it.pit() = bottom_pit; it.pos() = min(bottom_pos, it.paragraph().size()); setCursor(it); @@ -613,10 +492,10 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) switch (cmd.action) { case LFUN_UNDO: - flag.enabled(!buffer_->undostack().empty()); + flag.enabled(!buffer_.undostack().empty()); break; case LFUN_REDO: - flag.enabled(!buffer_->redostack().empty()); + flag.enabled(!buffer_.redostack().empty()); break; case LFUN_FILE_INSERT: case LFUN_FILE_INSERT_PLAINTEXT_PARA: @@ -656,12 +535,12 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_CHANGES_TRACK: flag.enabled(true); - flag.setOnOff(buffer_->params().trackChanges); + flag.setOnOff(buffer_.params().trackChanges); break; case LFUN_CHANGES_OUTPUT: - flag.enabled(buffer_); - flag.setOnOff(buffer_->params().outputChanges); + flag.enabled(true); + flag.setOnOff(buffer_.params().outputChanges); break; case LFUN_CHANGES_MERGE: @@ -672,11 +551,11 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) // In principle, these command should only be enabled if there // is a change in the document. However, without proper // optimizations, this will inevitably result in poor performance. - flag.enabled(buffer_); + flag.enabled(true); break; case LFUN_BUFFER_TOGGLE_COMPRESSION: { - flag.setOnOff(buffer_->params().compressed); + flag.setOnOff(buffer_.params().compressed); break; } @@ -702,10 +581,6 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) << " button[" << cmd.button() << ']' << endl; - // FIXME: this should not be possible. - if (!buffer_) - return Update::None; - Cursor & cur = cursor_; // Default Update flags. Update::flags updateFlags = Update::Force | Update::FitCursor; @@ -774,7 +649,9 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) case LFUN_PARAGRAPH_GOTO: { int const id = convert(to_utf8(cmd.argument())); int i = 0; - for (Buffer * b = buffer_; i == 0 || b != buffer_; b = theBufferList().next(b)) { + for (Buffer * b = &buffer_; i == 0 || b != &buffer_; + b = theBufferList().next(b)) { + ParIterator par = b->getParFromID(id); if (par == b->par_iterator_end()) { LYXERR(Debug::INFO) @@ -786,7 +663,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) << " found in buffer `" << b->fileName() << "'." << endl; - if (b == buffer_) { + if (b == &buffer_) { // Set the cursor setCursor(makeDocIterator(par, 0)); } else { @@ -806,20 +683,20 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) case LFUN_OUTLINE_UP: toc::outline(toc::Up, cursor_); cursor_.text()->setCursor(cursor_, cursor_.pit(), 0); - updateLabels(*buffer_); + updateLabels(buffer_); break; case LFUN_OUTLINE_DOWN: toc::outline(toc::Down, cursor_); cursor_.text()->setCursor(cursor_, cursor_.pit(), 0); - updateLabels(*buffer_); + updateLabels(buffer_); break; case LFUN_OUTLINE_IN: toc::outline(toc::In, cursor_); - updateLabels(*buffer_); + updateLabels(buffer_); break; case LFUN_OUTLINE_OUT: toc::outline(toc::Out, cursor_); - updateLabels(*buffer_); + updateLabels(buffer_); break; case LFUN_NOTE_NEXT: @@ -835,12 +712,12 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) } case LFUN_CHANGES_TRACK: - buffer_->params().trackChanges = !buffer_->params().trackChanges; + buffer_.params().trackChanges = !buffer_.params().trackChanges; break; case LFUN_CHANGES_OUTPUT: - buffer_->params().outputChanges = !buffer_->params().outputChanges; - if (buffer_->params().outputChanges) { + buffer_.params().outputChanges = !buffer_.params().outputChanges; + if (buffer_.params().outputChanges) { bool dvipost = LaTeXFeatures::isAvailable("dvipost"); bool xcolorsoul = LaTeXFeatures::isAvailable("soul") && LaTeXFeatures::isAvailable("xcolor"); @@ -872,21 +749,21 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) case LFUN_ALL_CHANGES_ACCEPT: // select complete document - cursor_.reset(buffer_->inset()); + cursor_.reset(buffer_.inset()); cursor_.selHandle(true); - buffer_->text().cursorBottom(cursor_); + buffer_.text().cursorBottom(cursor_); // accept everything in a single step to support atomic undo - buffer_->text().acceptOrRejectChanges(cursor_, Text::ACCEPT); + buffer_.text().acceptOrRejectChanges(cursor_, Text::ACCEPT); break; case LFUN_ALL_CHANGES_REJECT: // select complete document - cursor_.reset(buffer_->inset()); + cursor_.reset(buffer_.inset()); cursor_.selHandle(true); - buffer_->text().cursorBottom(cursor_); + buffer_.text().cursorBottom(cursor_); // reject everything in a single step to support atomic undo // Note: reject does not work recursively; the user may have to repeat the operation - buffer_->text().acceptOrRejectChanges(cursor_, Text::REJECT); + buffer_.text().acceptOrRejectChanges(cursor_, Text::REJECT); break; case LFUN_WORD_FIND: @@ -945,7 +822,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) Inset::BIBTEX_CODE); if (inset) { if (inset->addDatabase(to_utf8(cmd.argument()))) - buffer_->updateBibfilesCache(); + buffer_.updateBibfilesCache(); } break; } @@ -957,7 +834,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) Inset::BIBTEX_CODE); if (inset) { if (inset->delDatabase(to_utf8(cmd.argument()))) - buffer_->updateBibfilesCache(); + buffer_.updateBibfilesCache(); } break; } @@ -968,8 +845,8 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) from = cur.selectionBegin(); to = cur.selectionEnd(); } else { - from = doc_iterator_begin(buffer_->inset()); - to = doc_iterator_end(buffer_->inset()); + from = doc_iterator_begin(buffer_.inset()); + to = doc_iterator_end(buffer_.inset()); } int const count = countWords(from, to); docstring message; @@ -994,7 +871,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) case LFUN_BUFFER_TOGGLE_COMPRESSION: // turn compression on/off - buffer_->params().compressed = !buffer_->params().compressed; + buffer_.params().compressed = !buffer_.params().compressed; break; case LFUN_NEXT_INSET_TOGGLE: { @@ -1031,9 +908,6 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) docstring const BufferView::requestSelection() { - if (!buffer_) - return docstring(); - Cursor & cur = cursor_; if (!cur.selection()) { @@ -1056,17 +930,15 @@ docstring const BufferView::requestSelection() void BufferView::clearSelection() { - if (buffer_) { - cursor_.clearSelection(); - // Clear the selection buffer. Otherwise a subsequent - // middle-mouse-button paste would use the selection buffer, - // not the more current external selection. - cap::clearSelection(); - xsel_cache_.set = false; - // The buffer did not really change, but this causes the - // redraw we need because we cleared the selection above. - buffer_->changed(); - } + cursor_.clearSelection(); + // Clear the selection buffer. Otherwise a subsequent + // middle-mouse-button paste would use the selection buffer, + // not the more current external selection. + cap::clearSelection(); + xsel_cache_.set = false; + // The buffer did not really change, but this causes the + // redraw we need because we cleared the selection above. + buffer_.changed(); } @@ -1078,9 +950,7 @@ void BufferView::workAreaResize(int width, int height) // The complete text metrics will be redone. text_metrics_.clear(); - - if (buffer_) - resize(); + updateMetrics(false); } @@ -1140,12 +1010,8 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) // LFUN_FILE_OPEN generated by drag-and-drop. FuncRequest cmd = cmd0; - // E.g. Qt mouse press when no buffer - if (!buffer_) - return false; - Cursor cur(*this); - cur.push(buffer_->inset()); + cur.push(buffer_.inset()); cur.selection() = cursor_.selection(); // Either the inset under the cursor or the @@ -1158,7 +1024,7 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) // Get inset under mouse, if there is one. Inset const * covering_inset = - getCoveringInset(buffer_->text(), cmd.x, cmd.y); + getCoveringInset(buffer_.text(), cmd.x, cmd.y); if (covering_inset == last_inset_) // Same inset, no need to do anything... return false; @@ -1208,7 +1074,7 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) } // Build temporary cursor. - Inset * inset = buffer_->text().editXY(cur, cmd.x, cmd.y); + Inset * inset = buffer_.text().editXY(cur, cmd.x, cmd.y); // Put anchor at the same position. cur.resetAnchor(); @@ -1239,10 +1105,7 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) void BufferView::scroll(int /*lines*/) { -// if (!buffer_) -// return; -// -// Text const * t = &buffer_->text(); +// Text const * t = buffer_.text(); // int const line_height = defaultRowHeight(); // // // The new absolute coordinate @@ -1262,21 +1125,21 @@ void BufferView::setCursorFromRow(int row) int tmpid = -1; int tmppos = -1; - buffer_->texrow().getIdFromRow(row, tmpid, tmppos); + buffer_.texrow().getIdFromRow(row, tmpid, tmppos); - cursor_.reset(buffer_->inset()); + cursor_.reset(buffer_.inset()); if (tmpid == -1) - buffer_->text().setCursor(cursor_, 0, 0); + buffer_.text().setCursor(cursor_, 0, 0); else - buffer_->text().setCursor(cursor_, buffer_->getParFromID(tmpid).pit(), tmppos); + buffer_.text().setCursor(cursor_, buffer_.getParFromID(tmpid).pit(), tmppos); } void BufferView::gotoLabel(docstring const & label) { - for (InsetIterator it = inset_iterator_begin(buffer_->inset()); it; ++it) { + for (InsetIterator it = inset_iterator_begin(buffer_.inset()); it; ++it) { vector labels; - it->getLabelList(*buffer_, labels); + it->getLabelList(buffer_, labels); if (std::find(labels.begin(), labels.end(), label) != labels.end()) { setCursor(it); update(); @@ -1343,10 +1206,10 @@ bool BufferView::checkDepm(Cursor & cur, Cursor & old) if (!changed) return false; - updateLabels(*buffer_); + updateLabels(buffer_); updateMetrics(false); - buffer_->changed(); + buffer_.changed(); return true; } @@ -1442,7 +1305,7 @@ ViewMetricsInfo const & BufferView::viewMetricsInfo() // FIXME: We should split-up updateMetrics() for the singlepar case. void BufferView::updateMetrics(bool singlepar) { - Text & buftext = buffer_->text(); + Text & buftext = buffer_.text(); TextMetrics & tm = textMetrics(&buftext); pit_type size = int(buftext.paragraphs().size()); @@ -1571,13 +1434,10 @@ void BufferView::menuInsertLyXFile(string const & filenm) // Launch a file browser // FIXME UNICODE string initpath = lyxrc.document_path; - - if (buffer_) { - string const trypath = buffer_->filePath(); - // If directory is writeable, use this as default. - if (isDirWriteable(FileName(trypath))) - initpath = trypath; - } + string const trypath = buffer_.filePath(); + // If directory is writeable, use this as default. + if (isDirWriteable(FileName(trypath))) + initpath = trypath; // FIXME UNICODE FileDialog fileDlg(_("Select LyX document to insert"), @@ -1617,7 +1477,7 @@ void BufferView::menuInsertLyXFile(string const & filenm) docstring res; Buffer buf("", false); if (lyx::loadLyXFile(&buf, FileName(filename))) { - ErrorList & el = buffer_->errorList("Parse"); + ErrorList & el = buffer_.errorList("Parse"); // Copy the inserted document error list into the current buffer one. el = buf.errorList("Parse"); recordUndo(cursor_); @@ -1629,8 +1489,8 @@ void BufferView::menuInsertLyXFile(string const & filenm) // emit message signal. message(bformat(res, disp_fn)); - buffer_->errors("Parse"); - resize(); + buffer_.errors("Parse"); + updateMetrics(false); } } // namespace lyx diff --git a/src/BufferView.h b/src/BufferView.h index 93a4ae9be4..ea51376a78 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -79,20 +79,14 @@ struct ScrollbarParameters */ class BufferView : boost::noncopyable { public: - BufferView(); + /// + BufferView(Buffer & buffer); ~BufferView(); - /// set the buffer we are viewing. - /// \todo FIXME: eventually, we will create a new BufferView - /// when switching Buffers, so this method should go. - /// returns the buffer currently set - Buffer * setBuffer(Buffer * b); /// return the buffer being viewed. - Buffer * buffer() const; - - /// resize the BufferView. - void resize(); + Buffer * buffer(); + Buffer const * buffer() const; /// perform pending metrics updates. /** \c Update::FitCursor means first to do a FitCursor, and to @@ -269,7 +263,7 @@ private: /// CoordCache coord_cache_; /// - Buffer * buffer_; + Buffer & buffer_; /// Estimated average par height for scrollbar. int wh_; diff --git a/src/Importer.cpp b/src/Importer.cpp index ad609e47c1..6f38b20298 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -77,7 +77,15 @@ bool Importer::Import(LyXView * lv, FileName const & filename, if (loader_format == "lyx") { - lv->loadLyXFile(lyxfile); + Buffer * buf = lv->loadLyXFile(lyxfile); + if (!buf) { + // we are done + lv->message(_("file not imported!")); + return false; + } + updateLabels(*buf); + lv->setBuffer(buf); + lv->showErrorList("Parse"); } else { Buffer * const b = newFile(lyxfile.absFilename(), string(), true); if (b) diff --git a/src/LyX.cpp b/src/LyX.cpp index e93cfe6494..9acbceb541 100644 --- a/src/LyX.cpp +++ b/src/LyX.cpp @@ -435,11 +435,12 @@ int LyX::exec(int & argc, char * argv[]) } BufferList::iterator begin = pimpl_->buffer_list_.begin(); - BufferList::iterator end = pimpl_->buffer_list_.end(); bool final_success = false; - for (BufferList::iterator I = begin; I != end; ++I) { + for (BufferList::iterator I = begin; I != pimpl_->buffer_list_.end(); ++I) { Buffer * buf = *I; + if (buf != buf->getMasterBuffer()) + continue; bool success = false; buf->dispatch(batch_command, &success); final_success |= success; @@ -634,25 +635,36 @@ void LyX::restoreGuiSession() if (!pimpl_->files_to_load_.empty()) { for_each(pimpl_->files_to_load_.begin(), pimpl_->files_to_load_.end(), - bind(&LyXView::loadLyXFile, view, _1, true, false, false)); + bind(&LyXView::loadLyXFile, view, _1, true)); // clear this list to save a few bytes of RAM pimpl_->files_to_load_.clear(); pimpl_->session_->lastOpened().clear(); - return; - } - if (!lyxrc.load_session) - return; + } else if (lyxrc.load_session) { + vector const & lastopened = pimpl_->session_->lastOpened().getfiles(); + // do not add to the lastfile list since these files are restored from + // 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)); - vector const & lastopened = pimpl_->session_->lastOpened().getfiles(); - // do not add to the lastfile list since these files are restored from - // 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, false, false)); + // clear this list to save a few bytes of RAM + pimpl_->session_->lastOpened().clear(); + } + + BufferList::iterator I = pimpl_->buffer_list_.begin(); + BufferList::iterator end = pimpl_->buffer_list_.end(); + for (; I != end; ++I) { + Buffer * buf = *I; + if (buf != buf->getMasterBuffer()) + continue; + updateLabels(*buf); + } - // clear this list to save a few bytes of RAM - pimpl_->session_->lastOpened().clear(); + // FIXME: Switch to the last loaded Buffer. This must not be the first one + // because the Buffer won't be connected in this case. The correct solution + // would be to avoid the manual connection of the current Buffer in LyXView. + view->setBuffer(pimpl_->buffer_list_.last()); } diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index e228d7edd6..8466e447ca 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -124,7 +124,7 @@ void LyXAction::init() { LFUN_BUFFER_NEW, "buffer-new", NoBuffer }, { LFUN_BUFFER_NEW_TEMPLATE,"buffer-new-template", NoBuffer }, { LFUN_BUFFER_RELOAD, "buffer-reload", ReadOnly }, - { LFUN_BUFFER_SWITCH, "buffer-switch", ReadOnly }, + { LFUN_BUFFER_SWITCH, "buffer-switch", NoBuffer | ReadOnly }, { LFUN_BUFFER_TOGGLE_READ_ONLY, "buffer-toggle-read-only", ReadOnly }, { LFUN_BUFFER_UPDATE, "buffer-update", ReadOnly }, { LFUN_BUFFER_VIEW, "buffer-view", ReadOnly }, diff --git a/src/LyXFunc.cpp b/src/LyXFunc.cpp index 5c104dcc56..fea925ab58 100644 --- a/src/LyXFunc.cpp +++ b/src/LyXFunc.cpp @@ -85,8 +85,9 @@ #include "frontends/KeySymbol.h" #include "frontends/LyXView.h" #include "frontends/Menubar.h" -#include "frontends/Toolbars.h" #include "frontends/Selection.h" +#include "frontends/Toolbars.h" +#include "frontends/WorkArea.h" #include "support/environment.h" #include "support/FileFilterList.h" @@ -221,7 +222,7 @@ void LyXFunc::initKeySequences(KeyMap * kb) void LyXFunc::setLyXView(LyXView * lv) { - if (!quitting && lyx_view_ && lyx_view_ != lv) + if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv) // save current selection to the selection buffer to allow // middle-button paste in another window cap::saveSelection(lyx_view_->view()->cursor()); @@ -385,6 +386,12 @@ void LyXFunc::processKeySym(KeySymbolPtr keysym, key_modifier::state state) } else { dispatch(func); } + + /* When we move around, or type, it's nice to be able to see + * the cursor immediately after the keypress. + */ + if (lyx_view_ && lyx_view_->currentWorkArea()) + lyx_view_->currentWorkArea()->startBlinkingCursor(); } @@ -903,15 +910,17 @@ void LyXFunc::dispatch(FuncRequest const & cmd) // --- Menus ----------------------------------------------- case LFUN_BUFFER_NEW: menuNew(argument, false); + updateFlags = Update::None; break; case LFUN_BUFFER_NEW_TEMPLATE: menuNew(argument, true); + updateFlags = Update::None; break; case LFUN_BUFFER_CLOSE: closeBuffer(); - view()->update(); + updateFlags = Update::None; break; case LFUN_BUFFER_WRITE: @@ -1187,7 +1196,13 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } lyx_view_->message(bformat(_("Opening help file %1$s..."), makeDisplayPath(fname.absFilename()))); - lyx_view_->loadLyXFile(fname, false); + Buffer * buf = lyx_view_->loadLyXFile(fname, false); + if (buf) { + updateLabels(*buf); + lyx_view_->setBuffer(buf); + lyx_view_->showErrorList("Parse"); + } + updateFlags = Update::None; break; } @@ -1241,29 +1256,31 @@ void LyXFunc::dispatch(FuncRequest const & cmd) case LFUN_BUFFER_SWITCH: BOOST_ASSERT(lyx_view_); lyx_view_->setBuffer(theBufferList().getBuffer(argument)); - updateFlags = Update::Force; + updateFlags = Update::None; break; case LFUN_BUFFER_NEXT: BOOST_ASSERT(lyx_view_); lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer())); - updateFlags = Update::Force; + updateFlags = Update::None; break; case LFUN_BUFFER_PREVIOUS: BOOST_ASSERT(lyx_view_); lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer())); - updateFlags = Update::Force; + updateFlags = Update::None; break; case LFUN_FILE_NEW: BOOST_ASSERT(lyx_view_); newFile(*lyx_view_, argument); + updateFlags = Update::None; break; case LFUN_FILE_OPEN: BOOST_ASSERT(lyx_view_); open(argument); + updateFlags = Update::None; break; case LFUN_DROP_LAYOUTS_CHOICE: @@ -1296,24 +1313,35 @@ void LyXFunc::dispatch(FuncRequest const & cmd) int row; istringstream is(argument); is >> file_name >> row; - if (prefixIs(file_name, package().temp_dir().absFilename())) { + Buffer * buf = 0; + bool loaded = false; + if (prefixIs(file_name, package().temp_dir().absFilename())) // Needed by inverse dvi search. If it is a file // in tmpdir, call the apropriated function - lyx_view_->setBuffer(theBufferList().getBufferFromTmp(file_name)); - } else { + buf = theBufferList().getBufferFromTmp(file_name); + else { // Must replace extension of the file to be .lyx // and get full path FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx"); // Either change buffer or load the file - if (theBufferList().exists(s.absFilename())) { - lyx_view_->setBuffer(theBufferList().getBuffer(s.absFilename())); - } else { - lyx_view_->loadLyXFile(s); + if (theBufferList().exists(s.absFilename())) + buf = theBufferList().getBuffer(s.absFilename()); + else { + buf = lyx_view_->loadLyXFile(s); + loaded = true; } } - view()->setCursorFromRow(row); + if (!buf) { + updateFlags = Update::None; + break; + } + updateLabels(*buf); + lyx_view_->setBuffer(buf); + view()->setCursorFromRow(row); + if (loaded) + lyx_view_->showErrorList("Parse"); updateFlags = Update::FitCursor; break; } @@ -1472,36 +1500,33 @@ void LyXFunc::dispatch(FuncRequest const & cmd) } 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_); - 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()); + BOOST_ASSERT(lyx_view_ && lyx_view_->buffer()); + Buffer * parent = lyx_view_->buffer(); + FileName filename = makeAbsPath(argument, parent->filePath()); view()->saveBookmark(false); + Buffer * child = 0; + bool parsed = false; 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); + child = theBufferList().getBuffer(filename.absFilename()); + } else { + setMessage(bformat(_("Opening child document %1$s..."), + makeDisplayPath(filename.absFilename()))); + child = lyx_view_->loadLyXFile(filename, true); + parsed = true; + } + if (child) { + // 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. + child->setParentName(parent->fileName()); + updateLabels(*child->getMasterBuffer()); + lyx_view_->setBuffer(child); + if (parsed) + lyx_view_->showErrorList("Parse"); + } // If a screen update is required (in case where auto_open is false), - // loadLyXFile() would have taken care of it already. Otherwise we shall + // setBuffer() would have taken care of it already. Otherwise we shall // reset the update flag because it can cause a circular problem. // See bug 3970. updateFlags = Update::None; @@ -1997,10 +2022,8 @@ void LyXFunc::menuNew(string const & name, bool fromTemplate) } Buffer * const b = newFile(filename, templname, !name.empty()); - if (b) { - updateLabels(*b); + if (b) lyx_view_->setBuffer(b); - } } @@ -2060,7 +2083,11 @@ void LyXFunc::open(string const & fname) lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn)); docstring str2; - if (lyx_view_->loadLyXFile(fullname)) { + Buffer * buf = lyx_view_->loadLyXFile(fullname); + if (buf) { + updateLabels(*buf); + lyx_view_->setBuffer(buf); + lyx_view_->showErrorList("Parse"); str2 = bformat(_("Document %1$s opened."), disp_fn); } else { str2 = bformat(_("Could not open document %1$s"), disp_fn); @@ -2169,8 +2196,19 @@ void LyXFunc::closeBuffer() void LyXFunc::reloadBuffer() { FileName filename(lyx_view_->buffer()->fileName()); + docstring const disp_fn = makeDisplayPath(filename.absFilename()); + docstring str; closeBuffer(); - lyx_view_->loadLyXFile(filename); + Buffer * buf = lyx_view_->loadLyXFile(filename); + if (buf) { + updateLabels(*buf); + lyx_view_->setBuffer(buf); + lyx_view_->showErrorList("Parse"); + str = bformat(_("Document %1$s reloaded."), disp_fn); + } else { + str = bformat(_("Could not reload document %1$s"), disp_fn); + } + lyx_view_->message(str); } // Each "lyx_view_" should have it's own message method. lyxview and diff --git a/src/frontends/Application.cpp b/src/frontends/Application.cpp index 246476dd5a..83076e7abf 100644 --- a/src/frontends/Application.cpp +++ b/src/frontends/Application.cpp @@ -52,14 +52,11 @@ LyXView & Application::createView(unsigned int width, const std::string & geometryArg) { LyXView & view = gui().createRegisteredView(); - int view_id = view.id(); - theLyXFunc().setLyXView(&view); - /*int workArea_id_ =*/ gui().newWorkArea(width, height, view_id); - view.init(); view.setGeometry(width, height, posx, posy, maximized, iconSizeXY, geometryArg); + view.setFocus(); setCurrentView(view); diff --git a/src/frontends/Application.h b/src/frontends/Application.h index c050e5cee5..cb8526cd08 100644 --- a/src/frontends/Application.h +++ b/src/frontends/Application.h @@ -34,29 +34,56 @@ class Selection; There should be only one instance of this class. No Qt object initialisation should be done before the instanciation of this class. -\todo The work areas handling could be moved to a base virtual class -common to all frontends. + Model/View/Controller separation at frontend level in LyX-qt4: + + BufferList (N Buffers) + | + Buffer-a + Buffer-b + Buffer-c + Buffer-d + + Application (this is the frontend really, should probably be renamed). + | + LyXView-1 (M1 WorkAreas, M1 <= N) + | | + | + | | (many) + | WorkArea-1 + | | + | BufferView <-----------> Buffer-c + | | + | Cursor + | + LyXView-2 (M2 WorkAreas, M2 <= N, M2 independent of M1) + | + ... - Model/View/Controller separation in LyX: 1) The Model: \c Buffer The Buffer is the in-memory representation of a LyX file format. The Buffer does not (should not) have any information on what part of it is represented on screen. There is one unique Buffer per opened LyX - file. + file. A Buffer may or may not be represented on screen; typically, a + child document does not have an associated BufferView unless the user + choose to visualize it. - 2) The Controller: \c BufferView / \c Painter + 2) The Controller: \c BufferView / \c Painter \c Cursor - The BufferView is a tool used by the view that translates a part of - the Buffer contents into drawing routines. The BufferView asks each - inset of the Buffer to draw itself onto the screen using the Painter. - There can be only one Buffer displayed in a BufferView. While there - is the possibility to switch Buffer inside the BufferView, the goal - is to instantiate a new BufferView on each Buffer switch. + The BufferView is a tool used by the view (\sa WorkArea) that + translates a part of the Buffer contents into drawing routines. The + BufferView asks each inset of the Buffer to draw itself onto the + screen using the Painter. There can be only one Buffer displayed in + a BufferView and it is set on construction. Ideally, a BufferView + should not be able to change the contents of its associated Buffer. + A BufferView is instanciated and destroyed by a \c WorkArea; it is + automatically destroyed by the parent WorkArea when its Buffer is + closed. - \todo Instantiate a new BufferView on each Buffer switch. + \todo Move all Buffer changing LFUN to LyXFunc or Cursor. + \todo BufferView::buffer() should only offer const access. The \c Painter is just a virtual interface to formalize each kind of drawing routines (text, line, rectangle, etc). @@ -69,9 +96,10 @@ common to all frontends. 3) The View: \c WorkArea (and it's qt4 specialisation GuiWorkArea) This contains the real screen area where the drawing is done by the - Painter. One WorkArea holds one unique \c BufferView. While it could be - possible that multiple WorkArea share one BufferView, this is not - possible right now. + Painter. One WorkArea holds one unique \c BufferView. While it could + be possible that multiple WorkArea share one BufferView, this is not + something desirable because a BufferView is dependent of the WorkArea + size. The WorkArea also provide a scrollbar which position is translated into scrolling command to the inner \c BufferView. @@ -84,18 +112,32 @@ common to all frontends. 4) The Window: \c LyXView (and its qt4 specialisation \c GuiView) - This is a full window containing a menubar, toolbars, a tabbar and a - WorkArea. One LyXView could in theory contain multiple WorkArea - (ex: with split window) but this number is limited to one only for - now. In any case, there would be only one WorkArea that gets the focus + This is a full window containing a menubar, toolbars and a central + widget. A LyXView is in charge of creating and closing a View for a + given Buffer. + In the qt4 specialisation, \c GuiView, the central widget is a tab + widget. Each tab is reverved to the visualisation of one Buffer and + contains one WorkArea. In the qt4 frontend, one LyXView thus contains + multiple WorkAreas but this number can limited to one for another + frontend. The idea is that the kernel should not know how a Buffer + is displayed on screen; it's the frontend business. + In the future, we may also have multiple Workareas showing + simultaneously in the same GuiView (ex: with split window). + + \todo Implement split-window + + In any case, there would be only one WorkArea that gets the focus at a time. - Now, concerning the TabBar versus TabWidget issue. Right now, there is - only one WorkArea and the TabBar just used to tell the BufferView inside - the WorkArea to switch to this another Buffer. + With our current implementation using a QTabWidget, each Tab own its + own \c WorkArea. Clicking on a tab switch a WorkArea and not really + a Buffer. LFUN_BUFFER_SWITCH will tell the frontend to search the + WorkArea associated to this Buffer. The WorkArea is automatically + created if not already present. + + A WorkArea is connected to the Buffer::closing signal and is thus + automatically destroyed when its Buffer is closed. - With a TabWidget, each Tab would own its own \c WorkArea. Clicking on a tab - would switch a WorkArea instead of a Buffer. */ class Application { diff --git a/src/frontends/Gui.h b/src/frontends/Gui.h index 3f6754caca..7bf6ca7dd3 100644 --- a/src/frontends/Gui.h +++ b/src/frontends/Gui.h @@ -52,11 +52,6 @@ public: return view_ids_; } - - virtual int newWorkArea(unsigned int width, unsigned int height, int view_id) = 0; - /// - virtual WorkArea & workArea(int id) = 0; - protected: std::vector view_ids_; diff --git a/src/frontends/LyXView.cpp b/src/frontends/LyXView.cpp index 40f33b8c29..bf83d3cc46 100644 --- a/src/frontends/LyXView.cpp +++ b/src/frontends/LyXView.cpp @@ -70,8 +70,7 @@ namespace frontend { docstring current_layout; LyXView::LyXView(int id) - : work_area_(0), - toolbars_(new Toolbars(*this)), + : toolbars_(new Toolbars(*this)), autosave_timeout_(new Timeout(5000)), dialogs_(new Dialogs(*this)), controlcommand_(new ControlCommandBuffer(*this)), id_(id) @@ -88,177 +87,95 @@ LyXView::LyXView(int id) LyXView::~LyXView() { disconnectBuffer(); + disconnectBufferView(); } -// FIXME, there's only one WorkArea per LyXView possible for now. -void LyXView::setWorkArea(WorkArea * work_area) +Buffer * LyXView::buffer() { - BOOST_ASSERT(work_area); - work_area_ = work_area; - work_area_ids_.clear(); - work_area_ids_.push_back(work_area_->id()); + WorkArea * work_area = currentWorkArea(); + if (work_area) + return work_area->bufferView().buffer(); + return 0; } -// FIXME, there's only one WorkArea per LyXView possible for now. -WorkArea const * LyXView::currentWorkArea() const +Buffer const * LyXView::buffer() const { - return work_area_; + WorkArea const * work_area = currentWorkArea(); + if (work_area) + return work_area->bufferView().buffer(); + return 0; } -// FIXME, there's only one WorkArea per LyXView possible for now. -WorkArea * LyXView::currentWorkArea() -{ - return work_area_; -} - - -Buffer * LyXView::buffer() const -{ - BOOST_ASSERT(work_area_); - return work_area_->bufferView().buffer(); -} - - -void LyXView::setBuffer(Buffer * b, bool child_document) +void LyXView::setBuffer(Buffer * newBuffer) { busy(true); - BOOST_ASSERT(work_area_); - Buffer * oldBuffer = work_area_->bufferView().buffer(); + Buffer * oldBuffer = buffer(); + if (oldBuffer == newBuffer) { + busy(false); + return; + } + // 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(); - if (!b && theBufferList().empty()) - getDialogs().hideBufferDependent(); - - Buffer * newBuffer = work_area_->bufferView().setBuffer(b); - - if (newBuffer) { - //Are we closing an oldBuffer which was a child document? - if (!b && oldBuffer && oldBuffer->getMasterBuffer() != oldBuffer) - // Update the labels and section numbering of its master Buffer. - updateLabels(*oldBuffer->getMasterBuffer()); - //Are we opening a new child document? - else if (child_document && newBuffer->getMasterBuffer() != 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); - // Update the labels and section numbering to the new master Buffer. - updateLabels(*newBuffer->getMasterBuffer()); - } - //Now that all the updating of the old buffer has been done, we can - //connect the new buffer. Note that this will also disconnect the old - //buffer, if such there is. - //FIXME Is it clear that this should go right here? Or should it go - //earlier before the previous if (in which case we'd remove the "else")? - connectBuffer(*newBuffer); - - /* FIXME: We need to rebuild the Toc dialog before the others even - if it will be rebuilt again in the next line. This avoid a crash when - other dialogs are rebuilt before the Toc dialog. The reason is - that closing a Buffer triggers an update of all opened dialogs - when dispatching LFUN_DIALOG_UPDATE (hence the patch). - The path is as following: - setBuffer() -> updateBufferDependent() -> RestoreButton() -> LFUN - The problem here is that the Toc dialog has not been - reconstructed (because it comes after in the list of dialogs). */ - updateToc(); - - // Buffer-dependent dialogs should be updated or - // hidden. This should go here because some dialogs (eg ToC) - // require bv_->text. - getDialogs().updateBufferDependent(true); + WorkArea * wa = workArea(*newBuffer); + if (wa == 0) { + updateLabels(*newBuffer->getMasterBuffer()); + wa = addWorkArea(*newBuffer); } else //Disconnect the old buffer...there's no new one. disconnectBuffer(); + connectBuffer(*newBuffer); + connectBufferView(wa->bufferView()); + setCurrentWorkArea(wa); - if (quitting) - return; - - updateMenubar(); - updateToolbars(); - updateLayoutChoice(); - updateWindowTitle(); - updateStatusBar(); - updateTab(); busy(false); - work_area_->redraw(); } -bool LyXView::loadLyXFile(FileName const & filename, bool tolastfiles, - bool child_document, bool auto_open) +Buffer * LyXView::loadLyXFile(FileName const & filename, bool tolastfiles) { busy(true); - - BOOST_ASSERT(work_area_); string parentfilename; - Buffer * oldBuffer = work_area_->bufferView().buffer(); + Buffer * oldBuffer = buffer(); if (oldBuffer) parentfilename = oldBuffer->fileName(); - bool alreadyLoaded = checkIfLoaded(filename); Buffer * newBuffer = checkAndLoadLyXFile(filename); if (!newBuffer) { message(_("Document not loaded.")); updateStatusBar(); busy(false); - work_area_->redraw(); - return false; + return 0; } - 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()); - - bool const parse_error = !newBuffer->errorList("Parse").empty(); - bool const need_switch = parse_error || !auto_open; - if (need_switch) { - setBuffer(newBuffer, child_document); - if (!alreadyLoaded) { - if (parse_error) - showErrorList("Parse"); - // 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 (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()); - updateMenubar(); - updateToolbars(); - updateLayoutChoice(); - updateStatusBar(); - work_area_->redraw(); - } - } - if (tolastfiles) - LyX::ref().session().lastFiles().add(filename); + WorkArea * wa = addWorkArea(*newBuffer); + + // 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 + BufferView & bv = wa->bufferView(); + if (bv.moveToPosition(pit, pos, 0, 0).get<1>()) { + if (bv.fitCursor()) + bv.updateMetrics(false); + newBuffer->text().setCurrentFont(bv.cursor()); } } busy(false); - return true; + return newBuffer; } @@ -267,11 +184,6 @@ void LyXView::connectBuffer(Buffer & buf) if (errorsConnection_.connected()) disconnectBuffer(); - BOOST_ASSERT(work_area_); - bufferChangedConnection_ = - buf.changed.connect( - boost::bind(&WorkArea::redraw, work_area_)); - bufferStructureChangedConnection_ = buf.getMasterBuffer()->structureChanged.connect( boost::bind(&LyXView::updateToc, this)); @@ -299,30 +211,26 @@ void LyXView::connectBuffer(Buffer & buf) readonlyConnection_ = buf.readonly.connect( boost::bind(&LyXView::showReadonly, this, _1)); - - closingConnection_ = - buf.closing.connect( - boost::bind(&LyXView::setBuffer, this, (Buffer *)0, false)); } void LyXView::disconnectBuffer() { errorsConnection_.disconnect(); - bufferChangedConnection_.disconnect(); bufferStructureChangedConnection_.disconnect(); messageConnection_.disconnect(); busyConnection_.disconnect(); titleConnection_.disconnect(); timerConnection_.disconnect(); readonlyConnection_.disconnect(); - closingConnection_.disconnect(); layout_changed_connection_.disconnect(); } void LyXView::connectBufferView(BufferView & bv) { + message_connection_ = bv.message.connect( + boost::bind(&LyXView::message, this, _1)); show_dialog_connection_ = bv.showDialog.connect( boost::bind(&LyXView::showDialog, this, _1)); show_dialog_with_data_connection_ = bv.showDialogWithData.connect( @@ -338,6 +246,7 @@ void LyXView::connectBufferView(BufferView & bv) void LyXView::disconnectBufferView() { + message_connection_.disconnect(); show_dialog_connection_.disconnect(); show_dialog_with_data_connection_.disconnect(); show_inset_dialog_connection_.disconnect(); @@ -387,10 +296,10 @@ void LyXView::showReadonly(bool) } -BufferView * LyXView::view() const +BufferView * LyXView::view() { - BOOST_ASSERT(work_area_); - return &work_area_->bufferView(); + WorkArea * wa = currentWorkArea(); + return wa? &wa->bufferView() : 0; } @@ -402,16 +311,20 @@ void LyXView::updateToc() void LyXView::updateToolbars() { - BOOST_ASSERT(work_area_); - bool const math = - work_area_->bufferView().cursor().inMathed(); - bool const table = - lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled(); - bool const review = - lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() && - lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true); - - toolbars_->update(math, table, review); + WorkArea * wa = currentWorkArea(); + if (wa) { + bool const math = + wa->bufferView().cursor().inMathed(); + bool const table = + lyx::getStatus(FuncRequest(LFUN_LAYOUT_TABULAR)).enabled(); + bool const review = + lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).enabled() && + lyx::getStatus(FuncRequest(LFUN_CHANGES_TRACK)).onoff(true); + + toolbars_->update(math, table, review); + } else + toolbars_->update(false, false, false); + // update redaonly status of open dialogs. This could also be in // updateMenubar(), but since updateToolbars() and updateMenubar() // are always called together it is only here. @@ -449,7 +362,7 @@ void LyXView::autoSave() { LYXERR(Debug::INFO) << "Running autoSave()" << endl; - if (view()->buffer()) + if (buffer()) lyx::autoSave(view()); } @@ -464,7 +377,7 @@ void LyXView::resetAutosaveTimer() void LyXView::updateLayoutChoice() { // Don't show any layouts without a buffer - if (!view()->buffer()) { + if (!buffer()) { toolbars_->clearLayoutList(); return; } @@ -474,8 +387,7 @@ void LyXView::updateLayoutChoice() current_layout = buffer()->params().getTextClass().defaultLayoutName(); } - BOOST_ASSERT(work_area_); - docstring const & layout = work_area_->bufferView().cursor(). + docstring const & layout = currentWorkArea()->bufferView().cursor(). innerParagraph().layout()->name(); if (layout != current_layout) { @@ -490,42 +402,50 @@ void LyXView::updateWindowTitle() docstring maximize_title = lyx::from_ascii("LyX"); docstring minimize_title = lyx::from_ascii("LyX"); - if (view()->buffer()) { - string const cur_title = buffer()->fileName(); + Buffer * buf = buffer(); + if (buf) { + string const cur_title = buf->fileName(); if (!cur_title.empty()) { maximize_title += ": " + makeDisplayPath(cur_title, 30); minimize_title = lyx::from_utf8(onlyFilename(cur_title)); - if (!buffer()->isClean()) { + if (!buf->isClean()) { maximize_title += _(" (changed)"); minimize_title += lyx::char_type('*'); } - if (buffer()->isReadonly()) + if (buf->isReadonly()) maximize_title += _(" (read only)"); } } setWindowTitle(maximize_title, minimize_title); - updateTab(); } void LyXView::dispatch(FuncRequest const & cmd) { - theLyXFunc().setLyXView(this); - lyx::dispatch(cmd); + string const argument = to_utf8(cmd.argument()); + switch(cmd.action) { + case LFUN_BUFFER_SWITCH: + setBuffer(theBufferList().getBuffer(to_utf8(cmd.argument()))); + break; + default: + theLyXFunc().setLyXView(this); + lyx::dispatch(cmd); + } } -Buffer const * const LyXView::updateInset(Inset const * inset) const +Buffer const * const LyXView::updateInset(Inset const * inset) { - Buffer const * buffer_ptr = 0; - if (inset) { - BOOST_ASSERT(work_area_); - work_area_->scheduleRedraw(); + WorkArea * work_area = currentWorkArea(); + if (!work_area) + return 0; - buffer_ptr = work_area_->bufferView().buffer(); + if (inset) { + BOOST_ASSERT(work_area); + work_area->scheduleRedraw(); } - return buffer_ptr; + return work_area->bufferView().buffer(); } } // namespace frontend diff --git a/src/frontends/LyXView.h b/src/frontends/LyXView.h index 1048f519aa..7bf5ae9245 100644 --- a/src/frontends/LyXView.h +++ b/src/frontends/LyXView.h @@ -70,16 +70,19 @@ public: virtual void setFocus() = 0; - std::vector const & workAreaIds() const { return work_area_ids_; } - - /// FIXME: rename to setCurrentWorkArea() - void setWorkArea(WorkArea * work_area); - + /// + virtual WorkArea * workArea(Buffer & buffer) = 0; + /// + virtual WorkArea * addWorkArea(Buffer & buffer) = 0; + /// + virtual void setCurrentWorkArea(WorkArea * work_area) = 0; + /// + virtual void removeWorkArea(WorkArea * work_area) = 0; /// return the current WorkArea (the one that has the focus). - WorkArea const * currentWorkArea() const; + virtual WorkArea const * currentWorkArea() const = 0; /// FIXME: This non-const access is needed because of /// a mis-designed \c ControlSpellchecker. - WorkArea * currentWorkArea(); + virtual WorkArea * currentWorkArea() = 0; /** * This is called after the concrete view has been created. @@ -114,14 +117,12 @@ public: //@{ generic accessor functions - /** return the current buffer view - Returned as a shared_ptr so that anything wanting to cache the - buffer view can do so safely using a boost::weak_ptr. - */ - BufferView * view() const; + /// \return the current buffer view. + BufferView * view(); - /// return the buffer currently shown in this window - Buffer * buffer() const; + /// \return the buffer currently shown in this window + Buffer * buffer(); + Buffer const * buffer() const; /// return the toolbar for this view Toolbars & getToolbars() { return *toolbars_.get(); } @@ -141,14 +142,11 @@ public: //@} /// 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? + Buffer * loadLyXFile(support::FileName const & name, ///< File to load. + bool tolastfiles = true); ///< append to the "Open recent" menu? /// set a buffer to the current workarea. - void setBuffer(Buffer * b, ///< \c Buffer to set. - bool child_document = false); ///< Is this a child document? + void setBuffer(Buffer * b); ///< \c Buffer to set. /// updates the possible layouts selectable void updateLayoutChoice(); @@ -176,9 +174,6 @@ public: /// updates the title of the window void updateWindowTitle(); - /// updates the tab view - virtual void updateTab() = 0; - /// reset autosave timer void resetAutosaveTimer(); @@ -188,7 +183,7 @@ public: /** redraw \c inset in all the BufferViews in which it is currently * visible. If successful return a pointer to the owning Buffer. */ - Buffer const * const updateInset(Inset const *) const; + Buffer const * const updateInset(Inset const *); /// returns true if this view has the focus. virtual bool hasFocus() const = 0; @@ -196,17 +191,15 @@ public: /// show the error list to the user void showErrorList(std::string const &); +protected: /// connect to signals in the given BufferView void connectBufferView(BufferView & bv); /// disconnect from signals in the given BufferView void disconnectBufferView(); - -protected: - /// current work area (screen view of a BufferView). - /** - \todo FIXME: there is only one workArea per LyXView for now. - */ - frontend::WorkArea * work_area_; + /// connect to signals in the given buffer + void connectBuffer(Buffer & buf); + /// disconnect from signals in the given buffer + void disconnectBuffer(); /// view's menubar boost::scoped_ptr menubar_; @@ -231,8 +224,6 @@ private: /// dialogs for this view boost::scoped_ptr dialogs_; - /// buffer changed signal connection - boost::signals::connection bufferChangedConnection_; /// buffer structure changed signal connection boost::signals::connection bufferStructureChangedConnection_; /// buffer errors signal connection @@ -247,18 +238,6 @@ private: boost::signals::connection timerConnection_; /// buffer readonly status changed signal connection boost::signals::connection readonlyConnection_; - /// buffer closing signal connection - boost::signals::connection closingConnection_; - /// connect to signals in the given buffer - void connectBuffer(Buffer & buf); - /// disconnect from signals in the given buffer - /// NOTE: Do not call this unless you really want no buffer - /// to be connected---for example, when closing the last open - /// buffer. If you are switching buffers, just call - /// connectBuffer(), and the old buffer will be disconnected - /// automatically. This ensures that we do not leave LyX in a - /// state in which no buffer is connected. - void disconnectBuffer(); /// BufferView messages signal connection //@{ @@ -298,7 +277,6 @@ protected: private: int id_; - std::vector work_area_ids_; }; } // namespace frontend diff --git a/src/frontends/WorkArea.cpp b/src/frontends/WorkArea.cpp index 4e8187567c..cb13604e99 100644 --- a/src/frontends/WorkArea.cpp +++ b/src/frontends/WorkArea.cpp @@ -17,26 +17,27 @@ #include "frontends/Application.h" #include "frontends/FontMetrics.h" - -#include "FuncRequest.h" -#include "LyXFunc.h" +#include "frontends/LyXView.h" #include "BufferView.h" #include "Buffer.h" #include "BufferParams.h" +#include "Color.h" #include "CoordCache.h" #include "Cursor.h" #include "debug.h" -#include "Language.h" -#include "Color.h" #include "Font.h" +#include "FuncRequest.h" +#include "Language.h" +#include "LyX.h" +#include "LyXFunc.h" #include "LyXRC.h" -#include "Text.h" -#include "LyXView.h" #include "MetricsInfo.h" +#include "Text.h" #include "gettext.h" #include "support/ForkedcallsController.h" +#include "support/FileName.h" #include #include @@ -64,40 +65,55 @@ boost::signals::connection timecon; namespace lyx { namespace frontend { -WorkArea::WorkArea(int id, LyXView & lyx_view) - : buffer_view_(0), lyx_view_(lyx_view), greyed_out_(true), - id_(id), cursor_visible_(false), cursor_timeout_(400) +WorkArea::WorkArea(Buffer & buffer, LyXView & lv) + : buffer_view_(new BufferView(buffer)), lyx_view_(&lv), + cursor_visible_(false), cursor_timeout_(400) { - // Start loading the pixmap as soon as possible - //if (lyxrc.show_banner) { - // showBanner(); - //} - // Setup the signals timecon = cursor_timeout_.timeout .connect(boost::bind(&WorkArea::toggleCursor, this)); + bufferChangedConnection_ = + buffer.changed.connect( + boost::bind(&WorkArea::redraw, this)); + + bufferClosingConnection_ = + buffer.closing.connect( + boost::bind(&WorkArea::close, this)); + cursor_timeout_.start(); } -void WorkArea::setBufferView(BufferView * buffer_view) +WorkArea::~WorkArea() { - if (buffer_view_) { - message_connection_.disconnect(); - lyx_view_.disconnectBufferView(); - } - - hideCursor(); - buffer_view_ = buffer_view; - toggleCursor(); + bufferChangedConnection_.disconnect(); + bufferClosingConnection_.disconnect(); + + // current buffer is going to be switched-off, save cursor pos + // Ideally, the whole cursor stack should be saved, but session + // currently can only handle bottom (whole document) level pit and pos. + // That is to say, if a cursor is in a nested inset, it will be + // restore to the left of the top level inset. + Cursor & cur = buffer_view_->cursor(); + LyX::ref().session().lastFilePos().save( + support::FileName(buffer_view_->buffer()->fileName()), + boost::tie(cur.bottom().pit(), cur.bottom().pos()) ); + + delete buffer_view_; +} - message_connection_ = buffer_view_->message.connect( - boost::bind(&WorkArea::displayMessage, this, _1)); - lyx_view_.connectBufferView(*buffer_view); +void WorkArea::close() +{ + lyx_view_->removeWorkArea(this); } +//void WorkArea::setLyXView(LyXView * lyx_view) +//{ +// lyx_view_ = lyx_view; +//} + BufferView & WorkArea::bufferView() { @@ -127,16 +143,13 @@ void WorkArea::startBlinkingCursor() void WorkArea::redraw() { - if (!buffer_view_ || !buffer_view_->buffer()) { - greyed_out_ = true; - // The argument here are meaningless. - expose(1,1,1,1); + if (!isVisible()) + // No need to redraw in this case. return; - } // No need to do anything if this is the current view. The BufferView // metrics are already up to date. - if (&lyx_view_ != theApp()->currentView()) { + if (lyx_view_ != theApp()->currentView()) { // FIXME: it would be nice to optimize for the off-screen case. buffer_view_->updateMetrics(false); buffer_view_->cursor().fixIfBroken(); @@ -152,7 +165,6 @@ void WorkArea::redraw() } ViewMetricsInfo const & vi = buffer_view_->viewMetricsInfo(); - greyed_out_ = false; LYXERR(Debug::WORKAREA) << "WorkArea::redraw screen" << endl; @@ -176,13 +188,8 @@ void WorkArea::processKeySym(KeySymbolPtr key, key_modifier::state state) // the blinking cursor. stopBlinkingCursor(); - theLyXFunc().setLyXView(&lyx_view_); + theLyXFunc().setLyXView(lyx_view_); theLyXFunc().processKeySym(key, state); - - /* When we move around, or type, it's nice to be able to see - * the cursor immediately after the keypress. - */ - startBlinkingCursor(); } @@ -190,11 +197,11 @@ void WorkArea::dispatch(FuncRequest const & cmd0, key_modifier::state k) { // Handle drag&drop if (cmd0.action == LFUN_FILE_OPEN) { - lyx_view_.dispatch(cmd0); + lyx_view_->dispatch(cmd0); return; } - theLyXFunc().setLyXView(&lyx_view_); + theLyXFunc().setLyXView(lyx_view_); FuncRequest cmd; @@ -222,9 +229,9 @@ void WorkArea::dispatch(FuncRequest const & cmd0, key_modifier::state k) // Skip these when selecting if (cmd.action != LFUN_MOUSE_MOTION) { - lyx_view_.updateLayoutChoice(); - lyx_view_.updateMenubar(); - lyx_view_.updateToolbars(); + lyx_view_->updateLayoutChoice(); + lyx_view_->updateMenubar(); + lyx_view_->updateToolbars(); } // GUI tweaks except with mouse motion with no button pressed. @@ -233,7 +240,7 @@ void WorkArea::dispatch(FuncRequest const & cmd0, key_modifier::state k) // Slight hack: this is only called currently when we // clicked somewhere, so we force through the display // of the new status here. - lyx_view_.clearMessage(); + lyx_view_->clearMessage(); // Show the cursor immediately after any operation. startBlinkingCursor(); @@ -243,12 +250,12 @@ void WorkArea::dispatch(FuncRequest const & cmd0, key_modifier::state k) void WorkArea::resizeBufferView() { - lyx_view_.busy(true); - lyx_view_.message(_("Formatting document...")); + lyx_view_->busy(true); + lyx_view_->message(_("Formatting document...")); buffer_view_->workAreaResize(width(), height()); - lyx_view_.updateLayoutChoice(); - lyx_view_.clearMessage(); - lyx_view_.busy(false); + lyx_view_->updateLayoutChoice(); + lyx_view_->clearMessage(); + lyx_view_->busy(false); } @@ -268,7 +275,7 @@ void WorkArea::scrollBufferView(int position) redraw(); if (lyxrc.cursor_follows_scrollbar) { buffer_view_->setCursorFromScrollbar(); - lyx_view_.updateLayoutChoice(); + lyx_view_->updateLayoutChoice(); } // Show the cursor immediately after any operation. startBlinkingCursor(); @@ -280,9 +287,6 @@ void WorkArea::showCursor() if (cursor_visible_) return; - if (!buffer_view_->buffer()) - return; - CursorShape shape = BAR_SHAPE; Text const & text = *buffer_view_->cursor().innerText(); @@ -332,28 +336,19 @@ void WorkArea::hideCursor() void WorkArea::toggleCursor() { - if (buffer_view_->buffer()) { - - if (cursor_visible_) - hideCursor(); - else - showCursor(); + if (cursor_visible_) + hideCursor(); + else + showCursor(); - // Use this opportunity to deal with any child processes that - // have finished but are waiting to communicate this fact - // to the rest of LyX. - ForkedcallsController & fcc = ForkedcallsController::get(); - fcc.handleCompletedProcesses(); - } + // Use this opportunity to deal with any child processes that + // have finished but are waiting to communicate this fact + // to the rest of LyX. + ForkedcallsController & fcc = ForkedcallsController::get(); + fcc.handleCompletedProcesses(); cursor_timeout_.restart(); } - -void WorkArea::displayMessage(lyx::docstring const & message) -{ - lyx_view_.message(message); -} - } // namespace frontend } // namespace lyx diff --git a/src/frontends/WorkArea.h b/src/frontends/WorkArea.h index 09dbfc3a4f..da45fc5d61 100644 --- a/src/frontends/WorkArea.h +++ b/src/frontends/WorkArea.h @@ -25,7 +25,7 @@ #undef CursorShape namespace lyx { - +class Buffer; class BufferView; class FuncRequest; @@ -53,13 +53,13 @@ enum CursorShape { */ class WorkArea : public boost::signals::trackable { public: - WorkArea(int id, LyXView & lyx_view); - - virtual ~WorkArea() {} + /// + WorkArea(Buffer & buffer, LyXView & lv); - int const id() const { return id_; } + virtual ~WorkArea(); - void setBufferView(BufferView * buffer_view); + /// + void setLyXView(LyXView & lv) { lyx_view_ = &lv; } /// BufferView & bufferView(); @@ -69,6 +69,9 @@ public: /// \return true if has the keyboard input focus. virtual bool hasFocus() const = 0; + /// \return true if has this WorkArea is visible. + virtual bool isVisible() const = 0; + /// return the width of the work area in pixels virtual int width() const = 0; @@ -95,12 +98,17 @@ public: /// Process Key pressed event. /// This needs to be public because it is accessed externally by GuiView. void processKeySym(KeySymbolPtr key, key_modifier::state state); + protected: /// cause the display of the given area of the work area virtual void expose(int x, int y, int w, int h) = 0; /// void dispatch(FuncRequest const & cmd0, key_modifier::state = key_modifier::none); + + /// close this work area. + /// Slot for Buffer::closing boost signal. + void close(); /// void resizeBufferView(); /// @@ -120,25 +128,20 @@ protected: /// BufferView * buffer_view_; - - /// - LyXView & lyx_view_; /// - bool greyed_out_; + LyXView * lyx_view_; private: - /// - int id_; - /// - void displayMessage(docstring const &); - /// buffer messages signal connection - boost::signals::connection message_connection_; - /// is the cursor currently displayed bool cursor_visible_; /// Timeout cursor_timeout_; + + /// buffer changed signal connection + boost::signals::connection bufferChangedConnection_; + /// buffer closing signal connection + boost::signals::connection bufferClosingConnection_; }; } // namespace frontend diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 18da529ddc..aaf7add117 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,10 @@ GuiApplication::GuiApplication(int & argc, char ** argv) LoaderQueue::setPriority(10,100); guiApp = this; + + // Set the cache to 5120 kilobytes which corresponds to screen size of + // 1280 by 1024 pixels with a color depth of 32 bits. + QPixmapCache::setCacheLimit(5120); } diff --git a/src/frontends/qt4/GuiImplementation.cpp b/src/frontends/qt4/GuiImplementation.cpp index 8529b61ced..99c2871186 100644 --- a/src/frontends/qt4/GuiImplementation.cpp +++ b/src/frontends/qt4/GuiImplementation.cpp @@ -12,22 +12,12 @@ #include -// This include must be declared before everything else because -// of boost/Qt/LyX clash... -#include "GuiView.h" - #include "GuiImplementation.h" -#include "GuiWorkArea.h" -#include "BufferView.h" -#include "BufferList.h" -#include "FuncRequest.h" -#include "LyXFunc.h" +#include "GuiView.h" #include -using boost::shared_ptr; - namespace { @@ -49,7 +39,6 @@ namespace frontend { GuiImplementation::GuiImplementation() { view_ids_.clear(); - work_area_ids_.clear(); } @@ -74,9 +63,6 @@ bool GuiImplementation::unregisterView(int id) std::map::iterator it; for (it = views_.begin(); it != views_.end(); ++it) { if (it->first == id) { - std::vector const & wa_ids = it->second->workAreaIds(); - for (size_t i = 0; i < wa_ids.size(); ++i) - work_areas_.erase(wa_ids[i]); views_.erase(id); break; } @@ -108,9 +94,7 @@ bool GuiImplementation::closeAllViews() } views_.clear(); - work_areas_.clear(); view_ids_.clear(); - work_area_ids_.clear(); return true; } @@ -122,43 +106,6 @@ LyXView& GuiImplementation::view(int id) const } -std::vector const & GuiImplementation::workAreaIds() -{ - updateIds(work_areas_, work_area_ids_); - return work_area_ids_; -} - - -int GuiImplementation::newWorkArea(unsigned int w, unsigned int h, int view_id) -{ - updateIds(views_, view_ids_); - int id = 0; - while (work_areas_.find(id) != work_areas_.end()) - id++; - - GuiView * view = views_[view_id]; - - work_areas_.insert(std::pair - (id, new GuiWorkArea(w, h, id, *view))); - - // FIXME BufferView creation should be independant of WorkArea creation - buffer_views_[id].reset(new BufferView); - work_areas_[id]->setBufferView(buffer_views_[id].get()); - - view->setWorkArea(work_areas_[id]); - view->initTab(work_areas_[id]); - - return id; -} - - -WorkArea& GuiImplementation::workArea(int id) -{ - BOOST_ASSERT(work_areas_.find(id) != work_areas_.end()); - return *work_areas_[id]; -} - - } // namespace frontend } // namespace lyx diff --git a/src/frontends/qt4/GuiImplementation.h b/src/frontends/qt4/GuiImplementation.h index e2a4a524bc..08b22589e5 100644 --- a/src/frontends/qt4/GuiImplementation.h +++ b/src/frontends/qt4/GuiImplementation.h @@ -22,7 +22,6 @@ namespace lyx { namespace frontend { -class GuiWorkArea; class GuiView; class LyXView; @@ -44,9 +43,6 @@ public: virtual LyXView& view(int id) const; - virtual int newWorkArea(unsigned int width, unsigned int height, int view_id); - virtual WorkArea& workArea(int id); - private: /// Multiple views container. @@ -56,22 +52,6 @@ private: * \sa Qt::WA_DeleteOnClose attribute. */ std::map views_; - - /// Multiple workareas container. - /** - * Warning: This must not be a smart pointer as the destruction of the - * object is handled by Qt when its parent view is closed. - */ - std::map work_areas_; - /// - - /// view of a buffer. Eventually there will be several. - std::map > buffer_views_; - - - std::vector const & workAreaIds(); - - std::vector work_area_ids_; }; } // namespace frontend diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index dfb14ac1c8..ab114f783e 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -24,6 +24,7 @@ #include "qt_helpers.h" #include "frontends/Application.h" +#include "frontends/Dialogs.h" #include "frontends/Gui.h" #include "frontends/WorkArea.h" @@ -43,6 +44,7 @@ #include "LyXRC.h" #include "MenuBackend.h" #include "Session.h" +#include "version.h" #include #include @@ -50,17 +52,16 @@ #include #include #include -#include #include #include +#include #include #include +#include #include #include -#include +#include #include -#include - #include #include @@ -81,84 +82,59 @@ namespace { int const statusbar_timer_value = 3000; -class TabWidget : public QWidget +class BackgroundWidget: public QWidget { - QHBoxLayout* hlayout; public: - QTabBar* tabbar; - QPushButton* closeTabButton; - - void hideTabsIfNecessary() + BackgroundWidget(QString const & file, QString const & text) { - if (tabbar->count() > 1) { - tabbar->show(); - closeTabButton->show(); - } else { - tabbar->hide(); - closeTabButton->hide(); + splash_ = new QPixmap(file); + if (!splash_) { + lyxerr << "could not load splash screen: '" << fromqstr(file) << "'" << endl; + return; } + + QPainter pain(splash_); + pain.setPen(QColor(255, 255, 0)); + QFont font; + // The font used to display the version info + font.setStyleHint(QFont::SansSerif); + font.setWeight(QFont::Bold); + font.setPointSize(convert(lyxrc.font_sizes[Font::SIZE_LARGE])); + pain.setFont(font); + pain.drawText(260, 270, text); } - TabWidget(QWidget* w, bool topTabBar) + void paintEvent(QPaintEvent * ev) { - closeTabButton = new QPushButton(this); - FileName const file = support::libFileSearch("images", "closetab", "xpm"); - if (!file.empty()) { - QPixmap pm(toqstr(file.absFilename())); - closeTabButton->setIcon(QIcon(pm)); - closeTabButton->setMaximumSize(pm.size()); - closeTabButton->setFlat(true); - } else { - closeTabButton->setText("Close"); - } - closeTabButton->setCursor(Qt::ArrowCursor); - closeTabButton->setToolTip(tr("Close tab")); - closeTabButton->setEnabled(true); + if (!splash_) + return; - tabbar = new QTabBar; -#if QT_VERSION >= 0x040200 - tabbar->setUsesScrollButtons(true); -#endif - hlayout = new QHBoxLayout; - QVBoxLayout* vlayout = new QVBoxLayout; - hlayout->addWidget(tabbar); - hlayout->addWidget(closeTabButton); - if (topTabBar) { - vlayout->addLayout(hlayout); - vlayout->addWidget(w); - } else { - tabbar->setShape(QTabBar::RoundedSouth); - vlayout->addWidget(w); - vlayout->addLayout(hlayout); - } - vlayout->setMargin(0); - vlayout->setSpacing(0); - hlayout->setMargin(0); - setLayout(vlayout); - hideTabsIfNecessary(); + int x = (width() - splash_->width()) / 2; + int y = (height() - splash_->height()) / 2; + QPainter pain(this); + pain.drawPixmap(x, y, *splash_); } - void clearTabbar() - { - for (int i = tabbar->count() - 1; i >= 0; --i) - tabbar->removeTab(i); - } +private: + QPixmap * splash_; }; + } // namespace anon struct GuiView::GuiViewPrivate { - vector tabnames; string cur_title; - TabWidget* tabWidget; - int posx_offset; int posy_offset; - GuiViewPrivate() : tabWidget(0), posx_offset(0), posy_offset(0) + QTabWidget * tab_widget_; + QStackedWidget * stack_widget_; + BackgroundWidget * bg_widget_; + + GuiViewPrivate() : posx_offset(0), posy_offset(0) {} unsigned int smallIconSize; @@ -201,6 +177,28 @@ struct GuiView::GuiViewPrivate return menu; } + + void initBackground() + { + bg_widget_ = 0; + LYXERR(Debug::GUI) << "show banner: " << lyxrc.show_banner << endl; + /// The text to be written on top of the pixmap + QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version"); + FileName const file = support::libFileSearch("images", "banner", "png"); + if (file.empty()) + return; + + bg_widget_ = new BackgroundWidget(toqstr(file.absFilename()), text); + } + + void setBackground() + { + if (!bg_widget_) + return; + + stack_widget_->setCurrentWidget(bg_widget_); + bg_widget_->setUpdatesEnabled(true); + } }; @@ -228,6 +226,44 @@ GuiView::GuiView(int id) setWindowIcon(QPixmap(toqstr(iconname.absFilename()))); #endif + d.tab_widget_ = new QTabWidget; + + QPushButton * closeTabButton = new QPushButton(this); + FileName const file = support::libFileSearch("images", "closetab", "xpm"); + if (!file.empty()) { + QPixmap pm(toqstr(file.absFilename())); + closeTabButton->setIcon(QIcon(pm)); + closeTabButton->setMaximumSize(pm.size()); + closeTabButton->setFlat(true); + } else { + closeTabButton->setText("Close"); + } + closeTabButton->setCursor(Qt::ArrowCursor); + closeTabButton->setToolTip(tr("Close tab")); + closeTabButton->setEnabled(true); + + QObject::connect(d.tab_widget_, SIGNAL(currentChanged(int)), + this, SLOT(currentTabChanged(int))); + QObject::connect(closeTabButton, SIGNAL(clicked()), + this, SLOT(closeCurrentTab())); + + d.tab_widget_->setCornerWidget(closeTabButton); +#if QT_VERSION >= 0x040200 + d.tab_widget_->setUsesScrollButtons(true); +#endif + + d.initBackground(); + if (d.bg_widget_) { + lyxerr << "stack widget!" << endl; + d.stack_widget_ = new QStackedWidget; + d.stack_widget_->addWidget(d.bg_widget_); + d.stack_widget_->addWidget(d.tab_widget_); + setCentralWidget(d.stack_widget_); + } else { + d.stack_widget_ = 0; + setCentralWidget(d.tab_widget_); + } + // For Drag&Drop. setAcceptDrops(true); } @@ -250,8 +286,8 @@ void GuiView::close() void GuiView::setFocus() { - BOOST_ASSERT(work_area_); - static_cast(work_area_)->setFocus(); + if (d.tab_widget_->count()) + d.tab_widget_->currentWidget()->setFocus(); } @@ -274,14 +310,8 @@ void GuiView::init() QObject::connect(&statusbar_timer_, SIGNAL(timeout()), this, SLOT(update_view_state_qt())); - BOOST_ASSERT(work_area_); - if (!work_area_->bufferView().buffer() && !theBufferList().empty()) - setBuffer(theBufferList().first()); - - // make sure the buttons are disabled if needed - updateToolbars(); - updateLayoutChoice(); - updateMenubar(); + if (d.stack_widget_) + d.stack_widget_->setCurrentWidget(d.bg_widget_); } @@ -311,15 +341,6 @@ void GuiView::closeEvent(QCloseEvent * close_event) quitting = true; - if (view()->buffer()) { - // save cursor position for opened files to .lyx/session - // only bottom (whole doc) level pit and pos is saved. - LyX::ref().session().lastFilePos().save( - FileName(buffer()->fileName()), - boost::tie(view()->cursor().bottom().pit(), - view()->cursor().bottom().pos())); - } - // this is the place where we leave the frontend. // it is the only point at which we start quitting. saveGeometry(); @@ -501,7 +522,9 @@ void GuiView::setGeometry(unsigned int width, (void)geometryArg; #endif } - + + d.setBackground(); + show(); // For an unknown reason, the Window title update is not effective for @@ -610,56 +633,6 @@ void GuiView::update_view_state_qt() } -void GuiView::initTab(QWidget* workarea) -{ - // construct the TabWidget with 'false' to have the tabbar at the bottom - d.tabWidget = new TabWidget(workarea, true); - setCentralWidget(d.tabWidget); - QObject::connect(d.tabWidget->tabbar, SIGNAL(currentChanged(int)), - this, SLOT(currentTabChanged(int))); - QObject::connect(d.tabWidget->closeTabButton, SIGNAL(clicked()), - this, SLOT(closeCurrentTab())); -} - - -void GuiView::updateTab() -{ - std::vector const & names = theBufferList().getFileNames(); - - string cur_title; - if (view()->buffer()) { - cur_title = view()->buffer()->fileName(); - } - - // avoid unnecessary tabbar rebuild: - // check if something has changed - if (d.tabnames == names && d.cur_title == cur_title) - return; - d.tabnames = names; - d.cur_title = cur_title; - - QTabBar & tabbar = *d.tabWidget->tabbar; - - // update when all is done - tabbar.blockSignals(true); - - // remove all tab bars - d.tabWidget->clearTabbar(); - - // rebuild tabbar and function map from scratch - if (names.size() > 1) { - for(size_t i = 0; i < names.size(); i++) { - tabbar.addTab(toqstr(makeDisplayPath(names[i], 30))); - // set current tab - if (names[i] == cur_title) - tabbar.setCurrentIndex(i); - } - } - tabbar.blockSignals(false); - d.tabWidget->hideTabsIfNecessary(); -} - - void GuiView::closeCurrentTab() { dispatch(FuncRequest(LFUN_BUFFER_CLOSE)); @@ -668,8 +641,32 @@ void GuiView::closeCurrentTab() void GuiView::currentTabChanged(int i) { - BOOST_ASSERT(i >= 0 && size_type(i) < d.tabnames.size()); - dispatch(FuncRequest(LFUN_BUFFER_SWITCH, d.tabnames[i])); + disconnectBuffer(); + disconnectBufferView(); + GuiWorkArea * wa = dynamic_cast(d.tab_widget_->widget(i)); + BOOST_ASSERT(wa); + BufferView & bv = wa->bufferView(); + connectBufferView(bv); + connectBuffer(*bv.buffer()); + bv.updateMetrics(false); + bv.cursor().fixIfBroken(); + wa->setUpdatesEnabled(true); + wa->redraw(); + wa->setFocus(); + + updateToc(); + // Buffer-dependent dialogs should be updated or + // hidden. This should go here because some dialogs (eg ToC) + // require bv_->text. + getDialogs().updateBufferDependent(true); + updateMenubar(); + updateToolbars(); + updateLayoutChoice(); + updateWindowTitle(); + updateStatusBar(); + + lyxerr << "currentTabChanged " << i + << "File" << wa->bufferView().buffer()->fileName() << endl; } @@ -741,11 +738,18 @@ bool GuiView::event(QEvent * e) case QEvent::ShortcutOverride: { QKeyEvent * ke = static_cast(e); + if (d.tab_widget_->count() == 0) { + theLyXFunc().setLyXView(this); + boost::shared_ptr sym(new QKeySymbol); + sym->set(ke); + theLyXFunc().processKeySym(sym, q_key_state(ke->modifiers())); + e->accept(); + return true; + } if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { boost::shared_ptr sym(new QKeySymbol); sym->set(ke); - BOOST_ASSERT(work_area_); - work_area_->processKeySym(sym, key_modifier::none); + currentWorkArea()->processKeySym(sym, key_modifier::none); e->accept(); return true; } @@ -773,17 +777,20 @@ void GuiView::show() void GuiView::busy(bool yes) { - BOOST_ASSERT(work_area_); - static_cast(work_area_)->setUpdatesEnabled(!yes); + if (d.tab_widget_->count()) { + GuiWorkArea * wa = dynamic_cast(d.tab_widget_->currentWidget()); + BOOST_ASSERT(wa); + wa->setUpdatesEnabled(!yes); + if (yes) + wa->stopBlinkingCursor(); + else + wa->startBlinkingCursor(); + } - if (yes) { - work_area_->stopBlinkingCursor(); + if (yes) QApplication::setOverrideCursor(Qt::WaitCursor); - } - else { - work_area_->startBlinkingCursor(); + else QApplication::restoreOverrideCursor(); - } } @@ -833,6 +840,96 @@ Toolbars::ToolbarPtr GuiView::makeToolbar(ToolbarInfo const & tbinfo, bool newli return Toolbars::ToolbarPtr(Tb); } + +WorkArea * GuiView::workArea(Buffer & buffer) +{ + for (int i = 0; i != d.tab_widget_->count(); ++i) { + GuiWorkArea * wa = dynamic_cast(d.tab_widget_->widget(i)); + BOOST_ASSERT(wa); + if (wa->bufferView().buffer() == &buffer) + return wa; + } + return 0; +} + + +WorkArea * GuiView::addWorkArea(Buffer & buffer) +{ + GuiWorkArea * wa = new GuiWorkArea(buffer, *this); + d.tab_widget_->addTab(wa, toqstr(makeDisplayPath(buffer.fileName(), 30))); + wa->bufferView().updateMetrics(false); + if (d.stack_widget_) + d.stack_widget_->setCurrentWidget(d.tab_widget_); + return wa; +} + + +WorkArea * GuiView::currentWorkArea() +{ + if (d.tab_widget_->count() == 0) + return 0; + BOOST_ASSERT(dynamic_cast(d.tab_widget_->currentWidget())); + return dynamic_cast(d.tab_widget_->currentWidget()); +} + + +WorkArea const * GuiView::currentWorkArea() const +{ + if (d.tab_widget_->count() == 0) + return 0; + BOOST_ASSERT(dynamic_cast(d.tab_widget_->currentWidget())); + return dynamic_cast(d.tab_widget_->currentWidget()); +} + + +void GuiView::setCurrentWorkArea(WorkArea * work_area) +{ + BOOST_ASSERT(work_area); + + // Changing work area can result from opening a file so + // update the toc in any case. + updateToc(); + + GuiWorkArea * wa = dynamic_cast(work_area); + BOOST_ASSERT(wa); + d.tab_widget_->setCurrentWidget(wa); + wa->setFocus(); +} + + +void GuiView::removeWorkArea(WorkArea * work_area) +{ + BOOST_ASSERT(work_area); + if (work_area == currentWorkArea()) { + disconnectBuffer(); + disconnectBufferView(); + } + + // removing a work area often results from closing a file so + // update the toc in any case. + updateToc(); + + GuiWorkArea * gwa = dynamic_cast(work_area); + BOOST_ASSERT(gwa); + int index = d.tab_widget_->indexOf(gwa); + d.tab_widget_->removeTab(index); + + delete gwa; + + if (d.tab_widget_->count()) { + // make sure the next work area is enabled. + d.tab_widget_->currentWidget()->setUpdatesEnabled(true); + return; + } + + getDialogs().hideBufferDependent(); + if (d.stack_widget_) { + // No more work area, switch to the background widget. + d.setBackground(); + } +} + + } // namespace frontend } // namespace lyx diff --git a/src/frontends/qt4/GuiView.h b/src/frontends/qt4/GuiView.h index 3082d41b8a..1f67c8eb93 100644 --- a/src/frontends/qt4/GuiView.h +++ b/src/frontends/qt4/GuiView.h @@ -75,8 +75,6 @@ public: virtual void clearMessage(); virtual bool hasFocus() const; - virtual void updateTab(); - /// show - display the top-level window void show(); @@ -86,8 +84,6 @@ public: /// menu item has been selected void activated(FuncRequest const &); - void initTab(QWidget* workArea); - QMenu* createPopupMenu(); Q_SIGNALS: @@ -118,6 +114,19 @@ protected: /// virtual void moveEvent(QMoveEvent * e); + /// \return the \c Workarea associated to \p Buffer + /// \retval 0 if no \c WorkArea is found. + WorkArea * workArea(Buffer & buffer); + + /// Add a \c WorkArea + /// \return the \c Workarea associated to \p Buffer + /// \retval 0 if no \c WorkArea is found. + WorkArea * addWorkArea(Buffer & buffer); + void setCurrentWorkArea(WorkArea * work_area); + void removeWorkArea(WorkArea * work_area); + WorkArea const * currentWorkArea() const; + WorkArea * currentWorkArea(); + private: /// void dragEnterEvent(QDragEnterEvent * ev); diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 030b83c753..137de10185 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -173,8 +173,8 @@ SyntheticMouseEvent::SyntheticMouseEvent() {} -GuiWorkArea::GuiWorkArea(int w, int h, int id, LyXView & lyx_view) - : WorkArea(id, lyx_view), need_resize_(false), schedule_redraw_(false), +GuiWorkArea::GuiWorkArea(Buffer & buf, LyXView & lv) + : WorkArea(buf, lv), need_resize_(false), schedule_redraw_(false), preedit_lines_(1) { screen_ = QPixmap(viewport()->width(), viewport()->height()); @@ -196,8 +196,6 @@ GuiWorkArea::GuiWorkArea(int w, int h, int id, LyXView & lyx_view) viewport()->setCursor(Qt::IBeamCursor); - resize(w, h); - synthetic_mouse_event_.timeout.timeout.connect( boost::bind(&GuiWorkArea::generateSyntheticMouseEvent, this)); @@ -258,17 +256,13 @@ void GuiWorkArea::focusInEvent(QFocusEvent * /*event*/) // if (theApp() == 0 || &lyx_view_ == theApp()->currentView()) // return; - theApp()->setCurrentView(lyx_view_); + theApp()->setCurrentView(*lyx_view_); // Repaint the whole screen. // Note: this is different from redraw() as only the backing pixmap // will be redrawn, which is cheap. viewport()->repaint(); - // FIXME: it would be better to send a signal "newBuffer()" - // in BufferList that could be connected to the different tabbars. - lyx_view_.updateTab(); - startBlinkingCursor(); } @@ -459,49 +453,6 @@ void GuiWorkArea::update(int x, int y, int w, int h) } -void GuiWorkArea::doGreyOut(QLPainter & pain) -{ - pain.fillRectangle(0, 0, width(), height(), - Color::bottomarea); - - //if (!lyxrc.show_banner) - // return; - LYXERR(Debug::GUI) << "show banner: " << lyxrc.show_banner << endl; - /// The text to be written on top of the pixmap - QString const text = lyx_version ? QString(lyx_version) : qt_("unknown version"); - FileName const file = support::libFileSearch("images", "banner", "png"); - if (file.empty()) - return; - - QPixmap pm(toqstr(file.absFilename())); - if (!pm) { - lyxerr << "could not load splash screen: '" << file << "'" << endl; - return; - } - - QFont font; - // The font used to display the version info - font.setStyleHint(QFont::SansSerif); - font.setWeight(QFont::Bold); - font.setPointSize(convert(lyxrc.font_sizes[Font::SIZE_LARGE])); - - int const w = pm.width(); - int const h = pm.height(); - - int x = (width() - w) / 2; - int y = (height() - h) / 2; - - pain.drawPixmap(x, y, pm); - - x += 260; - y += 270; - - pain.setPen(QColor(255, 255, 0)); - pain.setFont(font); - pain.drawText(x, y, text); -} - - void GuiWorkArea::paintEvent(QPaintEvent * ev) { QRect const rc = ev->rect(); @@ -538,14 +489,6 @@ void GuiWorkArea::expose(int x, int y, int w, int h) void GuiWorkArea::updateScreen() { QLPainter pain(&screen_); - - if (greyed_out_) { - LYXERR(Debug::GUI) << "splash screen requested" << endl; - verticalScrollBar()->hide(); - doGreyOut(pain); - return; - } - verticalScrollBar()->show(); paintText(*buffer_view_, pain); } @@ -554,11 +497,9 @@ void GuiWorkArea::updateScreen() void GuiWorkArea::showCursor(int x, int y, int h, CursorShape shape) { if (schedule_redraw_) { - if (buffer_view_ && buffer_view_->buffer()) { - buffer_view_->update(Update::Force); - updateScreen(); - viewport()->update(QRect(0, 0, viewport()->width(), viewport()->height())); - } + buffer_view_->update(Update::Force); + updateScreen(); + viewport()->update(QRect(0, 0, viewport()->width(), viewport()->height())); schedule_redraw_ = false; // Show the cursor immediately after the update. hideCursor(); @@ -586,11 +527,6 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) docstring const & preedit_string = qstring_to_ucs4(e->preeditString()); - if(greyed_out_) { - e->ignore(); - return; - } - if (!commit_string.isEmpty()) { LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION diff --git a/src/frontends/qt4/GuiWorkArea.h b/src/frontends/qt4/GuiWorkArea.h index 09ba83c6d1..05903003ba 100644 --- a/src/frontends/qt4/GuiWorkArea.h +++ b/src/frontends/qt4/GuiWorkArea.h @@ -88,10 +88,11 @@ class GuiWorkArea : public QAbstractScrollArea, public WorkArea public: /// - GuiWorkArea(int width, int height, int id, LyXView & lyx_view); + GuiWorkArea(Buffer & buffer, LyXView & lv); /// bool hasFocus() const { return QAbstractScrollArea::hasFocus(); } + bool isVisible() const { return QAbstractScrollArea::isVisible(); } /// return the width of the content pane virtual int width() const { return viewport()->width(); } diff --git a/src/insets/InsetInclude.cpp b/src/insets/InsetInclude.cpp index 2097994776..4276e4455e 100644 --- a/src/insets/InsetInclude.cpp +++ b/src/insets/InsetInclude.cpp @@ -386,37 +386,34 @@ Buffer * getChildBuffer(Buffer const & buffer, InsetCommandParams const & params } // namespace anon - -Buffer * loadIfNeeded(Buffer const & buffer, InsetCommandParams const & params) +/// return true if the file is or got loaded. +Buffer * loadIfNeeded(Buffer const & parent, InsetCommandParams const & params) { if (isVerbatim(params) || isListings(params)) return 0; - FileName const included_file = includedFilename(buffer, params); + string const parent_filename = parent.fileName(); + FileName const included_file = makeAbsPath(to_utf8(params["filename"]), + onlyPath(parent_filename)); + if (!isLyXFilename(included_file.absFilename())) return 0; - Buffer * buf = theBufferList().getBuffer(included_file.absFilename()); - if (!buf) { + Buffer * child = theBufferList().getBuffer(included_file.absFilename()); + if (!child) { // the readonly flag can/will be wrong, not anymore I think. if (!fs::exists(included_file.toFilesystemEncoding())) - return false; - if (use_gui) { - lyx::dispatch(FuncRequest(LFUN_BUFFER_CHILD_OPEN, - included_file.absFilename() + "|true")); - buf = theBufferList().getBuffer(included_file.absFilename()); - } - else { - buf = theBufferList().newBuffer(included_file.absFilename()); - if (!loadLyXFile(buf, included_file)) { - //close the buffer we just opened - theBufferList().close(buf, false); - return false; - } + return 0; + + child = theBufferList().newBuffer(included_file.absFilename()); + if (!loadLyXFile(child, included_file)) { + //close the buffer we just opened + theBufferList().close(child, false); + return 0; } } - buf->setParentName(parentFilename(buffer)); - return buf; + child->setParentName(parent_filename); + return child; } @@ -768,7 +765,7 @@ InsetInclude::getBibfilesCache(Buffer const & buffer) const bool InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const { - BOOST_ASSERT(mi.base.bv && mi.base.bv->buffer()); + BOOST_ASSERT(mi.base.bv); bool use_preview = false; if (RenderPreview::status() != LyXRC::PREVIEW_OFF) { @@ -801,7 +798,7 @@ void InsetInclude::draw(PainterInfo & pi, int x, int y) const { setPosCache(pi, x, y); - BOOST_ASSERT(pi.base.bv && pi.base.bv->buffer()); + BOOST_ASSERT(pi.base.bv); bool use_preview = false; if (RenderPreview::status() != LyXRC::PREVIEW_OFF) { -- 2.39.2