]> git.lyx.org Git - lyx.git/blobdiff - src/Text2.cpp
Cleanup: Replace a bunch of Cursor arguments with DocIterators.
[lyx.git] / src / Text2.cpp
index ea534752671efe104b520f33b9db8469934b2565..5eedf4f3078bcf079c0844e8ec7924c8f8596f01 100644 (file)
@@ -4,16 +4,16 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Asger Alstrup
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
  * \author Alfredo Braunstein
  * \author Jean-Marc Lasgouttes
  * \author Angus Leeming
  * \author John Levon
- * \author André Pönitz
+ * \author André Pönitz
  * \author Allan Rae
  * \author Stefan Schimanski
  * \author Dekel Tsur
- * \author Jürgen Vigna
+ * \author Jürgen Vigna
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -63,19 +63,14 @@ using namespace std;
 
 namespace lyx {
 
-Text::Text()
-       : autoBreakRows_(false)
-{}
-
-
-bool Text::isMainText(Buffer const & buffer) const
+bool Text::isMainText() const
 {
-       return &buffer.text() == this;
+       return &owner_->buffer().text() == this;
 }
 
 
 // Note that this is supposed to return a fully realized font.
-FontInfo Text::layoutFont(Buffer const & buffer, pit_type const pit) const
+FontInfo Text::layoutFont(pit_type const pit) const
 {
        Layout const & layout = pars_[pit].layout();
 
@@ -83,7 +78,7 @@ FontInfo Text::layoutFont(Buffer const & buffer, pit_type const pit) const
                FontInfo lf = layout.resfont;
                // In case the default family has been customized
                if (layout.font.family() == INHERIT_FAMILY)
-                       lf.setFamily(buffer.params().getFont().fontInfo().family());
+                       lf.setFamily(owner_->buffer().params().getFont().fontInfo().family());
                // FIXME
                // It ought to be possible here just to use Inset::getLayout() and skip
                // the asInsetCollapsable() bit. Unfortunatley, that doesn't work right
@@ -101,15 +96,16 @@ FontInfo Text::layoutFont(Buffer const & buffer, pit_type const pit) const
        FontInfo font = layout.font;
        // Realize with the fonts of lesser depth.
        //font.realize(outerFont(pit, paragraphs()));
-       font.realize(buffer.params().getFont().fontInfo());
+       font.realize(owner_->buffer().params().getFont().fontInfo());
 
        return font;
 }
 
 
 // Note that this is supposed to return a fully realized font.
-FontInfo Text::labelFont(Buffer const & buffer, Paragraph const & par) const
+FontInfo Text::labelFont(Paragraph const & par) const
 {
+       Buffer const & buffer = owner_->buffer();
        Layout const & layout = par.layout();
 
        if (!par.getDepth()) {
@@ -128,9 +124,10 @@ FontInfo Text::labelFont(Buffer const & buffer, Paragraph const & par) const
 }
 
 
-void Text::setCharFont(Buffer const & buffer, pit_type pit,
+void Text::setCharFont(pit_type pit,
                pos_type pos, Font const & fnt, Font const & display_font)
 {
+       Buffer const & buffer = owner_->buffer();
        Font font = fnt;
        Layout const & layout = pars_[pit].layout();
 
@@ -156,7 +153,7 @@ void Text::setCharFont(Buffer const & buffer, pit_type pit,
 
        // Inside inset, apply the inset's font attributes if any
        // (charstyle!)
-       if (!isMainText(buffer))
+       if (!isMainText())
                layoutfont.realize(display_font.fontInfo());
 
        layoutfont.realize(buffer.params().getFont().fontInfo());
@@ -207,20 +204,20 @@ pit_type Text::undoSpan(pit_type pit)
 }
 
 
-void Text::setLayout(Buffer const & buffer, pit_type start, pit_type end,
-               docstring const & layout)
+void Text::setLayout(pit_type start, pit_type end,
+                    docstring const & layout)
 {
        LASSERT(start != end, /**/);
 
-       BufferParams const & bufparams = buffer.params();
-       Layout const & lyxlayout = bufparams.documentClass()[layout];
+       Buffer const & buffer = owner_->buffer();
+       BufferParams const & bp = buffer.params();
+       Layout const & lyxlayout = bp.documentClass()[layout];
 
        for (pit_type pit = start; pit != end; ++pit) {
                Paragraph & par = pars_[pit];
                par.applyLayout(lyxlayout);
                if (lyxlayout.margintype == MARGIN_MANUAL)
-                       par.setLabelWidthString(par.translateIfPossible(
-                               lyxlayout.labelstring(), buffer.params()));
+                       par.setLabelWidthString(par.expandLabel(lyxlayout, bp));
        }
 }
 
@@ -234,8 +231,8 @@ void Text::setLayout(Cursor & cur, docstring const & layout)
        pit_type end = cur.selEnd().pit() + 1;
        pit_type undopit = undoSpan(end - 1);
        recUndo(cur, start, undopit - 1);
-       setLayout(cur.buffer(), start, end, layout);
-       updateLabels(cur.buffer());
+       setLayout(start, end, layout);
+       cur.buffer()->updateLabels();
 }
 
 
@@ -294,7 +291,7 @@ void Text::changeDepth(Cursor & cur, DEPTH_CHANGE type)
        }
        // this handles the counter labels, and also fixes up
        // depth values for follow-on (child) paragraphs
-       updateLabels(cur.buffer());
+       cur.buffer()->updateLabels();
 }
 
 
@@ -306,13 +303,13 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
        FontInfo layoutfont;
        pit_type pit = cur.pit();
        if (cur.pos() < pars_[pit].beginOfBody())
-               layoutfont = labelFont(cur.buffer(), pars_[pit]);
+               layoutfont = labelFont(pars_[pit]);
        else
-               layoutfont = layoutFont(cur.buffer(), pit);
+               layoutfont = layoutFont(pit);
 
        // Update current font
        cur.real_current_font.update(font,
-                                       cur.buffer().params().language,
+                                       cur.buffer()->params().language,
                                        toggleall);
 
        // Reduce to implicit settings
@@ -360,7 +357,7 @@ void Text::setFont(BufferView const & bv, CursorSlice const & begin,
                TextMetrics const & tm = bv.textMetrics(this);
                Font f = tm.displayFont(pit, pos);
                f.update(font, language, toggleall);
-               setCharFont(buffer, pit, pos, f, tm.font_);
+               setCharFont(pit, pos, f, tm.font_);
        }
 }
 
@@ -392,8 +389,8 @@ void Text::toggleFree(Cursor & cur, Font const & font, bool toggleall)
        // Try implicit word selection
        // If there is a change in the language the implicit word selection
        // is disabled.
-       CursorSlice resetCursor = cur.top();
-       bool implicitSelection =
+       CursorSlice const resetCursor = cur.top();
+       bool const implicitSelection =
                font.language() == ignore_language
                && font.fontInfo().number() == FONT_IGNORE
                && selectWordWhenUnderCursor(cur, WHOLE_WORD_STRICT);
@@ -444,12 +441,23 @@ void Text::setParagraphs(Cursor & cur, docstring arg, bool merge)
 
        //FIXME UNICODE
        string const argument = to_utf8(arg);
+       depth_type priordepth = -1;
+       Layout priorlayout;
        for (pit_type pit = cur.selBegin().pit(), end = cur.selEnd().pit();
             pit <= end; ++pit) {
                Paragraph & par = pars_[pit];
                ParagraphParameters params = par.params();
                params.read(argument, merge);
+               // Changes to label width string apply to all paragraphs
+               // with same layout in a sequence.
+               // Do this only once for a selected range of paragraphs
+               // of the same layout and depth.
+               if (par.getDepth() != priordepth || par.layout() != priorlayout)
+                       setLabelWidthStringToSequence(pit, pars_,
+                                       params.labelWidthString());
                par.params().apply(params, par.layout());
+               priordepth = par.getDepth();
+               priorlayout = par.layout();
        }
 }
 
@@ -464,11 +472,22 @@ void Text::setParagraphs(Cursor & cur, ParagraphParameters const & p)
        pit_type undopit = undoSpan(cur.selEnd().pit());
        recUndo(cur, cur.selBegin().pit(), undopit - 1);
 
+       depth_type priordepth = -1;
+       Layout priorlayout;
        for (pit_type pit = cur.selBegin().pit(), end = cur.selEnd().pit();
             pit <= end; ++pit) {
                Paragraph & par = pars_[pit];
+               // Changes to label width string apply to all paragraphs
+               // with same layout in a sequence.
+               // Do this only once for a selected range of paragraphs
+               // of the same layout and depth.
+               if (par.getDepth() != priordepth || par.layout() != priorlayout)
+                       setLabelWidthStringToSequence(pit, pars_,
+                                       par.params().labelWidthString());
                par.params().apply(p, par.layout());
-       }       
+               priordepth = par.getDepth();
+               priorlayout = par.layout();
+       }
 }
 
 
@@ -478,22 +497,66 @@ void Text::insertInset(Cursor & cur, Inset * inset)
        LASSERT(this == cur.text(), /**/);
        LASSERT(inset, /**/);
        cur.paragraph().insertInset(cur.pos(), inset, cur.current_font,
-               Change(cur.buffer().params().trackChanges
+               Change(cur.buffer()->params().trackChanges
                ? Change::INSERTED : Change::UNCHANGED));
 }
 
 
 // needed to insert the selection
-void Text::insertStringAsLines(Cursor & cur, docstring const & str)
+void Text::insertStringAsLines(DocIterator const & dit, docstring const & str,
+               Font const & font)
 {
-       cur.buffer().insertStringAsLines(pars_, cur.pit(), cur.pos(),
-               cur.current_font, str, autoBreakRows_);
+       BufferParams const & bparams = owner_->buffer().params();
+       pit_type pit = dit.pit();
+       pos_type pos = dit.pos();
+
+       // insert the string, don't insert doublespace
+       bool space_inserted = true;
+       for (docstring::const_iterator cit = str.begin();
+           cit != str.end(); ++cit) {
+               Paragraph & par = pars_[pit];
+               if (*cit == '\n') {
+                       if (autoBreakRows_ && (!par.empty() || par.allowEmpty())) {
+                               lyx::breakParagraph(bparams, pars_, pit, pos,
+                                              par.layout().isEnvironment());
+                               ++pit;
+                               pos = 0;
+                               space_inserted = true;
+                       } else {
+                               continue;
+                       }
+                       // do not insert consecutive spaces if !free_spacing
+               } else if ((*cit == ' ' || *cit == '\t') &&
+                          space_inserted && !par.isFreeSpacing()) {
+                       continue;
+               } else if (*cit == '\t') {
+                       if (!par.isFreeSpacing()) {
+                               // tabs are like spaces here
+                               par.insertChar(pos, ' ', font, bparams.trackChanges);
+                               ++pos;
+                               space_inserted = true;
+                       } else {
+                               par.insertChar(pos, *cit, font, bparams.trackChanges);
+                               ++pos;
+                               space_inserted = true;
+                       }
+               } else if (!isPrintable(*cit)) {
+                       // Ignore unprintables
+                       continue;
+               } else {
+                       // just insert the character
+                       par.insertChar(pos, *cit, font, bparams.trackChanges);
+                       ++pos;
+                       space_inserted = (*cit == ' ');
+               }
+       }
 }
 
 
 // turn double CR to single CR, others are converted into one
 // blank. Then insertStringAsLines is called
-void Text::insertStringAsParagraphs(Cursor & cur, docstring const & str)
+void Text::insertStringAsParagraphs(DocIterator const & dit, docstring const & str,
+               Font const & font)
 {
        docstring linestr = str;
        bool newline_inserted = false;
@@ -514,7 +577,7 @@ void Text::insertStringAsParagraphs(Cursor & cur, docstring const & str)
                        newline_inserted = false;
                }
        }
-       insertStringAsLines(cur, linestr);
+       insertStringAsLines(dit, linestr, font);
 }
 
 
@@ -573,7 +636,7 @@ bool Text::checkAndActivateInset(Cursor & cur, bool front)
        if (!front && cur.pos() == 0)
                return false;
        Inset * inset = front ? cur.nextInset() : cur.prevInset();
-       if (!inset || inset->editable() != Inset::HIGHLY_EDITABLE)
+       if (!inset || !inset->editable())
                return false;
        /*
         * Apparently, when entering an inset we are expected to be positioned
@@ -599,7 +662,7 @@ bool Text::checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool mo
                return false;
        Paragraph & par = cur.paragraph();
        Inset * inset = par.isInset(cur.pos()) ? par.getInset(cur.pos()) : 0;
-       if (!inset || inset->editable() != Inset::HIGHLY_EDITABLE)
+       if (!inset || !inset->editable())
                return false;
        inset->edit(cur, movingForward, 
                movingLeft ? Inset::ENTRY_DIRECTION_RIGHT : Inset::ENTRY_DIRECTION_LEFT);
@@ -802,10 +865,18 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
        // delete the LineSeparator.
        // MISSING
 
-       bool const same_inset = &old.inset() == &cur.inset();
-       bool const same_par = same_inset && old.pit() == cur.pit();
-       bool const same_par_pos = same_par && old.pos() == cur.pos();
+       // Find a common inset and the corresponding depth.
+       size_t depth = 0;
+       for (; depth < cur.depth(); ++depth)
+               if (&old.inset() == &cur[depth].inset())
+                       break;
 
+       // Whether a common inset is found and whether the cursor is still in 
+       // the same paragraph (possibly nested).
+       bool const same_par = depth < cur.depth() && old.pit() == cur[depth].pit();
+       bool const same_par_pos = depth == cur.depth() - 1 && same_par 
+               && old.pos() == cur[depth].pos();
+       
        // If the chars around the old cursor were spaces, delete one of them.
        if (!same_par_pos) {
                // Only if the cursor has really moved.
@@ -815,14 +886,14 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
                    && oldpar.isLineSeparator(old.pos() - 1)
                    && !oldpar.isDeleted(old.pos() - 1)
                    && !oldpar.isDeleted(old.pos())) {
-                       oldpar.eraseChar(old.pos() - 1, cur.buffer().params().trackChanges);
+                       oldpar.eraseChar(old.pos() - 1, cur.buffer()->params().trackChanges);
 // FIXME: This will not work anymore when we have multiple views of the same buffer
 // In this case, we will have to correct also the cursors held by
 // other bufferviews. It will probably be easier to do that in a more
 // automated way in CursorSlice code. (JMarc 26/09/2001)
                        // correct all cursor parts
                        if (same_par) {
-                               fixCursorAfterDelete(cur.top(), old.top());
+                               fixCursorAfterDelete(cur[depth], old.top());
                                need_anchor_change = true;
                        }
                        return true;
@@ -870,7 +941,7 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
                return true;
        }
 
-       if (oldpar.stripLeadingSpaces(cur.buffer().params().trackChanges)) {
+       if (oldpar.stripLeadingSpaces(cur.buffer()->params().trackChanges)) {
                need_anchor_change = true;
                // We return true here because the Paragraph contents changed and
                // we need a redraw before further action is processed.