]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView_pimpl.C
minimal effort implementation of:
[lyx.git] / src / BufferView_pimpl.C
index 2746534219c8811d1bf94cf30ffc90a6dc21dd95..a1fc04b408b4608db3e96008a0fb279cb3f44de3 100644 (file)
@@ -12,6 +12,7 @@
  * \author André Pönitz
  * \author Dekel Tsur
  * \author Jürgen Vigna
+ * \author Abdelrazak Younes
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -28,6 +29,7 @@
 #include "CutAndPaste.h"
 #include "debug.h"
 #include "dispatchresult.h"
+#include "errorlist.h"
 #include "factory.h"
 #include "FloatList.h"
 #include "funcrequest.h"
@@ -48,7 +50,6 @@
 #include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
 #include "pariterator.h"
-#include "rowpainter.h"
 #include "toc.h"
 #include "undo.h"
 #include "vspace.h"
 #include "insets/insettext.h"
 
 #include "frontends/Alert.h"
-#include "frontends/Clipboard.h"
 #include "frontends/Dialogs.h"
 #include "frontends/FileDialog.h"
 #include "frontends/font_metrics.h"
 #include "frontends/Gui.h"
 #include "frontends/LyXView.h"
-#include "frontends/WorkArea.h"
+#include "frontends/Selection.h"
 
 #include "graphics/Previews.h"
 
 #include "support/convert.h"
 #include "support/filefilterlist.h"
 #include "support/filetools.h"
-#include "support/forkedcontr.h"
 #include "support/package.h"
 #include "support/types.h"
 
@@ -81,7 +80,6 @@
 #include <functional>
 #include <vector>
 
-using lyx::frontend::WorkArea;
 using lyx::frontend::Clipboard;
 using lyx::frontend::Gui;
 
@@ -91,7 +89,6 @@ using lyx::support::addPath;
 using lyx::support::bformat;
 using lyx::support::FileFilterList;
 using lyx::support::fileSearch;
-using lyx::support::ForkedcallsController;
 using lyx::support::isDirWriteable;
 using lyx::support::makeDisplayPath;
 using lyx::support::makeAbsPath;
@@ -113,12 +110,6 @@ namespace {
 
 unsigned int const saved_positions_num = 20;
 
-// All the below connection objects are needed because of a bug in some
-// versions of GCC (<=2.96 are on the suspects list.) By having and assigning
-// to these connections we avoid a segfault upon startup, and also at exit.
-// (Lgb)
-
-boost::signals::connection timecon;
 
 /// Return an inset of this class if it exists at the current cursor position
 template <class T>
@@ -137,18 +128,12 @@ T * getInsetByCode(LCursor & cur, InsetBase::Code code)
 
 
 BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner)
-       : bv_(&bv), owner_(owner), buffer_(0), wh_(0), cursor_timeout(400),
-         using_xterm_cursor(false), cursor_(bv),
+       : bv_(&bv), owner_(owner), buffer_(0), wh_(0),
+         cursor_(bv),
          multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0)
 {
        xsel_cache_.set = false;
 
-       // Setup the signals
-       timecon = cursor_timeout.timeout
-               .connect(boost::bind(&BufferView::Pimpl::cursorToggle, this));
-
-       cursor_timeout.start();
-
        saved_positions.resize(saved_positions_num);
        // load saved bookmarks
        lyx::Session::BookmarkList & bmList = LyX::ref().session().loadBookmarks();
@@ -161,73 +146,6 @@ BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner)
 }
 
 
-void BufferView::Pimpl::addError(ErrorItem const & ei)
-{
-       errorlist_.push_back(ei);
-}
-
-
-void BufferView::Pimpl::showReadonly(bool)
-{
-       owner_->updateWindowTitle();
-       owner_->getDialogs().updateBufferDependent(false);
-}
-
-
-void BufferView::Pimpl::connectBuffer(Buffer & buf)
-{
-       if (errorConnection_.connected())
-               disconnectBuffer();
-
-       errorConnection_ =
-               buf.error.connect(
-                       boost::bind(&BufferView::Pimpl::addError, this, _1));
-
-       messageConnection_ =
-               buf.message.connect(
-                       boost::bind(&LyXView::message, owner_, _1));
-
-       busyConnection_ =
-               buf.busy.connect(
-                       boost::bind(&LyXView::busy, owner_, _1));
-
-       titleConnection_ =
-               buf.updateTitles.connect(
-                       boost::bind(&LyXView::updateWindowTitle, owner_));
-
-       timerConnection_ =
-               buf.resetAutosaveTimers.connect(
-                       boost::bind(&LyXView::resetAutosaveTimer, owner_));
-
-       readonlyConnection_ =
-               buf.readonly.connect(
-                       boost::bind(&BufferView::Pimpl::showReadonly, this, _1));
-
-       closingConnection_ =
-               buf.closing.connect(
-                       boost::bind(&BufferView::Pimpl::setBuffer, this, (Buffer *)0));
-}
-
-
-void BufferView::Pimpl::disconnectBuffer()
-{
-       errorConnection_.disconnect();
-       messageConnection_.disconnect();
-       busyConnection_.disconnect();
-       titleConnection_.disconnect();
-       timerConnection_.disconnect();
-       readonlyConnection_.disconnect();
-       closingConnection_.disconnect();
-}
-
-
-void BufferView::Pimpl::newFile(string const & filename, string const & tname,
-       bool isNamed)
-{
-       setBuffer(::newFile(filename, tname, isNamed));
-}
-
-
 bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
 {
        // Get absolute path of file and add ".lyx"
@@ -262,7 +180,6 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
 
        if (found) {
                b = bufferlist.newBuffer(s);
-               connectBuffer(*b);
                if (!::loadLyXFile(b, s)) {
                        bufferlist.release(b);
                        return false;
@@ -274,14 +191,17 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
                int const ret = Alert::prompt(_("Create new document?"),
                         text, 0, 1, _("&Create"), _("Cancel"));
 
-               if (ret == 0)
-                       b = ::newFile(s, string(), true);
-               else
+               if (ret == 0) {
+                       b = newFile(s, string(), true);
+                       if (!b)
+                               return false;
+               } else
                        return false;
        }
 
        setBuffer(b);
-       bv_->showErrorList(_("Parse"));
+       // Send the "errors" signal in case of parsing errors
+       b->errors("Parse");
 
        // scroll to the position when the file was last closed
        if (lyxrc.use_lastfilepos) {
@@ -312,12 +232,6 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
 }
 
 
-lyx::frontend::Gui & BufferView::Pimpl::gui() const
-{
-       return owner_->gui();
-}
-
-
 int BufferView::Pimpl::width() const
 {
        return width_;
@@ -336,7 +250,6 @@ void BufferView::Pimpl::setBuffer(Buffer * b)
                            << "[ b = " << b << "]" << endl;
 
        if (buffer_) {
-               disconnectBuffer();
                // 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.
@@ -347,6 +260,12 @@ void BufferView::Pimpl::setBuffer(Buffer * b)
                        boost::tie(cursor_.pit(), cursor_.pos()) );
        }
 
+       // If we're quitting lyx, don't bother updating stuff
+       if (quitting) {
+               buffer_ = 0;
+               return;
+       }
+
        // If we are closing current buffer, switch to the first in
        // buffer list.
        if (!b) {
@@ -354,7 +273,6 @@ void BufferView::Pimpl::setBuffer(Buffer * b)
                                    << " No Buffer!" << endl;
                // We are closing the buffer, use the first buffer as current
                buffer_ = bufferlist.first();
-               owner_->getDialogs().hideBufferDependent();
        } else {
                // Set current buffer
                buffer_ = b;
@@ -365,15 +283,9 @@ void BufferView::Pimpl::setBuffer(Buffer * b)
        anchor_ref_ = 0;
        offset_ref_ = 0;
 
-
-       // If we're quitting lyx, don't bother updating stuff
-       if (quitting)
-               return;
-
        if (buffer_) {
                lyxerr[Debug::INFO] << BOOST_CURRENT_FUNCTION
                                    << "Buffer addr: " << buffer_ << endl;
-               connectBuffer(*buffer_);
                cursor_.push(buffer_->inset());
                cursor_.resetAnchor();
                buffer_->text().init(bv_);
@@ -386,34 +298,9 @@ void BufferView::Pimpl::setBuffer(Buffer * b)
                        cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset())));
                        cursor_.setSelection();
                }
-
-               // Buffer-dependent dialogs should be updated or
-               // hidden. This should go here because some dialogs (eg ToC)
-               // require bv_->text.
-               owner_->getDialogs().updateBufferDependent(true);
        }
 
        update();
-       owner_->updateMenubar();
-       owner_->updateToolbars();
-       owner_->updateLayoutChoice();
-       owner_->updateWindowTitle();
-
-       // This is done after the layout combox has been populated
-       if (buffer_) {
-               size_t i = cursor_.depth() - 1;
-               // we know we'll eventually find a paragraph
-               while (true) {
-                       CursorSlice const & slice = cursor_[i];
-                       if (!slice.inset().inMathed()) {
-                               LyXLayout_ptr const layout = slice.paragraph().layout();
-                               owner_->setLayout(layout->name());
-                               break;
-                       }
-                       BOOST_ASSERT(i>0);
-                       --i;
-               }
-       }
 
        if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF)
                lyx::graphics::Previews::get().generateBufferPreviews(*buffer_);
@@ -423,8 +310,6 @@ void BufferView::Pimpl::setBuffer(Buffer * b)
 void BufferView::Pimpl::resizeCurrentBuffer()
 {
        lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << endl;
-       owner_->busy(true);
-       owner_->message(_("Formatting document..."));
 
        LyXText * text = bv_->text();
        if (!text)
@@ -432,12 +317,7 @@ void BufferView::Pimpl::resizeCurrentBuffer()
 
        text->init(bv_);
        update();
-
        switchKeyMap();
-       owner_->busy(false);
-
-       // Reset the "Formatting..." message
-       owner_->clearMessage();
 }
 
 
@@ -512,8 +392,6 @@ void BufferView::Pimpl::scrollDocView(int value)
        if (!buffer_)
                return;
 
-       owner_->gui().guiCursor().hide();
-
        LyXText & t = *bv_->text();
 
        float const bar = value / float(wh_ * t.paragraphs().size());
@@ -524,10 +402,12 @@ void BufferView::Pimpl::scrollDocView(int value)
        t.redoParagraph(anchor_ref_);
        int const h = t.getPar(anchor_ref_).height();
        offset_ref_ = int((bar * t.paragraphs().size() - anchor_ref_) * h);
-       update();
+}
 
-       if (!lyxrc.cursor_follows_scrollbar)
-               return;
+
+void BufferView::Pimpl::setCursorFromScrollbar()
+{
+       LyXText & t = *bv_->text();
 
        int const height = 2 * defaultRowHeight();
        int const first = height;
@@ -553,7 +433,6 @@ void BufferView::Pimpl::scrollDocView(int value)
                        t.setCursorFromCoordinates(cur, 0, newy);
                }
        }
-       owner_->updateLayoutChoice();
 }
 
 
@@ -575,24 +454,7 @@ void BufferView::Pimpl::scroll(int /*lines*/)
 //     scrollDocView(new_top_y);
 //
 //     // Update the scrollbar.
-//     workArea_->setScrollbarParams(t->height(), top_y(), defaultRowHeight());
-}
-
-
-void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key,
-                                        key_modifier::state state)
-{
-       owner_->getLyXFunc().processKeySym(key, state);
-
-       /* This is perhaps a bit of a hack. When we move
-        * around, or type, it's nice to be able to see
-        * the cursor immediately after the keypress. So
-        * we reset the toggle timeout and force the visibility
-        * of the cursor. Note we cannot do this inside
-        * dispatch() itself, because that's called recursively.
-        */
-       if (available())
-               owner_->gui().guiCursor().show(*bv_);
+//     workArea_->setScrollbarParams(t->height(), top_y(), defaultRowHeight());}
 }
 
 
@@ -619,7 +481,7 @@ void BufferView::Pimpl::selectionRequested()
                xsel_cache_.set = cur.selection();
                sel = cur.selectionAsString(false);
                if (!sel.empty())
-                       owner_->gui().clipboard().put(sel);
+                       owner_->gui().selection().put(sel);
        }
 }
 
@@ -627,7 +489,6 @@ void BufferView::Pimpl::selectionRequested()
 void BufferView::Pimpl::selectionLost()
 {
        if (available()) {
-               owner_->gui().guiCursor().hide();
                cursor_.clearSelection();
                xsel_cache_.set = false;
        }
@@ -644,14 +505,12 @@ void BufferView::Pimpl::workAreaResize(int width, int height)
        height_ = height;
 
        if (buffer_ && widthChange) {
-               // The visible LyXView need a resize
+               // The WorkArea content needs a resize
                resizeCurrentBuffer();
        }
 
        if (widthChange || heightChange)
                update();
-
-       owner_->updateLayoutChoice();
 }
 
 
@@ -687,65 +546,34 @@ ViewMetricsInfo const & BufferView::Pimpl::viewMetricsInfo()
 }
 
 
-void BufferView::Pimpl::update(Update::flags flags)
+bool BufferView::Pimpl::update(Update::flags flags)
 {
-       lyxerr[Debug::DEBUG]
-               << BOOST_CURRENT_FUNCTION
-               << "[fitcursor = " << (flags & Update::FitCursor)
-               << ", forceupdate = " << (flags & Update::Force)
-               << ", singlepar = " << (flags & Update::SinglePar)
-               << "]  buffer: " << buffer_ << endl;
+       // This is close to a hot-path.
+       if (lyxerr.debugging(Debug::DEBUG)) {
+               lyxerr[Debug::DEBUG]
+                       << BOOST_CURRENT_FUNCTION
+                       << "[fitcursor = " << (flags & Update::FitCursor)
+                       << ", forceupdate = " << (flags & Update::Force)
+                       << ", singlepar = " << (flags & Update::SinglePar)
+                       << "]  buffer: " << buffer_ << endl;
+       }
 
        // Check needed to survive LyX startup
-       if (buffer_) {
-               // Update macro store
-               buffer_->buildMacros();
-
-               // This, together with doneUpdating(), verifies (using
-               // asserts) that screen redraw is not called from
-               // within itself.
-               theCoords.startUpdating();
-
-               // First drawing step
-               bool singlePar = flags & Update::SinglePar;
-               bool forceupdate(flags & (Update::Force | Update::SinglePar));
-
-               if ((flags & (Update::FitCursor | Update::MultiParSel))
-                   && (fitCursor() || multiParSel())) {
-                       forceupdate = true;
-                       singlePar = false;
-               }
-
-               if (forceupdate) {
-                       // Second drawing step
-                       updateMetrics(singlePar);
-                       owner_->workArea()->redraw(*bv_);
-               } else {
-                       // Abort updating of the coord
-                       // cache - just restore the old one
-                       theCoords.doneUpdating();
-               }
-       } else
-               owner_->workArea()->greyOut();
-
-       owner_->view_state_changed();
-}
+       if (!buffer_)
+               return false;
 
+       // Update macro store
+       buffer_->buildMacros();
 
-// Callback for cursor timer
-void BufferView::Pimpl::cursorToggle()
-{
-       if (buffer_) {
-               owner_->gui().guiCursor().toggle(*bv_);
+       // First drawing step
+       updateMetrics(flags & Update::SinglePar);
 
-               // 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();
-       }
+       // The second drawing step is done in WorkArea::redraw() if needed.
+       bool const need_second_step =
+               (flags & (Update::Force | Update::FitCursor | Update::MultiParSel))
+               && (fitCursor() || multiParSel());
 
-       cursor_timeout.restart();
+       return need_second_step;
 }
 
 
@@ -780,7 +608,8 @@ void BufferView::Pimpl::savePosition(unsigned int i)
                                      cursor_.paragraph().id(),
                                      cursor_.pos());
        if (i > 0)
-               owner_->message(bformat(_("Saved bookmark %1$d"), i));
+               // emit message signal.
+               bv_->message(bformat(_("Saved bookmark %1$d"), i));
 }
 
 
@@ -813,7 +642,8 @@ void BufferView::Pimpl::restorePosition(unsigned int i)
        bv_->setCursor(makeDocIterator(par, min(par->size(), saved_positions[i].par_pos)));
 
        if (i > 0)
-               owner_->message(bformat(_("Moved to bookmark %1$d"), i));
+               // emit message signal.
+               bv_->message(bformat(_("Moved to bookmark %1$d"), i));
 }
 
 
@@ -867,7 +697,6 @@ void BufferView::Pimpl::center()
 }
 
 
-
 void BufferView::Pimpl::menuInsertLyXFile(string const & filenm)
 {
        BOOST_ASSERT(cursor_.inTexted());
@@ -878,7 +707,7 @@ void BufferView::Pimpl::menuInsertLyXFile(string const & filenm)
                string initpath = lyxrc.document_path;
 
                if (available()) {
-                       string const trypath = owner_->buffer()->filePath();
+                       string const trypath = buffer_->filePath();
                        // If directory is writeable, use this as default.
                        if (isDirWriteable(trypath))
                                initpath = trypath;
@@ -903,7 +732,8 @@ void BufferView::Pimpl::menuInsertLyXFile(string const & filenm)
 
                // check selected filename
                if (filename.empty()) {
-                       owner_->message(_("Canceled."));
+                       // emit message signal.
+                       bv_->message(_("Canceled."));
                        return;
                }
        }
@@ -913,20 +743,24 @@ void BufferView::Pimpl::menuInsertLyXFile(string const & filenm)
        filename = fileSearch(string(), filename, "lyx");
 
        string const disp_fn = makeDisplayPath(filename);
-       owner_->message(bformat(_("Inserting document %1$s..."), disp_fn));
+       // emit message signal.
+       bv_->message(bformat(_("Inserting document %1$s..."), disp_fn));
 
        string res;
        Buffer buf("", false);
-       buf.error.connect(boost::bind(&BufferView::Pimpl::addError, this, _1));
        if (::loadLyXFile(&buf, makeAbsPath(filename))) {
+               ErrorList & el = buffer_->errorList("Parse");
+               // Copy the inserted document error list into the current buffer one.
+               el = buf.errorList("Parse");
                lyx::cap::pasteParagraphList(cursor_, buf.paragraphs(),
-                                            buf.params().textclass);
+                                            buf.params().textclass, el);
                res = _("Document %1$s inserted.");
        } else
                res = _("Could not insert document %1$s");
 
-       owner_->message(bformat(res, disp_fn));
-       bv_->showErrorList(_("Document insertion"));
+       // emit message signal.
+       bv_->message(bformat(res, disp_fn));
+       buffer_->errors("Parse");
        resizeCurrentBuffer();
 }
 
@@ -969,12 +803,6 @@ bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0)
        // LFUN_FILE_OPEN generated by drag-and-drop.
        FuncRequest cmd = cmd0;
 
-       // Handle drag&drop
-       if (cmd.action == LFUN_FILE_OPEN) {
-               owner_->dispatch(cmd);
-               return true;
-       }
-
        if (!buffer_)
                return false;
 
@@ -989,8 +817,6 @@ bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0)
        if (!available())
                return false;
 
-       owner_->gui().guiCursor().hide();
-
        // Either the inset under the cursor or the
        // surrounding LyXText will handle this event.
 
@@ -1025,20 +851,6 @@ bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0)
                        update(Update::FitCursor | Update::MultiParSel);
        }
 
-       // See workAreaKeyPress
-       cursor_timeout.restart();
-       owner_->gui().guiCursor().show(*bv_);
-
-       // Skip these when selecting
-       if (cmd.action != LFUN_MOUSE_MOTION) {
-               owner_->updateLayoutChoice();
-               owner_->updateToolbars();
-       }
-
-       // Slight hack: this is only called currently when we
-       // clicked somewhere, so we force through the display
-       // of the new status here.
-       owner_->clearMessage();
        return true;
 }
 
@@ -1070,7 +882,6 @@ FuncStatus BufferView::Pimpl::getStatus(FuncRequest const & cmd)
        case LFUN_OUTLINE_DOWN:
        case LFUN_OUTLINE_IN:
        case LFUN_OUTLINE_OUT:
-       case LFUN_ERROR_NEXT:
        case LFUN_NOTE_NEXT:
        case LFUN_REFERENCE_NEXT:
        case LFUN_WORD_FIND:
@@ -1082,6 +893,7 @@ FuncStatus BufferView::Pimpl::getStatus(FuncRequest const & cmd)
        case LFUN_BIBTEX_DATABASE_ADD:
        case LFUN_BIBTEX_DATABASE_DEL:
        case LFUN_WORDS_COUNT:
+       case LFUN_NEXT_INSET_TOGGLE:
                flag.enabled(true);
                break;
 
@@ -1250,10 +1062,6 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
                updateLabels(*buffer_);
                break;
 
-       case LFUN_ERROR_NEXT:
-               bv_funcs::gotoInset(bv_, InsetBase::ERROR_CODE, false);
-               break;
-
        case LFUN_NOTE_NEXT:
                bv_funcs::gotoInset(bv_, InsetBase::NOTE_CODE, false);
                break;
@@ -1398,6 +1206,30 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
                buffer_->params().compressed = !buffer_->params().compressed;
                break;
 
+       case LFUN_NEXT_INSET_TOGGLE: {
+               // this is the real function we want to invoke
+               FuncRequest tmpcmd = FuncRequest(LFUN_INSET_TOGGLE, cmd.origin);
+               // if there is an inset at cursor, see whether it
+               // wants to toggle.
+               InsetBase * inset = cur.nextInset();
+               if (inset && inset->isActive()) {
+                       LCursor tmpcur = cur;
+                       tmpcur.pushLeft(*inset);
+                       inset->dispatch(tmpcur, tmpcmd);
+                       if (tmpcur.result().dispatched()) {
+                               cur.dispatched();
+                       }
+               }
+               // if it did not work, try the underlying inset.
+               if (!cur.result().dispatched())
+                       cur.dispatch(tmpcmd);
+
+               if (cur.result().dispatched()) 
+                       cur.clearSelection();
+               
+               break;
+       }
+
        default:
                return false;
        }
@@ -1474,16 +1306,18 @@ void BufferView::Pimpl::updateMetrics(bool singlepar)
 
        // The coordinates of all these paragraphs are correct, cache them
        int y = y1;
+       CoordCache::InnerParPosCache & parPos = theCoords.parPos()[text];
        for (lyx::pit_type pit = pit1; pit <= pit2; ++pit) {
-               y += text->getPar(pit).ascent();
-               theCoords.parPos()[text][pit] = Point(0, y);
+               Paragraph const & par = text->getPar(pit);
+               y += par.ascent();
+               parPos[pit] = Point(0, y);
                if (singlepar && pit == cursor_.bottom().pit()) {
                        // In Single Paragraph mode, collect here the
                        // y1 and y2 of the (one) paragraph the cursor is in
-                       y1 = y - text->getPar(pit).ascent();
-                       y2 = y + text->getPar(pit).descent();
+                       y1 = y - par.ascent();
+                       y2 = y + par.descent();
                }
-               y += text->getPar(pit).descent();
+               y += par.descent();
        }
 
        if (singlepar) {