X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ftext2.C;h=917808ec8395ef3fa0de90f9adcdbae024957eaf;hb=ee1163d8e8cbe814912f3498f42fa65a55f22bb7;hp=2f90fd73b1a4db07bf11eaef1795a8746fb05638;hpb=a2cd656e256fa50aec3f03851b63a4bc6cdd666d;p=lyx.git diff --git a/src/text2.C b/src/text2.C index 2f90fd73b1..917808ec83 100644 --- a/src/text2.C +++ b/src/text2.C @@ -26,15 +26,12 @@ #include "bufferparams.h" #include "BufferView.h" #include "Bullet.h" -#include "counters.h" #include "coordcache.h" #include "cursor.h" #include "CutAndPaste.h" #include "debug.h" #include "dispatchresult.h" #include "errorlist.h" -#include "Floating.h" -#include "FloatList.h" #include "funcrequest.h" #include "gettext.h" #include "language.h" @@ -45,26 +42,21 @@ #include "paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" +#include "pariterator.h" #include "undo.h" #include "vspace.h" #include "frontends/font_metrics.h" #include "frontends/LyXView.h" -#include "insets/insetbibitem.h" #include "insets/insetenv.h" -#include "insets/insetfloat.h" -#include "insets/insetwrap.h" -#include "support/lstrings.h" #include "support/textutils.h" -#include "support/tostr.h" #include using lyx::pit_type; using lyx::pos_type; -using lyx::support::bformat; using std::endl; using std::ostringstream; @@ -74,7 +66,8 @@ using std::string; LyXText::LyXText(BufferView * bv) : maxwidth_(bv ? bv->workWidth() : 100), background_color_(LColor::background), - bv_owner(bv) + bv_owner(bv), + autoBreakRows_(false) {} @@ -92,7 +85,7 @@ void LyXText::init(BufferView * bv) pars_[pit].rows().clear(); current_font = getFont(pars_[0], 0); - updateCounters(); + updateCounters(*bv->buffer()); } @@ -118,7 +111,7 @@ InsetBase * LyXText::checkInsetHit(int x, int y) const InsetBase * inset = iit->inset; #if 1 lyxerr << "examining inset " << inset << endl; - if (theCoords.insets_.has(inset)) + if (theCoords.getInsets().has(inset)) lyxerr << " xo: " << inset->xo() << "..." << inset->xo() + inset->width() @@ -335,26 +328,14 @@ void LyXText::setLayout(LCursor & cur, string const & layout) pit_type start = cur.selBegin().pit(); pit_type end = cur.selEnd().pit() + 1; - pit_type endpit = setLayout(start, end, layout); - updateCounters(); + setLayout(start, end, layout); + updateCounters(cur.buffer()); } namespace { -void getSelectionSpan(LCursor & cur, pit_type & beg, pit_type & end) -{ - if (!cur.selection()) { - beg = cur.pit(); - end = cur.pit() + 1; - } else { - beg = cur.selBegin().pit(); - end = cur.selEnd().pit() + 1; - } -} - - bool changeDepthAllowed(LyXText::DEPTH_CHANGE type, Paragraph const & par, int max_depth) { @@ -375,11 +356,9 @@ bool changeDepthAllowed(LyXText::DEPTH_CHANGE type, bool LyXText::changeDepthAllowed(LCursor & cur, DEPTH_CHANGE type) const { BOOST_ASSERT(this == cur.text()); - pit_type beg, end; - getSelectionSpan(cur, beg, end); - int max_depth = 0; - if (beg != 0) - max_depth = pars_[beg - 1].getMaxDepthAfter(); + pit_type const beg = cur.selBegin().pit(); + pit_type const end = cur.selEnd().pit() + 1; + int max_depth = (beg != 0 ? pars_[beg - 1].getMaxDepthAfter() : 0); for (pit_type pit = beg; pit != end; ++pit) { if (::changeDepthAllowed(type, pars_[pit], max_depth)) @@ -393,13 +372,10 @@ bool LyXText::changeDepthAllowed(LCursor & cur, DEPTH_CHANGE type) const void LyXText::changeDepth(LCursor & cur, DEPTH_CHANGE type) { BOOST_ASSERT(this == cur.text()); - pit_type beg, end; - getSelectionSpan(cur, beg, end); + pit_type const beg = cur.selBegin().pit(); + pit_type const end = cur.selEnd().pit() + 1; recordUndoSelection(cur); - - int max_depth = 0; - if (beg != 0) - max_depth = pars_[beg - 1].getMaxDepthAfter(); + int max_depth = (beg != 0 ? pars_[beg - 1].getMaxDepthAfter() : 0); for (pit_type pit = beg; pit != end; ++pit) { Paragraph & par = pars_[pit]; @@ -414,7 +390,7 @@ void LyXText::changeDepth(LCursor & cur, DEPTH_CHANGE type) } // this handles the counter labels, and also fixes up // depth values for follow-on (child) paragraphs - updateCounters(); + updateCounters(cur.buffer()); } @@ -456,7 +432,9 @@ void LyXText::setFont(LCursor & cur, LyXFont const & font, bool toggleall) // Don't use forwardChar here as ditend might have // pos() == lastpos() and forwardChar would miss it. - for (; dit != ditend; dit.forwardPos()) { + // Can't use forwardPos either as this descends into + // nested insets. + for (; dit != ditend; dit.forwardPosNoDescend()) { if (dit.pos() != dit.lastpos()) { LyXFont f = getFont(dit.paragraph(), dit.pos()); f.update(font, params.language, toggleall); @@ -596,302 +574,6 @@ void LyXText::setParagraph(LCursor & cur, } -string expandLabel(LyXTextClass const & textclass, - LyXLayout_ptr const & layout, bool appendix) -{ - string fmt = appendix ? - layout->labelstring_appendix() : layout->labelstring(); - - // handle 'inherited level parts' in 'fmt', - // i.e. the stuff between '@' in '@Section@.\arabic{subsection}' - size_t const i = fmt.find('@', 0); - if (i != string::npos) { - size_t const j = fmt.find('@', i + 1); - if (j != string::npos) { - string parent(fmt, i + 1, j - i - 1); - string label = expandLabel(textclass, textclass[parent], appendix); - fmt = string(fmt, 0, i) + label + string(fmt, j + 1, string::npos); - } - } - - return textclass.counters().counterLabel(fmt); -} - - -namespace { - -void incrementItemDepth(ParagraphList & pars, pit_type pit, pit_type first_pit) -{ - int const cur_labeltype = pars[pit].layout()->labeltype; - - if (cur_labeltype != LABEL_ENUMERATE && cur_labeltype != LABEL_ITEMIZE) - return; - - int const cur_depth = pars[pit].getDepth(); - - pit_type prev_pit = pit - 1; - while (true) { - int const prev_depth = pars[prev_pit].getDepth(); - int const prev_labeltype = pars[prev_pit].layout()->labeltype; - if (prev_depth == 0 && cur_depth > 0) { - if (prev_labeltype == cur_labeltype) { - pars[pit].itemdepth = pars[prev_pit].itemdepth + 1; - } - break; - } else if (prev_depth < cur_depth) { - if (prev_labeltype == cur_labeltype) { - pars[pit].itemdepth = pars[prev_pit].itemdepth + 1; - break; - } - } else if (prev_depth == cur_depth) { - if (prev_labeltype == cur_labeltype) { - pars[pit].itemdepth = pars[prev_pit].itemdepth; - break; - } - } - if (prev_pit == first_pit) - break; - - --prev_pit; - } -} - - -void resetEnumCounterIfNeeded(ParagraphList & pars, pit_type pit, - pit_type firstpit, Counters & counters) -{ - if (pit == firstpit) - return; - - int const cur_depth = pars[pit].getDepth(); - pit_type prev_pit = pit - 1; - while (true) { - int const prev_depth = pars[prev_pit].getDepth(); - int const prev_labeltype = pars[prev_pit].layout()->labeltype; - if (prev_depth <= cur_depth) { - if (prev_labeltype != LABEL_ENUMERATE) { - switch (pars[pit].itemdepth) { - case 0: - counters.reset("enumi"); - case 1: - counters.reset("enumii"); - case 2: - counters.reset("enumiii"); - case 3: - counters.reset("enumiv"); - } - } - break; - } - - if (prev_pit == firstpit) - break; - - --prev_pit; - } -} - -} // anon namespace - - -// set the counter of a paragraph. This includes the labels -void LyXText::setCounter(Buffer const & buf, pit_type pit) -{ - Paragraph & par = pars_[pit]; - BufferParams const & bufparams = buf.params(); - LyXTextClass const & textclass = bufparams.getLyXTextClass(); - LyXLayout_ptr const & layout = par.layout(); - Counters & counters = textclass.counters(); - - // Always reset - par.itemdepth = 0; - - if (pit == 0) { - par.params().appendix(par.params().startOfAppendix()); - } else { - par.params().appendix(pars_[pit - 1].params().appendix()); - if (!par.params().appendix() && - par.params().startOfAppendix()) { - par.params().appendix(true); - textclass.counters().reset(); - } - - // Maybe we have to increment the item depth. - incrementItemDepth(pars_, pit, 0); - } - - // erase what was there before - par.params().labelString(string()); - - if (layout->margintype == MARGIN_MANUAL) { - if (par.params().labelWidthString().empty()) - par.setLabelWidthString(layout->labelstring()); - } else { - par.setLabelWidthString(string()); - } - - // is it a layout that has an automatic label? - if (layout->labeltype == LABEL_COUNTER) { - BufferParams const & bufparams = buf.params(); - LyXTextClass const & textclass = bufparams.getLyXTextClass(); - counters.step(layout->counter); - string label = expandLabel(textclass, layout, par.params().appendix()); - par.params().labelString(label); - } else if (layout->labeltype == LABEL_ITEMIZE) { - // At some point of time we should do something more - // clever here, like: - // par.params().labelString( - // bufparams.user_defined_bullet(par.itemdepth).getText()); - // for now, use a simple hardcoded label - string itemlabel; - switch (par.itemdepth) { - case 0: - itemlabel = "*"; - break; - case 1: - itemlabel = "-"; - break; - case 2: - itemlabel = "@"; - break; - case 3: - itemlabel = "ยท"; - break; - } - - par.params().labelString(itemlabel); - } else if (layout->labeltype == LABEL_ENUMERATE) { - // Maybe we have to reset the enumeration counter. - resetEnumCounterIfNeeded(pars_, pit, 0, counters); - - // FIXME - // Yes I know this is a really, really! bad solution - // (Lgb) - string enumcounter = "enum"; - - switch (par.itemdepth) { - case 2: - enumcounter += 'i'; - case 1: - enumcounter += 'i'; - case 0: - enumcounter += 'i'; - break; - case 3: - enumcounter += "iv"; - break; - default: - // not a valid enumdepth... - break; - } - - counters.step(enumcounter); - - par.params().labelString(counters.enumLabel(enumcounter)); - } else if (layout->labeltype == LABEL_BIBLIO) {// ale970302 - counters.step("bibitem"); - int number = counters.value("bibitem"); - if (par.bibitem()) { - par.bibitem()->setCounter(number); - par.params().labelString(layout->labelstring()); - } - // In biblio should't be following counters but... - } else { - string s = buf.B_(layout->labelstring()); - - // the caption hack: - if (layout->labeltype == LABEL_SENSITIVE) { - pit_type end = paragraphs().size(); - pit_type tmppit = pit; - InsetBase * in = 0; - bool isOK = false; - while (tmppit != end) { - in = pars_[tmppit].inInset(); - if (in->lyxCode() == InsetBase::FLOAT_CODE || - in->lyxCode() == InsetBase::WRAP_CODE) { - isOK = true; - break; - } -#ifdef WITH_WARNINGS -#warning replace this code by something that works -// This code does not work because we have currently no way to move up -// in the hierarchy of insets (JMarc 16/08/2004) -#endif -#if 0 -/* I think this code is supposed to be useful when one has a caption - * in a minipage in a figure inset. We need to go up to be able to see - * that the caption should use "Figure" as label - */ - else { - Paragraph const * owner = &ownerPar(buf, in); - tmppit = 0; - for ( ; tmppit != end; ++tmppit) - if (&pars_[tmppit] == owner) - break; - } -#else - ++tmppit; -#endif - } - - if (isOK) { - string type; - - if (in->lyxCode() == InsetBase::FLOAT_CODE) - type = static_cast(in)->params().type; - else if (in->lyxCode() == InsetBase::WRAP_CODE) - type = static_cast(in)->params().type; - else - BOOST_ASSERT(false); - - Floating const & fl = textclass.floats().getType(type); - - counters.step(fl.type()); - - // Doesn't work... yet. - s = bformat(_("%1$s #:"), buf.B_(fl.name())); - } else { - // par->SetLayout(0); - // s = layout->labelstring; - s = _("Senseless: "); - } - } - par.params().labelString(s); - - } -} - - -// Updates all counters. -void LyXText::updateCounters() -{ - // start over - bv()->buffer()->params().getLyXTextClass().counters().reset(); - - bool update_pos = false; - - pit_type end = paragraphs().size(); - for (pit_type pit = 0; pit != end; ++pit) { - string const oldLabel = pars_[pit].params().labelString(); - size_t maxdepth = 0; - if (pit != 0) - maxdepth = pars_[pit - 1].getMaxDepthAfter(); - - if (pars_[pit].params().depth() > maxdepth) - pars_[pit].params().depth(maxdepth); - - // setCounter can potentially change the labelString. - setCounter(*bv()->buffer(), pit); - string const & newLabel = pars_[pit].params().labelString(); - if (oldLabel != newLabel) { - //lyxerr[Debug::DEBUG] << "changing labels: old: " << oldLabel << " new: " - // << newLabel << endl; - update_pos = true; - } - } -} - - // this really should just insert the inset and not move the cursor. void LyXText::insertInset(LCursor & cur, InsetBase * inset) { @@ -910,7 +592,8 @@ void LyXText::insertStringAsLines(LCursor & cur, string const & str) // only to be sure, should not be neccessary cur.clearSelection(); - cur.buffer().insertStringAsLines(pars_, pit, pos, current_font, str); + cur.buffer().insertStringAsLines(pars_, pit, pos, current_font, str, + autoBreakRows_); cur.resetAnchor(); setCursor(cur, cur.pit(), pos); @@ -1128,6 +811,11 @@ pos_type LyXText::getColumnNearX(pit_type const pit, c = end - 1; } + if (row.pos() < end && c >= end + && par.isInset(end) && par.getInset(end)->display()) { + c = end - 1; + } + x = int(tmpx) + xo; return c - row.pos(); } @@ -1137,8 +825,8 @@ pos_type LyXText::getColumnNearX(pit_type const pit, pit_type LyXText::getPitNearY(int y) const { BOOST_ASSERT(!paragraphs().empty()); - BOOST_ASSERT(theCoords.pars_.find(this) != theCoords.pars_.end()); - CoordCache::InnerParPosCache const & cc = theCoords.pars_[this]; + BOOST_ASSERT(theCoords.getParPos().find(this) != theCoords.getParPos().end()); + CoordCache::InnerParPosCache const & cc = theCoords.getParPos().find(this)->second; lyxerr << "LyXText::getPitNearY: y: " << y << " cache size: " << cc.size() << endl; @@ -1174,6 +862,7 @@ Row const & LyXText::getRowNearY(int y, pit_type pit) const return *rit; } + // x,y are absolute screen coordinates // sets cursor recursively descending into nested editable insets InsetBase * LyXText::editXY(LCursor & cur, int x, int y) const @@ -1194,12 +883,12 @@ InsetBase * LyXText::editXY(LCursor & cur, int x, int y) const InsetBase * inset = checkInsetHit(x, y); lyxerr << "inset " << inset << " hit at x: " << x << " y: " << y << endl; if (!inset) { - //either we deconst editXY or better we move current_font - //and real_current_font to LCursor + // Either we deconst editXY or better we move current_font + // and real_current_font to LCursor const_cast(this)->setCurrentFont(cur); return 0; } - + // This should be just before or just behind the // cursor position set above. BOOST_ASSERT((pos != 0 && inset == pars_[pit].getInset(pos - 1)) @@ -1229,49 +918,52 @@ bool LyXText::checkAndActivateInset(LCursor & cur, bool front) } -void LyXText::cursorLeft(LCursor & cur) +bool LyXText::cursorLeft(LCursor & cur) { if (cur.pos() != 0) { bool boundary = cur.boundary(); - setCursor(cur, cur.pit(), cur.pos() - 1, true, false); + bool updateNeeded = setCursor(cur, cur.pit(), cur.pos() - 1, true, false); if (!checkAndActivateInset(cur, false)) { if (false && !boundary && bidi.isBoundary(cur.buffer(), cur.paragraph(), cur.pos() + 1)) - setCursor(cur, cur.pit(), cur.pos() + 1, true, true); + updateNeeded |= + setCursor(cur, cur.pit(), cur.pos() + 1, true, true); } - return; + return updateNeeded; } if (cur.pit() != 0) { - // steps into the paragraph above - setCursor(cur, cur.pit() - 1, getPar(cur.pit() - 1).size()); + // Steps into the paragraph above + return setCursor(cur, cur.pit() - 1, getPar(cur.pit() - 1).size()); } + return false; } -void LyXText::cursorRight(LCursor & cur) +bool LyXText::cursorRight(LCursor & cur) { if (false && cur.boundary()) { - setCursor(cur, cur.pit(), cur.pos(), true, false); - return; + return setCursor(cur, cur.pit(), cur.pos(), true, false); } if (cur.pos() != cur.lastpos()) { + bool updateNeeded = false; if (!checkAndActivateInset(cur, true)) { - setCursor(cur, cur.pit(), cur.pos() + 1, true, false); + updateNeeded |= setCursor(cur, cur.pit(), cur.pos() + 1, true, false); if (false && bidi.isBoundary(cur.buffer(), cur.paragraph(), cur.pos())) - setCursor(cur, cur.pit(), cur.pos(), true, true); + updateNeeded |= setCursor(cur, cur.pit(), cur.pos(), true, true); } - return; + return updateNeeded; } if (cur.pit() != cur.lastpit()) - setCursor(cur, cur.pit() + 1, 0); + return setCursor(cur, cur.pit() + 1, 0); + return false; } -void LyXText::cursorUp(LCursor & cur) +bool LyXText::cursorUp(LCursor & cur) { Paragraph const & par = cur.paragraph(); int const row = par.pos2row(cur.pos()); @@ -1279,62 +971,102 @@ void LyXText::cursorUp(LCursor & cur) if (!cur.selection()) { int const y = bv_funcs::getPos(cur).y_; + LCursor old = cur; editXY(cur, x, y - par.rows()[row].ascent() - 1); - return; + + // This happens when you move out of an inset. + // And to give the DEPM the possibility of doing + // something we must provide it with two different + // cursors. (Lgb) + LCursor dummy = cur; + if (dummy == old) + ++dummy.pos(); + + return deleteEmptyParagraphMechanism(dummy, old); } + bool updateNeeded = false; + if (row > 0) { - setCursor(cur, cur.pit(), x2pos(cur.pit(), row - 1, x)); + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), row - 1, x)); } else if (cur.pit() > 0) { --cur.pit(); - setCursor(cur, cur.pit(), x2pos(cur.pit(), cur.paragraph().rows().size() - 1, x)); - + //cannot use 'par' now + updateNeeded |= setCursor(cur, cur.pit(), x2pos(cur.pit(), cur.paragraph().rows().size() - 1, x)); } cur.x_target() = x; + + return updateNeeded; } -void LyXText::cursorDown(LCursor & cur) +bool LyXText::cursorDown(LCursor & cur) { - - Paragraph const & par = cur.paragraph(); int const row = par.pos2row(cur.pos()); int const x = cur.targetX(); if (!cur.selection()) { int const y = bv_funcs::getPos(cur).y_; + LCursor old = cur; editXY(cur, x, y + par.rows()[row].descent() + 1); - return; + + // This happens when you move out of an inset. + // And to give the DEPM the possibility of doing + // something we must provide it with two different + // cursors. (Lgb) + LCursor dummy = cur; + if (dummy == old) + ++dummy.pos(); + + bool const changed = deleteEmptyParagraphMechanism(dummy, old); + + // Make sure that cur gets back whatever happened to dummy(Lgb) + if (changed) + cur = dummy; + + return changed; + } - + + bool updateNeeded = false; + if (row + 1 < int(par.rows().size())) { - setCursor(cur, cur.pit(), x2pos(cur.pit(), row + 1, x)); + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), row + 1, x)); } else if (cur.pit() + 1 < int(paragraphs().size())) { ++cur.pit(); - setCursor(cur, cur.pit(), x2pos(cur.pit(), 0, x)); + updateNeeded |= setCursor(cur, cur.pit(), + x2pos(cur.pit(), 0, x)); } - + cur.x_target() = x; + + return updateNeeded; } -void LyXText::cursorUpParagraph(LCursor & cur) +bool LyXText::cursorUpParagraph(LCursor & cur) { + bool updated = false; if (cur.pos() > 0) - setCursor(cur, cur.pit(), 0); + updated = setCursor(cur, cur.pit(), 0); else if (cur.pit() != 0) - setCursor(cur, cur.pit() - 1, 0); + updated = setCursor(cur, cur.pit() - 1, 0); + return updated; } -void LyXText::cursorDownParagraph(LCursor & cur) +bool LyXText::cursorDownParagraph(LCursor & cur) { + bool updated = false; if (cur.pit() != cur.lastpit()) - setCursor(cur, cur.pit() + 1, 0); + updated = setCursor(cur, cur.pit() + 1, 0); else - setCursor(cur, cur.pit(), cur.lastpos()); + updated = setCursor(cur, cur.pit(), cur.lastpos()); + return updated; } @@ -1342,16 +1074,16 @@ void LyXText::cursorDownParagraph(LCursor & cur) // position. Called by deleteEmptyParagraphMechanism void LyXText::fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where) { - // do notheing if cursor is not in the paragraph where the + // Do nothing if cursor is not in the paragraph where the // deletion occured, if (cur.pit() != where.pit()) return; - // if cursor position is after the deletion place update it + // If cursor position is after the deletion place update it if (cur.pos() > where.pos()) --cur.pos(); - // check also if we don't want to set the cursor on a spot behind the + // Check also if we don't want to set the cursor on a spot behind the // pagragraph because we erased the last character. if (cur.pos() > cur.lastpos()) cur.pos() = cur.lastpos(); @@ -1360,7 +1092,6 @@ void LyXText::fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where) bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) { - BOOST_ASSERT(cur.size() == old.size()); // Would be wrong to delete anything if we have a selection. if (cur.selection()) return false; @@ -1403,6 +1134,10 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) && old.pos() < oldpar.size() && oldpar.isLineSeparator(old.pos()) && oldpar.isLineSeparator(old.pos() - 1)) { + // We need to set the text to Change::INSERTED to + // get it erased properly + pars_[old.pit()].setChange(old.pos() -1, + Change::INSERTED); pars_[old.pit()].erase(old.pos() - 1); #ifdef WITH_WARNINGS #warning This will not work anymore when we have multiple views of the same buffer @@ -1416,7 +1151,7 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) #warning DEPM, look here #endif //fixCursorAfterDelete(cur.anchor(), old.top()); - return false; + return true; } } @@ -1438,8 +1173,6 @@ bool LyXText::deleteEmptyParagraphMechanism(LCursor & cur, LCursor const & old) if (oldpar.empty() || (oldpar.size() == 1 && oldpar.isLineSeparator(0))) { // ok, we will delete something - CursorSlice tmpcursor; - deleted = true; bool selection_position_was_oldcursor_position =