Abdelrazak Younes wrote:
Jean-Marc Lasgouttes wrote:
"Abdelrazak" == Abdelrazak Younes <[EMAIL PROTECTED]> writes:

Abdelrazak> Stefan Schimanski wrote:
The attached patch fixes that. It should fix also a number of
other situation where cursor may be invalidated. I had to add a
test in Cursor::fixIfBroken() for the case were we are not inside
an Inset but in the main Text.
 Nice! Testing it for a few minutes now. Looks fine. Couldn't cause
a crash yet.

Abdelrazak> I need a second OK. JMarc?

The general idea is correct, but...

Originally, fixIfBroken got the cursor out of insets when coordinates
were different. Now you add a different test at level 1 the just
resets the values. It would be better to rewrite fixIfBroken to do at
each level

- go out of the inset if the value of cur.inset() is not correct wrt
  previous level.

How can I do that? If I erase an inset in one view while the cursor was in this very inset in the other view, how can I know that the inset the CursorSlice is referring to has been deleted?

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' D:\devel\lyx\trunk\boost\boost/noncopyable.hpp(28) : see declaration of 'boost::noncopyable_::noncopyable::operator =' D:\devel\lyx\trunk\boost\boost/noncopyable.hpp(22) : see declaration of 'boost::noncopyable_::noncopyable' This diagnostic occurred in the compiler generated function 'boost::signals::detail::signal_base &boost::signals::detail::signal_base::operator =(const boost::signals::detail::signal_base &)'
InsetMathRef.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' D:\devel\lyx\trunk\boost\boost/noncopyable.hpp(28) : see declaration of 'boost::noncopyable_::noncopyable::operator =' D:\devel\lyx\trunk\boost\boost/noncopyable.hpp(22) : see declaration of 'boost::noncopyable_::noncopyable' This diagnostic occurred in the compiler generated function 'boost::signals::detail::signal_base &boost::signals::detail::signal_base::operator =(const boost::signals::detail::signal_base &)'
InsetMathHull.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' D:\devel\lyx\trunk\boost\boost/noncopyable.hpp(28) : see declaration of 'boost::noncopyable_::noncopyable::operator =' D:\devel\lyx\trunk\boost\boost/noncopyable.hpp(22) : see declaration of 'boost::noncopyable_::noncopyable' This diagnostic occurred in the compiler generated function 'boost::signals::detail::signal_base &boost::signals::detail::signal_base::operator =(const boost::signals::detail::signal_base &)'
Generating Code...

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)
@@ -38,9 +38,23 @@
        : inset_(&p), idx_(0), pit_(0), pos_(0)
 {
        BOOST_ASSERT(inset_);
+       inset_->destroyed.connect(
+                       boost::bind(&CursorSlice::invalidate, 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;
@@ -51,6 +53,8 @@
        CursorSlice();
        ///
        explicit CursorSlice(Inset &);
+       ///
+       bool isValid() const;
 
        /// the current inset
        Inset & inset() const { return *inset_; }
@@ -117,6 +121,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)
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.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>
 
@@ -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,6 +475,9 @@
        //
        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);

Reply via email to