]> git.lyx.org Git - lyx.git/blobdiff - src/BufferView.cpp
Add empty InsetLayout for undefined cases. Should avoid possible bugs caused by empty...
[lyx.git] / src / BufferView.cpp
index 5859d577727be0cfc4e7ebed001e9ea7dfd87d19..9abb3d7d1f4a86f2f1d18dbfaa45a946d7149117 100644 (file)
@@ -69,7 +69,6 @@
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/ExceptionMessage.h"
-#include "support/FileFilterList.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
 #include "support/lstrings.h"
@@ -114,7 +113,7 @@ bool findNextInset(DocIterator & dit, vector<InsetCode> const & codes,
        while (tmpdit) {
                Inset const * inset = tmpdit.nextInset();
                if (inset
-                   && find(codes.begin(), codes.end(), inset->lyxCode()) != codes.end()
+                   && std::find(codes.begin(), codes.end(), inset->lyxCode()) != codes.end()
                    && (contents.empty() ||
                    static_cast<InsetCommand const *>(inset)->getFirstNonOptParam() == contents)) {
                        dit = tmpdit;
@@ -140,7 +139,7 @@ bool findInset(DocIterator & dit, vector<InsetCode> const & codes,
        if (same_content) {
                Inset const * inset = tmpdit.nextInset();
                if (inset
-                   && find(codes.begin(), codes.end(), inset->lyxCode()) != codes.end()) {
+                   && std::find(codes.begin(), codes.end(), inset->lyxCode()) != codes.end()) {
                        contents = static_cast<InsetCommand const *>(inset)->getFirstNonOptParam();
                }
        }
@@ -258,7 +257,7 @@ struct BufferView::Private
 
 
 BufferView::BufferView(Buffer & buf)
-       : width_(0), height_(0), buffer_(buf), d(new Private(*this))
+       : width_(0), height_(0), full_screen_(false), buffer_(buf), d(new Private(*this))
 {
        d->xsel_cache_.set = false;
        d->intl_.initKeyMapper(lyxrc.use_kbmap);
@@ -288,6 +287,24 @@ BufferView::~BufferView()
 }
 
 
+int BufferView::rightMargin() const
+{
+       // The additional test for the case the outliner is opened.
+       if (!full_screen_ ||
+               !lyxrc.full_screen_limit ||
+               width_ < lyxrc.full_screen_width + 20)
+                       return 10;
+
+       return (width_ - lyxrc.full_screen_width) / 2;
+}
+
+
+int BufferView::leftMargin() const
+{
+       return rightMargin();
+}
+
+
 Intl & BufferView::getIntl()
 {
        return d->intl_;
@@ -417,6 +434,11 @@ void BufferView::updateScrollbar()
        if (height_ == 0)
                return;
 
+       // We prefer fixed size line scrolling.
+       d->scrollbarParameters_.single_step = defaultRowHeight();
+       // We prefer full screen page scrolling.
+       d->scrollbarParameters_.page_step = height_;
+
        Text & t = buffer_.text();
        TextMetrics & tm = d->text_metrics_[&t];                
 
@@ -425,7 +447,7 @@ void BufferView::updateScrollbar()
                << " curr par: " << d->cursor_.bottom().pit()
                << " default height " << defaultRowHeight());
 
-       int const parsize = int(t.paragraphs().size());
+       size_t const parsize = t.paragraphs().size();
        if (d->par_height_.size() != parsize) {
                d->par_height_.clear();
                // FIXME: We assume a default paragraph height of 2 rows. This
@@ -433,45 +455,35 @@ void BufferView::updateScrollbar()
                d->par_height_.resize(parsize, defaultRowHeight() * 2);
        }
 
-       // It would be better to fix the scrollbar to understand
-       // values in [0..1] and divide everything by wh
-
        // Look at paragraph heights on-screen
-       pit_type first_visible_pit = -1;
        pair<pit_type, ParagraphMetrics const *> first = tm.first();
        pair<pit_type, ParagraphMetrics const *> last = tm.last();
        for (pit_type pit = first.first; pit <= last.first; ++pit) {
-               ParagraphMetrics const & pm = tm.parMetrics(pit);
-               d->par_height_[pit] = pm.height();
-               if (first_visible_pit >= 0 || pm.position() + pm.descent() <= 0)
-                       continue;
-               first_visible_pit = pit;
-               LYXERR(Debug::SCROLLING, "first visible pit " << first_visible_pit);
-               // FIXME: we should look for the first visible row within
-               // the deepest inset!
-               int row_pos = pm.position();
-               size_t const nrows = pm.rows().size();
-               for (size_t i = 0; i != nrows; ++i) {
-                       Row const & row = pm.rows()[i];
-                       if (row_pos >= 0) {
-                               LYXERR(Debug::SCROLLING, "first visible row " << i
-                                       << "(row pos = " << row_pos << ");");
-                               break;
-                       }
-                       row_pos += row.height();
-               }
-               d->scrollbarParameters_.position = row_pos;
+               d->par_height_[pit] = tm.parMetrics(pit).height();
+               LYXERR(Debug::SCROLLING, "storing height for pit " << pit << " : "
+                       << d->par_height_[pit]);
        }
 
-       d->scrollbarParameters_.height = 0;
-       for (size_t i = 0; i != d->par_height_.size(); ++i) {
-               if (i == first_visible_pit)
-                       d->scrollbarParameters_.position += d->scrollbarParameters_.height;
-               d->scrollbarParameters_.height += d->par_height_[i];
+       int top_pos = first.second->position() - first.second->ascent();
+       int bottom_pos = last.second->position() + last.second->descent();
+       bool first_visible = first.first == 0 && top_pos >= 0;
+       bool last_visible = last.first + 1 == int(parsize) && bottom_pos <= height_;
+       if (first_visible && last_visible) {
+               d->scrollbarParameters_.min = 0;
+               d->scrollbarParameters_.max = 0;
+               return;
        }
 
-       // We prefer fixed size line scrolling.
-       d->scrollbarParameters_.lineScrollHeight = defaultRowHeight();
+       d->scrollbarParameters_.min = top_pos;
+       for (size_t i = 0; i != size_t(first.first); ++i)
+               d->scrollbarParameters_.min -= d->par_height_[i];
+       d->scrollbarParameters_.max = bottom_pos;
+       for (size_t i = last.first + 1; i != parsize; ++i)
+               d->scrollbarParameters_.max += d->par_height_[i];
+
+       d->scrollbarParameters_.position = 0;
+       // The reference is the top position so we remove one page.
+       d->scrollbarParameters_.max -= d->scrollbarParameters_.page_step;
 }
 
 
@@ -513,22 +525,44 @@ void BufferView::scrollDocView(int value)
                return;
        }
 
-       int par_pos = 0;
-       for (size_t i = 0; i != d->par_height_.size(); ++i) {
+       // cut off at the top
+       if (value <= d->scrollbarParameters_.min) {
+               DocIterator dit = doc_iterator_begin(buffer_.inset());
+               showCursor(dit);
+               LYXERR(Debug::SCROLLING, "scroll to top");
+               return;
+       }
+
+       // cut off at the bottom
+       if (value >= d->scrollbarParameters_.max) {
+               DocIterator dit = doc_iterator_end(buffer_.inset());
+               dit.backwardPos();
+               showCursor(dit);
+               LYXERR(Debug::SCROLLING, "scroll to bottom");
+               return;
+       }
+
+       // find paragraph at target position
+       int par_pos = d->scrollbarParameters_.min;
+       pit_type i = 0;
+       for (; i != int(d->par_height_.size()); ++i) {
                par_pos += d->par_height_[i];
-               if (par_pos >= value) {
-                       d->anchor_pit_ = pit_type(i);
+               if (par_pos >= value)
                        break;
-               }
        }
 
-       LYXERR(Debug::SCROLLING, "value = " << value
-               << "\tanchor_ref_ = " << d->anchor_pit_
-               << "\tpar_pos = " << par_pos);
+       if (par_pos < value) {
+               // It seems we didn't find the correct pit so stay on the safe side and
+               // scroll to bottom.
+               LYXERR0("scrolling position not found!");
+               scrollDocView(d->scrollbarParameters_.max);
+               return;
+       }
 
-       d->anchor_ypos_ = par_pos - value;
-       updateMetrics();
-       buffer_.changed();
+       DocIterator dit = doc_iterator_begin(buffer_.inset());
+       dit.pit() = i;
+       LYXERR(Debug::SCROLLING, "value = " << value << " -> scroll to pit " << i);
+       showCursor(dit);
 }
 
 
@@ -615,7 +649,7 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
        int top_id, pos_type top_pos)
 {
        bool success = false;
-       DocIterator doc_it;
+       DocIterator dit;
 
        d->cursor_.clearSelection();
 
@@ -623,19 +657,19 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
        // 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()) {
-                       doc_it = makeDocIterator(par, min(par->size(), top_pos));
+               dit = buffer_.getParFromID(top_id);
+               if (!dit.atEnd()) {
+                       dit.pos() = min(dit.paragraph().size(), top_pos);
                        // Some slices of the iterator may not be
                        // reachable (e.g. closed collapsable inset)
                        // so the dociterator may need to be
                        // shortened. Otherwise, setCursor may crash
                        // lyx when the cursor can not be set to these
                        // insets.
-                       size_t const n = doc_it.depth();
+                       size_t const n = dit.depth();
                        for (size_t i = 0; i < n; ++i)
-                               if (doc_it[i].inset().editable() != Inset::HIGHLY_EDITABLE) {
-                                       doc_it.resize(i);
+                               if (dit[i].inset().editable() != Inset::HIGHLY_EDITABLE) {
+                                       dit.resize(i);
                                        break;
                                }
                        success = true;
@@ -648,16 +682,17 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos,
        // 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()) {
-               doc_it = doc_iterator_begin(buffer_.inset());
-               doc_it.pit() = bottom_pit;
-               doc_it.pos() = min(bottom_pos, doc_it.paragraph().size());
+       if (bottom_pit < int(buffer_.paragraphs().size())) {
+               dit = doc_iterator_begin(buffer_.inset());
+                               
+               dit.pit() = bottom_pit;
+               dit.pos() = min(bottom_pos, dit.paragraph().size());
                success = true;
        }
 
        if (success) {
                // Note: only bottom (document) level pit is set.
-               setCursor(doc_it);
+               setCursor(dit);
                // set the current font.
                d->cursor_.setCurrentFont();
                // To center the screen on this new position we need the
@@ -695,6 +730,12 @@ int BufferView::workWidth() const
 
 
 void BufferView::showCursor()
+{
+       showCursor(d->cursor_);
+}
+
+
+void BufferView::showCursor(DocIterator const & dit)
 {
        // We are not properly started yet, delay until resizing is
        // done.
@@ -703,11 +744,11 @@ void BufferView::showCursor()
 
        LYXERR(Debug::SCROLLING, "recentering!");
 
-       CursorSlice & bot = d->cursor_.bottom();
+       CursorSlice const & bot = dit.bottom();
        TextMetrics & tm = d->text_metrics_[bot.text()];
 
        pos_type const max_pit = pos_type(bot.text()->paragraphs().size() - 1);
-       int bot_pit = d->cursor_.bottom().pit();
+       int bot_pit = bot.pit();
        if (bot_pit > max_pit) {
                // FIXME: Why does this happen?
                LYXERR0("bottom pit is greater that max pit: "
@@ -722,9 +763,13 @@ void BufferView::showCursor()
 
        if (tm.has(bot_pit)) {
                ParagraphMetrics const & pm = tm.parMetrics(bot_pit);
-               int offset = coordOffset(d->cursor_, d->cursor_.boundary()).y_;
+               BOOST_ASSERT(!pm.rows().empty());
+               // FIXME: smooth scrolling doesn't work in mathed.
+               CursorSlice const & cs = dit.innerTextSlice();
+               int offset = coordOffset(dit, dit.boundary()).y_;
                int ypos = pm.position() + offset;
-               Dimension const & row_dim = d->cursor_.textRow().dimension();
+               Dimension const & row_dim =
+                       pm.getRow(cs.pos(), dit.boundary()).dimension();
                if (ypos - row_dim.ascent() < 0)
                        scrollUp(- ypos + row_dim.ascent());
                else if (ypos + row_dim.descent() > height_)
@@ -735,10 +780,12 @@ void BufferView::showCursor()
 
        tm.redoParagraph(bot_pit);
        ParagraphMetrics const & pm = tm.parMetrics(bot_pit);
-       int offset = coordOffset(d->cursor_, d->cursor_.boundary()).y_;
+       int offset = coordOffset(dit, dit.boundary()).y_;
 
        d->anchor_pit_ = bot_pit;
-       Dimension const & row_dim = d->cursor_.textRow().dimension();
+       CursorSlice const & cs = dit.innerTextSlice();
+       Dimension const & row_dim =
+               pm.getRow(cs.pos(), dit.boundary()).dimension();
 
        if (d->anchor_pit_ == 0)
                d->anchor_ypos_ = offset + pm.ascent();
@@ -848,7 +895,7 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd)
 
        case LFUN_LAYOUT:
        case LFUN_LAYOUT_PARAGRAPH:
-               flag.enabled(cur.inset().forceDefaultParagraphs(cur.idx()));
+               flag.enabled(cur.inset().allowParagraphCustomization(cur.idx()));
                break;
 
        case LFUN_INSET_SETTINGS: {
@@ -969,27 +1016,27 @@ bool BufferView::dispatch(FuncRequest const & cmd)
                for (Buffer * b = &buffer_; i == 0 || b != &buffer_;
                        b = theBufferList().next(b)) {
 
-                       ParIterator par = b->getParFromID(id);
-                       if (par == b->par_iterator_end()) {
+                       DocIterator dit = b->getParFromID(id);
+                       if (dit.atEnd()) {
                                LYXERR(Debug::INFO, "No matching paragraph found! [" << id << "].");
+                               ++i;
+                               continue;
+                       }
+                       LYXERR(Debug::INFO, "Paragraph " << dit.paragraph().id()
+                               << " found in buffer `"
+                               << b->absFileName() << "'.");
+
+                       if (b == &buffer_) {
+                               // Set the cursor
+                               setCursor(dit);
+                               processUpdateFlags(Update::Force | Update::FitCursor);
                        } else {
-                               LYXERR(Debug::INFO, "Paragraph " << par->id()
-                                       << " found in buffer `"
-                                       << b->absFileName() << "'.");
-
-                               if (b == &buffer_) {
-                                       // Set the cursor
-                                       setCursor(makeDocIterator(par, 0));
-                                       showCursor();
-                               } else {
-                                       // Switch to other buffer view and resend cmd
-                                       theLyXFunc().dispatch(FuncRequest(
-                                               LFUN_BUFFER_SWITCH, b->absFileName()));
-                                       theLyXFunc().dispatch(cmd);
-                               }
-                               break;
+                               // Switch to other buffer view and resend cmd
+                               theLyXFunc().dispatch(FuncRequest(
+                                       LFUN_BUFFER_SWITCH, b->absFileName()));
+                               theLyXFunc().dispatch(cmd);
                        }
-                       ++i;
+                       break;
                }
                break;
        }
@@ -1062,7 +1109,10 @@ bool BufferView::dispatch(FuncRequest const & cmd)
                break;
 
        case LFUN_WORD_FIND:
-               find(this, cmd);
+               if (find(this, cmd))
+                       showCursor();
+               else
+                       message(_("String not found!"));
                break;
 
        case LFUN_WORD_REPLACE: {
@@ -1148,23 +1198,26 @@ bool BufferView::dispatch(FuncRequest const & cmd)
                int const chars_blanks = countChars(from, to, true);
                docstring message;
                if (cur.selection())
-                       message = _("Statistics for the selection:\n");
+                       message = _("Statistics for the selection:");
                else
-                       message = _("Statistics for the document:\n");
+                       message = _("Statistics for the document:");
+               message += "\n\n";
                if (words != 1)
-                       message += bformat(_("\n%1$d words"), words);
+                       message += bformat(_("%1$d words"), words);
                else
-                       message += _("\nOne word");
+                       message += _("One word");
+               message += "\n";
                if (chars_blanks != 1)
-                       message += bformat(_("\n%1$d characters (including blanks)"),
+                       message += bformat(_("%1$d characters (including blanks)"),
                                          chars_blanks);
                else
-                       message += _("\nOne character (including blanks)");
+                       message += _("One character (including blanks)");
+               message += "\n";
                if (chars != 1)
-                       message += bformat(_("\n%1$d characters (excluding blanks)"),
+                       message += bformat(_("%1$d characters (excluding blanks)"),
                                          chars);
                else
-                       message += _("\nOne character (excluding blanks)");
+                       message += _("One character (excluding blanks)");
 
                Alert::information(_("Statistics"), message);
        }
@@ -1178,7 +1231,7 @@ bool BufferView::dispatch(FuncRequest const & cmd)
        case LFUN_BUFFER_TOGGLE_EMBEDDING: {
                // turn embedding on/off
                try {
-                       buffer_.embeddedFiles().enable(!buffer_.params().embedded);
+                       buffer_.embeddedFiles().enable(!buffer_.params().embedded, buffer_);
                } catch (ExceptionMessage const & message) {
                        Alert::error(message.title_, message.details_);
                }
@@ -1310,7 +1363,7 @@ void BufferView::resize(int width, int height)
 
        // Clear the paragraph height cache.
        d->par_height_.clear();
-
+       // Redo the metrics.
        updateMetrics();
 }
 
@@ -1429,8 +1482,8 @@ void BufferView::lfunScroll(FuncRequest const & cmd)
 {
        string const scroll_type = cmd.getArg(0);
        int const scroll_step = 
-               (scroll_type == "line")? d->scrollbarParameters_.lineScrollHeight
-               : (scroll_type == "page")? height_ : 0;
+               (scroll_type == "line")? d->scrollbarParameters_.single_step
+               : (scroll_type == "page")? d->scrollbarParameters_.page_step : 0;
        if (scroll_step == 0)
                return;
        string const scroll_quantity = cmd.getArg(1);
@@ -1523,7 +1576,7 @@ void BufferView::gotoLabel(docstring const & label)
        for (InsetIterator it = inset_iterator_begin(buffer_.inset()); it; ++it) {
                vector<docstring> labels;
                it->getLabelList(buffer_, labels);
-               if (find(labels.begin(), labels.end(), label) != labels.end()) {
+               if (std::find(labels.begin(), labels.end(), label) != labels.end()) {
                        setCursor(it);
                        showCursor();
                        return;
@@ -1632,9 +1685,9 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select)
        // For an example, see bug 2933:
        // http://bugzilla.lyx.org/show_bug.cgi?id=2933
        // The code below could maybe be moved to a DocIterator method.
-       //lyxerr << "cur before " << cur <<endl;
-       DocIterator dit(cur.inset());
-       dit.push_back(cur.bottom());
+       //lyxerr << "cur before " << cur << endl;
+       DocIterator dit = doc_iterator_begin(cur.inset());
+       dit.bottom() = cur.bottom();
        size_t i = 1;
        while (i < cur.depth() && dit.nextInset() == &cur[i].inset()) {
                dit.push_back(cur[i]);
@@ -1669,6 +1722,9 @@ void BufferView::putSelectionAt(DocIterator const & cur,
                } else
                        d->cursor_.setSelection(d->cursor_, length);
        }
+       // Ensure a redraw happens in any case because the new selection could 
+       // possibly be on the same screen as the previous selection.
+       processUpdateFlags(Update::Force | Update::FitCursor);
 }
 
 
@@ -1736,6 +1792,19 @@ void BufferView::updateMetrics()
        // Rebreak anchor paragraph.
        tm.redoParagraph(d->anchor_pit_);
        ParagraphMetrics & anchor_pm = tm.par_metrics_[d->anchor_pit_];
+       
+       // position anchor
+       if (d->anchor_pit_ == 0) {
+               int scrollRange = d->scrollbarParameters_.max - d->scrollbarParameters_.min;
+               
+               // Complete buffer visible? Then it's easy.
+               if (scrollRange == 0)
+                       d->anchor_ypos_ = anchor_pm.ascent();
+       
+               // FIXME: Some clever handling needed to show
+               // the _first_ paragraph up to the top if the cursor is
+               // in the first line.
+       }               
        anchor_pm.setPosition(d->anchor_ypos_);
 
        LYXERR(Debug::PAINTING, "metrics: "