Angus Leeming wrote:
Abdelrazak Younes <[EMAIL PROTECTED]> writes:
The only simple solution I can think of right now is to emit a signal in the Inset destructor that we can connect to the CursorSlice. The CursorSlice will then invalidate itself.
Here is what I came up with. In principle this should solve all problems of invalid cursors. Unfortunately it doesn't compile... somebody has an idea why?

Compiling...
MathMacroTemplate.cpp
D:\devel\lyx\trunk\boost\boost/signals/detail/signal_base.hpp(150) : error C2248: 'boost::noncopyable_::noncopyable::operator =' : cannot access private member declared in class 'boost::noncopyable_::noncopyable'

You can't copy boost::signals. That means that either you're going to have to define a copy constructor for the Inset holding the signal member or you need to define a NonCopyableSignal wrapper to boost::signal that defines a no-op copy constructor...

Here is the updated patch. Fully working, well tested.

OK?

Abdel.


Index: BufferView.cpp
===================================================================
--- BufferView.cpp      (revision 18473)
+++ BufferView.cpp      (working copy)
@@ -215,6 +215,10 @@
                        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();
                }
        }
 
Index: Cursor.cpp
===================================================================
--- Cursor.cpp  (revision 18473)
+++ Cursor.cpp  (working copy)
@@ -1299,44 +1299,10 @@
 
 void Cursor::fixIfBroken()
 {
-       // find out last good level
-       Cursor copy = *this;
-       size_t newdepth = depth();
-       while (!copy.empty()) {
-               if (copy.idx() > copy.lastidx()) {
-                       lyxerr << "wrong idx " << copy.idx()
-                              << ", max is " << copy.lastidx()
-                              << " at level " << copy.depth()
-                              << ". Trying to correct this."  << endl;
-                       lyxerr << "old: " << *this << endl;
-                       newdepth = copy.depth() - 1;
-               }
-               else if (copy.pit() > copy.lastpit()) {
-                       lyxerr << "wrong pit " << copy.pit()
-                              << ", max is " << copy.lastpit()
-                              << " at level " << copy.depth()
-                              << ". Trying to correct this."  << endl;
-                       lyxerr << "old: " << *this << endl;
-                       newdepth = copy.depth() - 1;
-               }
-               else if (copy.pos() > copy.lastpos()) {
-                       lyxerr << "wrong pos " << copy.pos()
-                              << ", max is " << copy.lastpos()
-                              << " at level " << copy.depth()
-                              << ". Trying to correct this."  << endl;
-                       lyxerr << "old: " << *this << endl;
-                       newdepth = copy.depth() - 1;
-               }
-               copy.pop();
+       if (DocIterator::fixIfBroken()) {
+                       clearSelection();
+                       resetAnchor();
        }
-       // shrink cursor to a size where everything is valid, possibly
-       // leaving insets
-       while (depth() > newdepth) {
-               pop();
-               lyxerr << "correcting cursor to level " << depth() << endl;
-               lyxerr << "new: " << *this << endl;
-               clearSelection();
-       }
 }
 
 
Index: CursorSlice.cpp
===================================================================
--- CursorSlice.cpp     (revision 18473)
+++ CursorSlice.cpp     (working copy)
@@ -22,6 +22,7 @@
 #include "mathed/MathData.h"
 
 #include <boost/assert.hpp>
+#include <boost/bind.hpp>
 
 
 namespace lyx {
@@ -38,9 +39,44 @@
        : inset_(&p), idx_(0), pit_(0), pos_(0)
 {
        BOOST_ASSERT(inset_);
+       inset_->destroyed.connect(
+                       boost::bind(&CursorSlice::invalidate, this));
 }
 
 
+CursorSlice::CursorSlice(CursorSlice const & cs)
+{
+       operator=(cs);
+}
+
+
+CursorSlice & CursorSlice::operator=(CursorSlice const & cs)
+{
+       inset_ = cs.inset_;
+       idx_ = cs.idx_;
+       pit_ = cs.pit_;
+       pos_ = cs.pos_;
+       if (inset_) {
+               BOOST_ASSERT(inset_);
+               inset_->destroyed.connect(
+                       boost::bind(&CursorSlice::invalidate, this));
+       }
+       return *this;
+}
+
+
+void CursorSlice::invalidate()
+{
+       inset_ = 0;
+}
+
+
+bool CursorSlice::isValid() const
+{
+       return inset_ != 0;
+}
+
+
 MathData & CursorSlice::cell() const
 {
        return inset_->asInsetMath()->cell(idx_);
Index: CursorSlice.h
===================================================================
--- CursorSlice.h       (revision 18473)
+++ CursorSlice.h       (working copy)
@@ -20,6 +20,8 @@
 #include "support/types.h"
 #include "insets/Inset.h"
 
+#include <boost/signals/trackable.hpp>
+
 #include <cstddef>
 #include <iosfwd>
 
@@ -38,7 +40,7 @@
 // that of MathData and Text should vanish. They are conceptually the
 // same (now...)
 
-class CursorSlice {
+class CursorSlice : public boost::signals::trackable {
 public:
        /// type for cell number in inset
        typedef size_t idx_type;
@@ -50,7 +52,13 @@
        ///
        CursorSlice();
        ///
+       CursorSlice(CursorSlice const &);
+       ///
        explicit CursorSlice(Inset &);
+       ///
+       CursorSlice & operator=(CursorSlice const &);
+       ///
+       bool isValid() const;
 
        /// the current inset
        Inset & inset() const { return *inset_; }
@@ -117,6 +125,9 @@
        /// pointer to 'owning' inset. This is some kind of cache.
        Inset * inset_;
 private:
+       ///
+       void invalidate();
+
        /*!
         * Cell index of a position in this inset.
         * This is the primary cell information also for grid like insets,
Index: DocIterator.cpp
===================================================================
--- DocIterator.cpp     (revision 18473)
+++ DocIterator.cpp     (working copy)
@@ -558,6 +558,58 @@
 }
 
 
+bool DocIterator::fixIfBroken()
+{
+       bool fixed = false;
+       
+       for (size_t i = slices_.size() - 1; i != 0; --i)
+               if (!slices_[i].isValid()) {
+                       pop_back();
+                       fixed = true;
+               }
+
+       // The top level CursorSlice should always be valid. 
+       BOOST_ASSERT(slices_[0].isValid());
+
+       if (idx() > lastidx()) {
+               lyxerr << "wrong idx " << idx()
+                       << ", max is " << lastidx()
+                       << " at level " << depth()
+                       << ". Trying to correct this."  << endl;
+               lyxerr << "old: " << *this << endl;
+               for (size_t i = idx(); i != lastidx(); --i)
+                       pop_back();
+               idx() = lastidx();
+               pit() = lastpit();
+               pos() = lastpos();
+               fixed = true;
+       }
+       else if (pit() > lastpit()) {
+               lyxerr << "wrong pit " << pit()
+                       << ", max is " << lastpit()
+                       << " at level " << depth()
+                       << ". Trying to correct this."  << endl;
+               lyxerr << "old: " << *this << endl;
+               pit() = lastpit();
+               pos() = 0;
+               fixed = true;
+       }
+       else if (pos() > lastpos()) {
+               lyxerr << "wrong pos " << pos()
+                       << ", max is " << lastpos()
+                       << " at level " << depth()
+                       << ". Trying to correct this."  << endl;
+               lyxerr << "old: " << *this << endl;
+               pos() = lastpos();
+               fixed = true;
+       }
+       if (fixed) {
+               lyxerr << "new: " << *this << endl;
+       }
+       return fixed;
+}
+
+
 std::ostream & operator<<(std::ostream & os, DocIterator const & dit)
 {
        for (size_t i = 0, n = dit.depth(); i != n; ++i)
@@ -608,11 +660,12 @@
                if (inset == 0) {
                        // FIXME
                        lyxerr << BOOST_CURRENT_FUNCTION
-                              << " Should not happen, but does e.g. after C-n 
C-l C-z S-C-z"
+                              << " Should not happen, but does e.g. after C-n 
C-l C-z S-C-z\n"
+                                  << " or when a Buffer has been concurently 
edited by two views"
                                << '\n' << "dit: " << dit << '\n'
                                << " lastpos: " << dit.lastpos() << endl;
-                       //break;
-                       BOOST_ASSERT(false);
+                       dit.fixIfBroken();
+                       return dit;
                }
                dit.push_back(data_[i]);
                dit.top().inset_ = inset;
Index: DocIterator.h
===================================================================
--- DocIterator.h       (revision 18473)
+++ DocIterator.h       (working copy)
@@ -227,6 +227,9 @@
        void pop_back() { slices_.pop_back(); }
        /// recompute the inset parts of the cursor from the document data
        void updateInsets(Inset * inset);
+       /// fix DocIterator in circumstances that should never happen.
+       /// \return true if the DocIterator was fixed.
+       bool fixIfBroken();
 
 private:
        /**
Index: frontends/WorkArea.cpp
===================================================================
--- frontends/WorkArea.cpp      (revision 18473)
+++ frontends/WorkArea.cpp      (working copy)
@@ -140,9 +140,11 @@
 
        // 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();
+       }
 
        updateScrollbar();
 
Index: insets/Inset.cpp
===================================================================
--- insets/Inset.cpp    (revision 18473)
+++ insets/Inset.cpp    (working copy)
@@ -126,6 +126,14 @@
 {}
 
 
+Inset & Inset::operator=(Inset const & inset)
+{
+       dim_ = inset.dim_;
+       background_color_ = inset.background_color_;
+       return *this;
+}
+
+
 std::auto_ptr<Inset> Inset::clone() const
 {
        std::auto_ptr<Inset> b = doClone();
Index: insets/Inset.h
===================================================================
--- insets/Inset.h      (revision 18473)
+++ insets/Inset.h      (working copy)
@@ -20,6 +20,8 @@
 
 #include "support/docstream.h"
 
+#include <boost/signal.hpp>
+
 #include <memory>
 #include <vector>
 
@@ -54,7 +56,7 @@
 // everything storing large quantities of insets. Mathed e.g. would
 // suffer.
 
-class Inset {
+class Inset : public boost::noncopyable {
 public:
        ///
        typedef ptrdiff_t  difference_type;
@@ -70,7 +72,7 @@
        typedef size_t     col_type;
 
        /// virtual base class destructor
-       virtual ~Inset() {}
+       virtual ~Inset() { destroyed();}
        /// replicate ourselves
        std::auto_ptr<Inset> clone() const;
 
@@ -473,9 +475,14 @@
        //
        enum { TEXT_TO_INSET_OFFSET = 4 };
 
+       /// This signal is emitted when the inset is destroyed.
+       boost::signal<void()> destroyed;
+
 protected:
        Inset();
        Inset(Inset const & i);
+       ///
+       Inset & operator=(Inset const &);
        /** The real dispatcher.
         *  Gets normally called from Cursor::dispatch(). Cursor::dispatch()
         *  assumes the common case of 'LFUN handled, need update'.

Reply via email to