]> git.lyx.org Git - lyx.git/blobdiff - src/Text2.cpp
Update my email and status.
[lyx.git] / src / Text2.cpp
index ed2f3fd0bac72effaee670e743a8597f014cc4b2..fe2d94e831ae6f2b2540fb5af62d655adf609ae4 100644 (file)
 #include "CutAndPaste.h"
 #include "DispatchResult.h"
 #include "ErrorList.h"
-#include "FuncRequest.h"
 #include "Language.h"
 #include "Layout.h"
 #include "Lexer.h"
-#include "LyXFunc.h"
+#include "LyX.h"
 #include "LyXRC.h"
 #include "Paragraph.h"
-#include "paragraph_funcs.h"
 #include "ParagraphParameters.h"
 #include "TextClass.h"
 #include "TextMetrics.h"
-#include "VSpace.h"
 
 #include "insets/InsetCollapsable.h"
 
@@ -63,19 +60,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,33 +75,25 @@ 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());
-               // FIXME
-               // It ought to be possible here just to use Inset::getLayout() and skip
-               // the asInsetCollapsable() bit. Unfortunatley, that doesn't work right
-               // now, because Inset::getLayout() will return a default-constructed
-               // InsetLayout, and that e.g. sets the foreground color to red. So we
-               // need to do some work to make that possible.
-               InsetCollapsable const * icp = pars_[pit].inInset().asInsetCollapsable();
-               if (!icp)
-                       return lf;
-               FontInfo icf = icp->getLayout().font();
+                       lf.setFamily(owner_->buffer().params().getFont().fontInfo().family());
+               FontInfo icf = owner_->getLayout().font();
                icf.realize(lf);
                return icf;
        }
 
        FontInfo font = layout.font;
        // Realize with the fonts of lesser depth.
-       //font.realize(outerFont(pit, paragraphs()));
-       font.realize(buffer.params().getFont().fontInfo());
+       //font.realize(outerFont(pit));
+       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 +112,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();
 
@@ -148,7 +133,7 @@ void Text::setCharFont(Buffer const & buffer, pit_type pit,
                while (!layoutfont.resolved() &&
                       tp != pit_type(paragraphs().size()) &&
                       pars_[tp].getDepth()) {
-                       tp = outerHook(tp, paragraphs());
+                       tp = outerHook(tp);
                        if (tp != pit_type(paragraphs().size()))
                                layoutfont.realize(pars_[tp].layout().font);
                }
@@ -156,7 +141,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());
@@ -169,10 +154,10 @@ void Text::setCharFont(Buffer const & buffer, pit_type pit,
 
 
 void Text::setInsetFont(BufferView const & bv, pit_type pit,
-               pos_type pos, Font const & font, bool toggleall)
+               pos_type pos, Font const & font)
 {
        Inset * const inset = pars_[pit].getInset(pos);
-       LASSERT(inset && inset->noFontChange(), /**/);
+       LASSERT(inset && inset->resetFontEdit(), /**/);
 
        CursorSlice::idx_type endidx = inset->nargs();
        for (CursorSlice cs(*inset); cs.idx() != endidx; ++cs.idx()) {
@@ -182,36 +167,18 @@ void Text::setInsetFont(BufferView const & bv, pit_type pit,
                        CursorSlice cellend = cs;
                        cellend.pit() = cellend.lastpit();
                        cellend.pos() = cellend.lastpos();
-                       text->setFont(bv, cs, cellend, font, toggleall);
+                       text->setFont(bv, cs, cellend, font);
                }
        }
 }
 
 
-// return past-the-last paragraph influenced by a layout change on pit
-pit_type Text::undoSpan(pit_type pit)
-{
-       pit_type const end = paragraphs().size();
-       pit_type nextpit = pit + 1;
-       if (nextpit == end)
-               return nextpit;
-       //because of parindents
-       if (!pars_[pit].getDepth())
-               return boost::next(nextpit);
-       //because of depth constrains
-       for (; nextpit != end; ++pit, ++nextpit) {
-               if (!pars_[pit].getDepth())
-                       break;
-       }
-       return nextpit;
-}
-
-
-void Text::setLayout(Buffer const & buffer, pit_type start, pit_type end,
+void Text::setLayout(pit_type start, pit_type end,
                     docstring const & layout)
 {
        LASSERT(start != end, /**/);
 
+       Buffer const & buffer = owner_->buffer();
        BufferParams const & bp = buffer.params();
        Layout const & lyxlayout = bp.documentClass()[layout];
 
@@ -231,18 +198,15 @@ void Text::setLayout(Cursor & cur, docstring const & layout)
 
        pit_type start = cur.selBegin().pit();
        pit_type end = cur.selEnd().pit() + 1;
-       pit_type undopit = undoSpan(end - 1);
-       recUndo(cur, start, undopit - 1);
-       setLayout(*cur.buffer(), start, end, layout);
-       cur.buffer()->updateLabels();
+       cur.recordUndoSelection();
+       setLayout(start, end, layout);
+       cur.forceBufferUpdate();
 }
 
 
 static bool changeDepthAllowed(Text::DEPTH_CHANGE type,
                        Paragraph const & par, int max_depth)
 {
-       if (par.layout().labeltype == LABEL_BIBLIO)
-               return false;
        int const depth = par.params().depth();
        if (type == Text::INC_DEPTH && depth < max_depth)
                return true;
@@ -293,7 +257,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
-       cur.buffer()->updateLabels();
+       cur.forceBufferUpdate();
 }
 
 
@@ -305,9 +269,9 @@ 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,
@@ -326,15 +290,67 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
 
        // Ok, we have a selection.
        cur.recordUndoSelection();
+       Font newfont = font;
+
+       if (toggleall) {        
+               // Toggling behaves as follows: We check the first character of the
+               // selection. If it's (say) got EMPH on, then we set to off; if off,
+               // then to on. With families and the like, we set it to INHERIT, if
+               // we already have it.
+               CursorSlice const & sl = cur.selBegin();
+               Text const & text = *sl.text();
+               Paragraph const & par = text.getPar(sl.pit());
+       
+               // get font at the position
+               Font oldfont = par.getFont(cur.bv().buffer().params(), sl.pos(),
+                       text.outerFont(sl.pit()));
+               FontInfo const & oldfi = oldfont.fontInfo();
+       
+               FontInfo & newfi = newfont.fontInfo();
+       
+               FontFamily newfam = newfi.family();
+               if (newfam !=   INHERIT_FAMILY && newfam != IGNORE_FAMILY &&
+                               newfam == oldfi.family())
+                       newfi.setFamily(INHERIT_FAMILY);
+               
+               FontSeries newser = newfi.series();
+               if (newser == BOLD_SERIES && oldfi.series() == BOLD_SERIES)
+                       newfi.setSeries(INHERIT_SERIES);
+       
+               FontShape newshp = newfi.shape();
+               if (newshp !=   INHERIT_SHAPE && newshp != IGNORE_SHAPE &&
+                               newshp == oldfi.shape())
+                       newfi.setShape(INHERIT_SHAPE);
+
+               ColorCode newcol = newfi.color();
+               if (newcol != Color_none && newcol != Color_inherit 
+                   && newcol != Color_ignore && newcol == oldfi.color())
+                       newfi.setColor(Color_none);
+
+               // ON/OFF ones
+               if (newfi.emph() == FONT_TOGGLE)
+                       newfi.setEmph(oldfi.emph() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.underbar() == FONT_TOGGLE)
+                       newfi.setUnderbar(oldfi.underbar() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.strikeout() == FONT_TOGGLE)
+                       newfi.setStrikeout(oldfi.strikeout() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.uuline() == FONT_TOGGLE)
+                       newfi.setUuline(oldfi.uuline() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.uwave() == FONT_TOGGLE)
+                       newfi.setUwave(oldfi.uwave() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.noun() == FONT_TOGGLE)
+                       newfi.setNoun(oldfi.noun() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.number() == FONT_TOGGLE)
+                       newfi.setNumber(oldfi.number() == FONT_OFF ? FONT_ON : FONT_OFF);
+       }
 
        setFont(cur.bv(), cur.selectionBegin().top(), 
-               cur.selectionEnd().top(), font, toggleall);
+               cur.selectionEnd().top(), newfont);
 }
 
 
 void Text::setFont(BufferView const & bv, CursorSlice const & begin,
-               CursorSlice const & end, Font const & font,
-               bool toggleall)
+               CursorSlice const & end, Font const & font)
 {
        Buffer const & buffer = bv.buffer();
 
@@ -349,17 +365,18 @@ void Text::setFont(BufferView const & bv, CursorSlice const & begin,
                pit_type const pit = dit.pit();
                pos_type const pos = dit.pos();
                Inset * inset = pars_[pit].getInset(pos);
-               if (inset && inset->noFontChange()) {
+               if (inset && inset->resetFontEdit()) {
                        // We need to propagate the font change to all
-                       // text cells of the inset (bug 1973).
-                       // FIXME: This should change, see documentation
-                       // of noFontChange in Inset.h
-                       setInsetFont(bv, pit, pos, font, toggleall);
+                       // text cells of the inset (bugs 1973, 6919).
+                       setInsetFont(bv, pit, pos, font);
                }
                TextMetrics const & tm = bv.textMetrics(this);
                Font f = tm.displayFont(pit, pos);
-               f.update(font, language, toggleall);
-               setCharFont(buffer, pit, pos, f, tm.font_);
+               f.update(font, language);
+               setCharFont(pit, pos, f, tm.font_);
+               // font change may change language... 
+               // spell checker has to know that
+               pars_[pit].requestSpellCheck(pos);
        }
 }
 
@@ -434,30 +451,57 @@ docstring Text::getStringToIndex(Cursor const & cur)
 }
 
 
+void Text::setLabelWidthStringToSequence(Cursor const & cur,
+               docstring const & s)
+{
+       Cursor c = cur;
+       // Find first of same layout in sequence
+       while (!isFirstInSequence(c.pit())) {
+               c.pit() = depthHook(c.pit(), c.paragraph().getDepth());
+       }
+
+       // now apply label width string to every par
+       // in sequence
+       depth_type const depth = c.paragraph().getDepth();
+       Layout const & layout = c.paragraph().layout();
+       for ( ; c.pit() <= c.lastpit() ; ++c.pit()) {
+               while (c.paragraph().getDepth() > depth) {
+                       ++c.pit();
+                       if (c.pit() > c.lastpit())
+                               return;
+               }
+               if (c.paragraph().getDepth() < depth)
+                       return;
+               if (c.paragraph().layout() != layout)
+                       return;
+               c.recordUndo();
+               c.paragraph().setLabelWidthString(s);
+       }
+}
+
+
 void Text::setParagraphs(Cursor & cur, docstring arg, bool merge) 
 {
        LASSERT(cur.text(), /**/);
-       // make sure that the depth behind the selection are restored, too
-       pit_type undopit = undoSpan(cur.selEnd().pit());
-       recUndo(cur, cur.selBegin().pit(), undopit - 1);
 
        //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];
+       Cursor c(cur.bv());
+       c.setCursor(cur.selectionBegin());
+       for ( ; c <= cur.selectionEnd() ; ++c.pit()) {
+               Paragraph & par = c.paragraph();
                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());
+               cur.recordUndo();
                par.params().apply(params, par.layout());
+               if (par.getDepth() != priordepth || par.layout() != priorlayout)
+                       setLabelWidthStringToSequence(c, params.labelWidthString());
                priordepth = par.getDepth();
                priorlayout = par.layout();
        }
@@ -470,23 +514,22 @@ void Text::setParagraphs(Cursor & cur, docstring arg, bool merge)
 void Text::setParagraphs(Cursor & cur, ParagraphParameters const & p) 
 {
        LASSERT(cur.text(), /**/);
-       // make sure that the depth behind the selection are restored, too
-       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];
+       Cursor c(cur.bv());
+       c.setCursor(cur.selectionBegin());
+       for ( ; c < cur.selectionEnd() ; ++c.pit()) {
+               Paragraph & par = c.paragraph();
                // 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());
+               cur.recordUndo();
                par.params().apply(p, par.layout());
+               if (par.getDepth() != priordepth || par.layout() != priorlayout)
+                       setLabelWidthStringToSequence(c,
+                               par.params().labelWidthString());
                priordepth = par.getDepth();
                priorlayout = par.layout();
        }
@@ -504,41 +547,6 @@ void Text::insertInset(Cursor & cur, Inset * inset)
 }
 
 
-// needed to insert the selection
-void Text::insertStringAsLines(Cursor & cur, docstring const & str)
-{
-       cur.buffer()->insertStringAsLines(pars_, cur.pit(), cur.pos(),
-               cur.current_font, str, autoBreakRows_);
-}
-
-
-// turn double CR to single CR, others are converted into one
-// blank. Then insertStringAsLines is called
-void Text::insertStringAsParagraphs(Cursor & cur, docstring const & str)
-{
-       docstring linestr = str;
-       bool newline_inserted = false;
-
-       for (string::size_type i = 0, siz = linestr.size(); i < siz; ++i) {
-               if (linestr[i] == '\n') {
-                       if (newline_inserted) {
-                               // we know that \r will be ignored by
-                               // insertStringAsLines. Of course, it is a dirty
-                               // trick, but it works...
-                               linestr[i - 1] = '\r';
-                               linestr[i] = '\n';
-                       } else {
-                               linestr[i] = ' ';
-                               newline_inserted = true;
-                       }
-               } else if (isPrintable(linestr[i])) {
-                       newline_inserted = false;
-               }
-       }
-       insertStringAsLines(cur, linestr);
-}
-
-
 bool Text::setCursor(Cursor & cur, pit_type par, pos_type pos,
                        bool setfont, bool boundary)
 {
@@ -546,6 +554,9 @@ bool Text::setCursor(Cursor & cur, pit_type par, pos_type pos,
        bool const update_needed = !tm.contains(par);
        Cursor old = cur;
        setCursorIntern(cur, par, pos, setfont, boundary);
+       // FIXME There is a chance that we'll miss a screen update here.
+       // If so, then do DEPM and then check if cur wants an update and
+       // go ahead and do it, if so.
        return cur.bv().checkDepm(cur, old) || update_needed;
 }
 
@@ -561,12 +572,12 @@ void Text::setCursor(CursorSlice & cur, pit_type par, pos_type pos)
 
        // None of these should happen, but we're scaredy-cats
        if (pos < 0) {
-               lyxerr << "dont like -1" << endl;
+               lyxerr << "don't like -1" << endl;
                LASSERT(false, /**/);
        }
 
        if (pos > para.size()) {
-               lyxerr << "dont like 1, pos: " << pos
+               lyxerr << "don't like 1, pos: " << pos
                       << " size: " << para.size()
                       << " par: " << par << endl;
                LASSERT(false, /**/);
@@ -631,7 +642,7 @@ bool Text::checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool mo
 bool Text::cursorBackward(Cursor & cur)
 {
        // Tell BufferView to test for FitCursor in any case!
-       cur.updateFlags(Update::FitCursor);
+       cur.screenUpdateFlags(Update::FitCursor);
 
        // not at paragraph start?
        if (cur.pos() > 0) {
@@ -699,7 +710,7 @@ bool Text::cursorVisRight(Cursor & cur, bool skip_inset)
 bool Text::cursorForward(Cursor & cur)
 {
        // Tell BufferView to test for FitCursor in any case!
-       cur.updateFlags(Update::FitCursor);
+       cur.screenUpdateFlags(Update::FitCursor);
 
        // not at paragraph end?
        if (cur.pos() != cur.lastpos()) {
@@ -930,8 +941,9 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
                        }
                }
 
-               // don't delete anything if this is the only remaining paragraph within the given range
-               // note: Text::acceptOrRejectChanges() sets the cursor to 'first' after calling DEPM
+               // don't delete anything if this is the only remaining paragraph
+               // within the given range. Note: Text::acceptOrRejectChanges()
+               // sets the cursor to 'first' after calling DEPM
                if (first == last)
                        continue;