]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.C
update comments.
[lyx.git] / src / BufferView.C
index cd8e79892a3ee8831de55de3c82f513e49117e91..154755c15e0105b13c812fe3866b6af956101bb1 100644 (file)
@@ -20,6 +20,7 @@
 #include "buffer_funcs.h"
 #include "bufferlist.h"
 #include "bufferparams.h"
+#include "bufferview_funcs.h"
 #include "coordcache.h"
 #include "CutAndPaste.h"
 #include "debug.h"
@@ -88,7 +89,6 @@ using support::fileSearch;
 using support::isDirWriteable;
 using support::isFileReadable;
 using support::makeDisplayPath;
-using support::makeAbsPath;
 using support::package;
 
 using std::distance;
@@ -187,7 +187,7 @@ void BufferView::setBuffer(Buffer * b)
                                    << "Buffer addr: " << buffer_ << endl;
                cursor_.push(buffer_->inset());
                cursor_.resetAnchor();
-               buffer_->text().init(this);
+               updateLabels(*buffer_);
                buffer_->text().setCurrentFont(cursor_);
                if (buffer_->getCursor().size() > 0 &&
                    buffer_->getAnchor().size() > 0)
@@ -301,7 +301,6 @@ void BufferView::resize()
 
        lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << endl;
 
-       buffer_->text().init(this);
        updateMetrics(false);
        switchKeyMap();
 }
@@ -336,6 +335,10 @@ bool BufferView::multiParSel()
 
 bool BufferView::update(Update::flags flags)
 {
+       // last_inset_ points to the last visited inset. This pointer may become
+       // invalid because of keyboard editing. Since all such operations
+       // causes screen update(), I reset last_inset_ to avoid such a problem.
+       last_inset_ = 0;
        // This is close to a hot-path.
        if (lyxerr.debugging(Debug::DEBUG)) {
                lyxerr[Debug::DEBUG]
@@ -400,6 +403,8 @@ void BufferView::updateScrollbar()
        }
 
        LyXText & t = buffer_->text();
+       TextMetrics & tm = text_metrics_[&t];
+
        int const parsize = int(t.paragraphs().size() - 1);
        if (anchor_ref_ >  parsize)  {
                anchor_ref_ = parsize;
@@ -420,13 +425,14 @@ void BufferView::updateScrollbar()
        // estimated average paragraph height:
        if (wh_ == 0)
                wh_ = height_ / 4;
-       int h = t.getPar(anchor_ref_).height();
+
+       int h = tm.parMetrics(anchor_ref_).height();
 
        // Normalize anchor/offset (MV):
        while (offset_ref_ > h && anchor_ref_ < parsize) {
                anchor_ref_++;
                offset_ref_ -= h;
-               h = t.getPar(anchor_ref_).height();
+               h = tm.parMetrics(anchor_ref_).height();
        }
        // Look at paragraph heights on-screen
        int sumh = 0;
@@ -434,7 +440,7 @@ void BufferView::updateScrollbar()
        for (pit_type pit = anchor_ref_; pit <= parsize; ++pit) {
                if (sumh > height_)
                        break;
-               int const h2 = t.getPar(pit).height();
+               int const h2 = tm.parMetrics(pit).height();
                sumh += h2;
                nh++;
        }
@@ -467,14 +473,16 @@ void BufferView::scrollDocView(int value)
                return;
 
        LyXText & t = buffer_->text();
+       TextMetrics & tm = text_metrics_[&t];
 
        float const bar = value / float(wh_ * t.paragraphs().size());
 
        anchor_ref_ = int(bar * t.paragraphs().size());
        if (anchor_ref_ >  int(t.paragraphs().size()) - 1)
                anchor_ref_ = int(t.paragraphs().size()) - 1;
-       t.redoParagraph(*this, anchor_ref_);
-       int const h = t.getPar(anchor_ref_).height();
+
+       tm.redoParagraph(anchor_ref_);
+       int const h = tm.parMetrics(anchor_ref_).height();
        offset_ref_ = int((bar * t.paragraphs().size() - anchor_ref_) * h);
        updateMetrics(false);
 }
@@ -571,12 +579,13 @@ int BufferView::workWidth() const
 void BufferView::center()
 {
        CursorSlice & bot = cursor_.bottom();
+       TextMetrics & tm = text_metrics_[bot.text()];
        pit_type const pit = bot.pit();
-       bot.text()->redoParagraph(*this, pit);
-       Paragraph const & par = bot.text()->paragraphs()[pit];
+       tm.redoParagraph(pit);
+       ParagraphMetrics const & pm = tm.parMetrics(pit);
        anchor_ref_ = pit;
        offset_ref_ = bv_funcs::coordOffset(*this, cursor_, cursor_.boundary()).y_
-               + par.ascent() - height_ / 2;
+               + pm.ascent() - height_ / 2;
 }
 
 
@@ -1007,20 +1016,22 @@ void BufferView::clearSelection()
        if (buffer_) {
                cursor_.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();
        }
 }
 
 
 void BufferView::workAreaResize(int width, int height)
 {
-       // A resize is triggered whenever a window gets focus,
-       // because of the shared rows() of a buffer in multiple
-       // buffer views.
-       
        // Update from work area
        width_ = width;
        height_ = height;
 
+       // The complete text metrics will be redone.
+       text_metrics_.clear();
+
        if (buffer_)
                resize();
 }
@@ -1141,8 +1152,6 @@ void BufferView::scroll(int /*lines*/)
 //
 //     scrollDocView(new_top_y);
 //
-//     // Update the scrollbar.
-//     workArea_->setScrollbarParams(t->height(), top_y(), defaultRowHeight());}
 }
 
 
@@ -1190,6 +1199,30 @@ LyXText const * BufferView::getLyXText() const
 }
 
 
+TextMetrics const & BufferView::textMetrics(LyXText const * t) const
+{
+       return const_cast<BufferView *>(this)->textMetrics(t);
+}
+
+
+TextMetrics & BufferView::textMetrics(LyXText const * t)
+{
+       TextMetricsCache::iterator tmc_it  = text_metrics_.find(t);
+       if (tmc_it == text_metrics_.end()) {
+               tmc_it = text_metrics_.insert(
+                       make_pair(t, TextMetrics(this, const_cast<LyXText *>(t)))).first;
+       }       
+       return tmc_it->second;
+}
+
+
+ParagraphMetrics const & BufferView::parMetrics(LyXText const * t,
+               pit_type pit) const
+{
+       return textMetrics(t).parMetrics(pit);
+}
+
+
 int BufferView::workHeight() const
 {
        return height_;
@@ -1207,6 +1240,28 @@ void BufferView::setCursor(DocIterator const & dit)
 }
 
 
+bool BufferView::checkDepm(LCursor & cur, LCursor & old)
+{
+       // Would be wrong to delete anything if we have a selection.
+       if (cur.selection())
+               return false;
+
+       bool need_anchor_change = false;
+       bool changed = cursor_.text()->deleteEmptyParagraphMechanism(cur, old,
+               need_anchor_change);
+
+       if (need_anchor_change)
+               cur.resetAnchor();
+       
+       if (!changed)
+               return false;
+
+       updateMetrics(false);
+       buffer_->changed();
+       return true;
+}
+
+
 bool BufferView::mouseSetCursor(LCursor & cur)
 {
        BOOST_ASSERT(&cur.bv() == this);
@@ -1220,7 +1275,7 @@ bool BufferView::mouseSetCursor(LCursor & cur)
        // FIXME: move this to InsetText::notifyCursorLeaves?
        bool update = false;
        if (!badcursor && cursor_.inTexted())
-               update = cursor_.text()->deleteEmptyParagraphMechanism(cur, cursor_);
+               checkDepm(cur, cursor_);
 
        cursor_ = cur;
        cursor_.clearSelection();
@@ -1271,47 +1326,56 @@ ViewMetricsInfo const & BufferView::viewMetricsInfo()
 }
 
 
+// FIXME: We should split-up updateMetrics() for the singlepar case.
 void BufferView::updateMetrics(bool singlepar)
 {
-       // Clear out the position cache in case of full screen redraw.
-       if (!singlepar)
-               coord_cache_.clear();
-
        LyXText & buftext = buffer_->text();
+       TextMetrics & tm = textMetrics(&buftext);
        pit_type size = int(buftext.paragraphs().size());
 
        if (anchor_ref_ > int(buftext.paragraphs().size() - 1)) {
                anchor_ref_ = int(buftext.paragraphs().size() - 1);
                offset_ref_ = 0;
        }
+       
+       // If the paragraph metrics has changed, we can not
+       // use the singlepar optimisation.
+       if (singlepar
+               // In Single Paragraph mode, rebreak only
+               // the (main text, not inset!) paragraph containing the cursor.
+               // (if this paragraph contains insets etc., rebreaking will
+               // recursively descend)
+               && tm.redoParagraph(cursor_.bottom().pit()))
+               singlepar = false;
 
        pit_type const pit = anchor_ref_;
        int pit1 = pit;
        int pit2 = pit;
        size_t const npit = buftext.paragraphs().size();
 
-       // Rebreak anchor paragraph. In Single Paragraph mode, rebreak only
-       // the (main text, not inset!) paragraph containing the cursor.
-       // (if this paragraph contains insets etc., rebreaking will
-       // recursively descend)
-       if (!singlepar || pit == cursor_.bottom().pit())
-               buftext.redoParagraph(*this, pit);
-       int y0 = buftext.getPar(pit).ascent() - offset_ref_;
+       // Rebreak anchor paragraph.
+       if (!singlepar)
+               tm.redoParagraph(pit);
+       
+       // Clear out the position cache in case of full screen redraw.
+       if (!singlepar)
+               coord_cache_.clear();
+
+       int y0 = tm.parMetrics(pit).ascent() - offset_ref_;
 
-       // Redo paragraphs above anchor if necessary; again, in Single Par
-       // mode, only if we encounter the (main text) one having the cursor.
+       // Redo paragraphs above anchor if necessary.
        int y1 = y0;
        while (y1 > 0 && pit1 > 0) {
-               y1 -= buftext.getPar(pit1).ascent();
+               y1 -= tm.parMetrics(pit1).ascent();
                --pit1;
-               if (!singlepar || pit1 == cursor_.bottom().pit())
-                       buftext.redoParagraph(*this, pit1);
-               y1 -= buftext.getPar(pit1).descent();
+               if (!singlepar)
+                       tm.redoParagraph(pit1);
+               y1 -= tm.parMetrics(pit1).descent();
        }
 
 
        // Take care of ascent of first line
-       y1 -= buftext.getPar(pit1).ascent();
+       y1 -= tm.parMetrics(pit1).ascent();
 
        // Normalize anchor for next time
        anchor_ref_ = pit1;
@@ -1324,34 +1388,33 @@ void BufferView::updateMetrics(bool singlepar)
                anchor_ref_ = 0;
        }
 
-       // Redo paragraphs below the anchor if necessary. Single par mode:
-       // only the one containing the cursor if encountered.
+       // Redo paragraphs below the anchor if necessary.
        int y2 = y0;
        while (y2 < height_ && pit2 < int(npit) - 1) {
-               y2 += buftext.getPar(pit2).descent();
+               y2 += tm.parMetrics(pit2).descent();
                ++pit2;
-               if (!singlepar || pit2 == cursor_.bottom().pit())
-                       buftext.redoParagraph(*this, pit2);
-               y2 += buftext.getPar(pit2).ascent();
+               if (!singlepar)
+                       tm.redoParagraph(pit2);
+               y2 += tm.parMetrics(pit2).ascent();
        }
 
        // Take care of descent of last line
-       y2 += buftext.getPar(pit2).descent();
+       y2 += tm.parMetrics(pit2).descent();
 
        // The coordinates of all these paragraphs are correct, cache them
        int y = y1;
        CoordCache::InnerParPosCache & parPos = coord_cache_.parPos()[&buftext];
        for (pit_type pit = pit1; pit <= pit2; ++pit) {
-               Paragraph const & par = buftext.getPar(pit);
-               y += par.ascent();
+               ParagraphMetrics const & pm = tm.parMetrics(pit);
+               y += pm.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 - par.ascent();
-                       y2 = y + par.descent();
+                       y1 = y - pm.ascent();
+                       y2 = y + pm.descent();
                }
-               y += par.descent();
+               y += pm.descent();
        }
 
        if (singlepar) {
@@ -1393,7 +1456,7 @@ void BufferView::menuInsertLyXFile(string const & filenm)
                if (buffer_) {
                        string const trypath = buffer_->filePath();
                        // If directory is writeable, use this as default.
-                       if (isDirWriteable(trypath))
+                       if (isDirWriteable(FileName(trypath)))
                                initpath = trypath;
                }
 
@@ -1449,5 +1512,4 @@ void BufferView::menuInsertLyXFile(string const & filenm)
        resize();
 }
 
-
 } // namespace lyx