]> git.lyx.org Git - features.git/commitdiff
The BufferView/WorkArea/LyXView reorg a.k.a Multiple WorkAreas:
authorAbdelrazak Younes <younes@lyx.org>
Tue, 21 Aug 2007 07:33:46 +0000 (07:33 +0000)
committerAbdelrazak Younes <younes@lyx.org>
Tue, 21 Aug 2007 07:33:46 +0000 (07:33 +0000)
* 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

23 files changed:
src/Buffer.cpp
src/Buffer.h
src/BufferView.cpp
src/BufferView.h
src/Importer.cpp
src/LyX.cpp
src/LyXAction.cpp
src/LyXFunc.cpp
src/frontends/Application.cpp
src/frontends/Application.h
src/frontends/Gui.h
src/frontends/LyXView.cpp
src/frontends/LyXView.h
src/frontends/WorkArea.cpp
src/frontends/WorkArea.h
src/frontends/qt4/GuiApplication.cpp
src/frontends/qt4/GuiImplementation.cpp
src/frontends/qt4/GuiImplementation.h
src/frontends/qt4/GuiView.cpp
src/frontends/qt4/GuiView.h
src/frontends/qt4/GuiWorkArea.cpp
src/frontends/qt4/GuiWorkArea.h
src/insets/InsetInclude.cpp

index f9d11689bb164044af2b9656aa7c6819d3a44768..5f73e27f6bec1f9ce4eb07510839b996138d3ad4 100644 (file)
@@ -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)
 {
index 7db748fb1e4ea94285c81d192a96e9973a662843..450622043ee0ab6a052026cb1dd2d7329785f99b 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <iosfwd>
 #include <string>
-#include <map>
 #include <utility>
 #include <vector>
 
@@ -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<void()> resetAutosaveTimers;
        /// This signal is emitting if the buffer is being closed.
-       boost::signal<void()> closing;
+       boost::signal<void(Buffer *)> 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<Impl> 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<support::FileName> bibfilesCache_;
index 5ee6410efc07b7966b239be7dac4aaabb7bf598c..75566e54e03fdaead47b0a9dafc8eec55b3158bc 100644 (file)
@@ -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<BookmarksSection::Bookmark &>(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<pit_type, pos_type, int> 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<pit_type, pos_type, int> 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<size_t>(bottom_pit) < buffer_->paragraphs().size()) {
-               DocIterator it = doc_iterator_begin(buffer_->inset());
+       if (static_cast<size_t>(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<int>(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<docstring> 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
index 93a4ae9be474f5be2838cee6d2a61bdfb9241bbc..ea51376a781add9cb11cf966475d62a0735e7155 100644 (file)
@@ -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_;
index ad609e47c13330ffcc4265b13599f0605314aabd..6f38b202987af9269a36e0e1e09592ee81100de8 100644 (file)
@@ -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)
index e93cfe64941f027ef76d0d6934ed9d5c8c28c8ab..9acbceb541357f655f11792cbec5867ce2fa9558 100644 (file)
@@ -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<FileName> 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<FileName> 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());
 }
 
 
index e228d7edd684ce2903baa25132d263525b7a955d..8466e447ca72307e64e8e45579e504e6aa11bdc6 100644 (file)
@@ -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 },
index 5c104dcc56ba26fae54609e84a83a74cd7c4d24a..fea925ab582786393df284187163c1f09cac114b 100644 (file)
@@ -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
index 246476dd5a6dbfbe6e626e39fb63cea5f0b49c97..83076e7abf107b936e41ea6c99e10336cf23a7ae 100644 (file)
@@ -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);
index c050e5cee5d6278405300a7e50d1582cce2872b5..cb8526cd08161db4ec35fc357aa92f86b4f5f0d2 100644 (file)
@@ -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)
+   |  |
+   |  <tab-widget>
+   |     | (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
 {
index 3f6754caca283fc11cdd2ebaf0bcb0cd2858b046..7bf6ca7dd3195ee5f0bd4ce4258ee9e96708ea1a 100644 (file)
@@ -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<int> view_ids_;
index 40f33b8c293be5dff8b01f1fee1b09d75161b619..bf83d3cc467816494c421db8dabca29ac306c3fe 100644 (file)
@@ -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
index 1048f519aab04ad6e8d19d69667c590b24679248..7bf5ae92457015809f22e7f110187060ebc281a9 100644 (file)
@@ -70,16 +70,19 @@ public:
 
        virtual void setFocus() = 0;
 
-       std::vector<int> 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> menubar_;
@@ -231,8 +224,6 @@ private:
        /// dialogs for this view
        boost::scoped_ptr<Dialogs> 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<int> work_area_ids_;
 };
 
 } // namespace frontend
index 4e8187567c9ce6392994487f98d4ca9c1141ea82..cb13604e9946fa0b2f757f7c574783090f0f2ed4 100644 (file)
 
 #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 <boost/utility.hpp>
 #include <boost/bind.hpp>
@@ -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
index 09dbfc3a4f2e406c357177c38026c3d4c3f8c30d..da45fc5d614f7807b63138edeaad59413d5083d0 100644 (file)
@@ -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
index 18da529ddc931eef7e95a7b6df14e621b421eabf..aaf7add1170615015cd53c8d87056b8be272b8ec 100644 (file)
@@ -42,6 +42,7 @@
 #include <QFileOpenEvent>
 #include <QLocale>
 #include <QLibraryInfo>
+#include <QPixmapCache>
 #include <QTextCodec>
 #include <QTimer>
 #include <QTranslator>
@@ -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);
 }
 
 
index 8529b61ced5ea6f4ea73a8a4ad63b4ca3bbccaae..99c287118603e9657ecf109472192481908141ab 100644 (file)
 
 #include <config.h>
 
-// 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 <QApplication>
 
-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<int, GuiView *>::iterator it;
        for (it = views_.begin(); it != views_.end(); ++it) {
                if (it->first == id) {
-                       std::vector<int> 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<int> 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<int, GuiWorkArea *>
-                                       (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
 
index e2a4a524bcd10bc270fd91c58b039c49588241a0..08b22589e5dce785613762b56a0b3d5764ee9087 100644 (file)
@@ -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<int, GuiView *> 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<int, GuiWorkArea *> work_areas_;
-       ///
-
-       /// view of a buffer. Eventually there will be several.
-       std::map<int, boost::shared_ptr<BufferView> > buffer_views_;
-
-
-       std::vector<int> const & workAreaIds();
-
-       std::vector<int> work_area_ids_;
 };
 
 } // namespace frontend
index dfb14ac1c82d1e7d07a55e40efc55a55c76beb46..ab114f783e01be7d802d45be5da40c1af27f9b2f 100644 (file)
@@ -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 <QAction>
 #include <QApplication>
 #include <QDesktopWidget>
 #include <QDragEnterEvent>
 #include <QDropEvent>
-#include <QHBoxLayout>
 #include <QList>
 #include <QMimeData>
+#include <QPainter>
 #include <QPixmap>
 #include <QPushButton>
+#include <QStackedWidget>
 #include <QStatusBar>
 #include <QToolBar>
-#include <QTabBar>
+#include <QTabWidget>
 #include <QUrl>
-#include <QVBoxLayout>
-
 
 #include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
@@ -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<int>(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<string> 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<GuiWorkArea *>(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<string> 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<GuiWorkArea *>(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<QKeyEvent*>(e);
+               if (d.tab_widget_->count() == 0) {
+                       theLyXFunc().setLyXView(this);
+                       boost::shared_ptr<QKeySymbol> 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<QKeySymbol> 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<GuiWorkArea *>(work_area_)->setUpdatesEnabled(!yes);
+       if (d.tab_widget_->count()) {
+               GuiWorkArea * wa = dynamic_cast<GuiWorkArea *>(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<GuiWorkArea *>(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<GuiWorkArea *>(d.tab_widget_->currentWidget()));
+       return dynamic_cast<GuiWorkArea *>(d.tab_widget_->currentWidget());
+}
+
+
+WorkArea const * GuiView::currentWorkArea() const
+{
+       if (d.tab_widget_->count() == 0)
+               return 0;
+       BOOST_ASSERT(dynamic_cast<GuiWorkArea const *>(d.tab_widget_->currentWidget()));
+       return dynamic_cast<GuiWorkArea const *>(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<GuiWorkArea *>(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<GuiWorkArea *>(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
 
index 3082d41b8a36d38a9da07baf6cce0da1a72893fb..1f67c8eb930c8106d86771ef7a2136bfe9887523 100644 (file)
@@ -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);
index 030b83c7535a170d0d450e4676c2b14155fced3c..137de10185877a6aa79f9be44042d94d0f02a939 100644 (file)
@@ -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<int>(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
index 09ba83c6d1bfe820d8a2ad66387f07ad16bc822d..05903003bacbb8c83138ac029d4a23ef510e40ef 100644 (file)
@@ -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(); }
index 20979947762132b9175827507a2ed22c219e41b0..4276e4455e601ac081ee002b5e0d26700a3bdde5 100644 (file)
@@ -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) {