};
-void LyXText::rowBreakPoint(Buffer const & buffer, pit_type const pit,
- Row & row) const
+void LyXText::rowBreakPoint(Buffer const & buffer, int right_margin,
+ pit_type const pit, Row & row) const
{
Paragraph const & par = pars_[pit];
pos_type const end = par.size();
}
// maximum pixel width of a row
- int width = maxwidth_ - rightMargin(buffer, par); // - leftMargin(buffer, pit, row);
+ int width = maxwidth_ - right_margin; // - leftMargin(buffer, pit, row);
if (width < 0) {
row.endpos(end);
return;
Change(Change::INSERTED));
}
+ // FIXME: Breaking a paragraph has nothing to do with setting a cursor.
+ // Because of the mix between the model (the paragraph contents) and the
+ // view (the paragraph breaking in rows, we have to do this here before
+ // the setCursor() call below.
+ bool changed_height = redoParagraph(cur.bv(), cpit);
+ changed_height |= redoParagraph(cur.bv(), cpit + 1);
+ if (changed_height)
+ // A singlePar update is not enough in this case.
+ cur.updateFlags(Update::Force);
+
+
// This check is necessary. Otherwise the new empty paragraph will
// be deleted automatically. And it is more friendly for the user!
if (cur.pos() != 0 || isempty)
}
par.insertChar(cur.pos(), c, current_font, cur.buffer().params().trackChanges);
+
+ // FIXME: Inserting a character has nothing to do with setting a cursor.
+ // Because of the mix between the model (the paragraph contents) and the
+ // view (the paragraph breaking in rows, we have to do this here.
+ if (redoParagraph(cur.bv(), cur.pit()))
+ // A singlePar update is not enough in this case.
+ cur.updateFlags(Update::Force);
setCursor(cur, cur.pit(), cur.pos() + 1, false, cur.boundary());
charInserted();
}
{
BOOST_ASSERT(this == cur.text());
bool needsUpdate = false;
+ Paragraph & par = cur.paragraph();
if (cur.pos() != cur.lastpos()) {
- recordUndo(cur, Undo::DELETE, cur.pit());
- setCursorIntern(cur, cur.pit(), cur.pos() + 1, false, cur.boundary());
- needsUpdate = backspace(cur);
+ // this is the code for a normal delete, not pasting
+ // any paragraphs
+ recordUndo(cur, Undo::DELETE);
// FIXME: change tracking (MG)
- if (cur.paragraph().isDeleted(cur.pos()))
- cur.posRight();
+ par.eraseChar(cur.pos(), cur.buffer().params().trackChanges);
+ if (par.isDeleted(cur.pos()))
+ cur.forwardPos();
+ needsUpdate = true;
} else if (cur.pit() != cur.lastpit()) {
- LCursor scur = cur;
-
- setCursorIntern(cur, cur.pit() + 1, 0, false, false);
- if (pars_[cur.pit()].layout() == pars_[scur.pit()].layout()) {
- recordUndo(scur, Undo::DELETE, scur.pit());
- needsUpdate = backspace(cur);
- if (cur.buffer().params().trackChanges) {
- // FIXME: Change tracking (MG)
- // move forward after the paragraph break is DELETED
- Paragraph & par = cur.paragraph();
- // FIXME: change tracking (MG)
- if (par.isDeleted(par.size()))
- setCursorIntern(cur, cur.pit() + 1, 0);
- }
+ if (cur.buffer().params().trackChanges
+ && par.isInserted(cur.pos())) {
+ // mark "carriage return" as deleted:
+ // FIXME: Change tracking (MG)
+ par.setChange(cur.pos(), Change(Change::DELETED));
+ cur.forwardPos();
+ needsUpdate = true;
} else {
- setCursorIntern(scur, scur.pit(), scur.pos(), false, scur.boundary());
+ setCursorIntern(cur, cur.pit() + 1, 0);
+ needsUpdate = backspacePos0(cur);
+ // FIXME: Change tracking (MG)
+ if (cur.paragraph().isDeleted(cur.pos()))
+ cur.forwardPos();
}
} else
needsUpdate = dissolveInset(cur);
+ // FIXME: Inserting characters has nothing to do with setting a cursor.
+ // Because of the mix between the model (the paragraph contents)
+ // and the view (the paragraph breaking in rows, we have to do this
+ // here before the setCursorIntern() call.
+ if (needsUpdate) {
+ if (redoParagraph(cur.bv(), cur.pit()))
+ // A singlePar update is not enough in this case.
+ cur.updateFlags(Update::Force);
+ // Make sure the cursor is correct. Is this really needed?
+ // No, not really... at least not here!
+ setCursorIntern(cur, cur.pit(), cur.pos());
+ }
+
return needsUpdate;
}
bool LyXText::backspacePos0(LCursor & cur)
{
BOOST_ASSERT(this == cur.text());
+ if (cur.pit() == 0)
+ return false;
+
bool needsUpdate = false;
- Paragraph & par = cur.paragraph();
- // is it an empty paragraph?
- pos_type lastpos = cur.lastpos();
- if (lastpos == 0 || (lastpos == 1 && par.isSeparator(0))) {
- // This is an empty paragraph and we delete it just
- // by moving the cursor one step
- // left and let the DeleteEmptyParagraphMechanism
- // handle the actual deletion of the paragraph.
-
- if (cur.pit() != 0) {
- // For KeepEmpty layouts we need to get
- // rid of the keepEmpty setting first.
- // And the only way to do this is to
- // reset the layout to something
- // else: f.ex. the default layout.
- if (par.allowEmpty()) {
- Buffer & buf = cur.buffer();
- BufferParams const & bparams = buf.params();
- par.layout(bparams.getLyXTextClass().defaultLayout());
- }
+ BufferParams const & bufparams = cur.buffer().params();
+ LyXTextClass const & tclass = bufparams.getLyXTextClass();
+ ParagraphList & plist = cur.text()->paragraphs();
+ Paragraph const & par = cur.paragraph();
+ LCursor prevcur = cur;
+ --prevcur.pit();
+ prevcur.pos() = prevcur.lastpos();
+ Paragraph const & prevpar = prevcur.paragraph();
- cursorLeft(cur);
- return true;
- }
+ // is it an empty paragraph?
+ if (cur.lastpos() == 0
+ || (cur.lastpos() == 1 && par.isSeparator(0))) {
+ recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+ plist.erase(boost::next(plist.begin(), cur.pit()));
+ needsUpdate = true;
}
-
- if (cur.pit() != 0)
- recordUndo(cur, Undo::DELETE, cur.pit() - 1);
-
- pit_type tmppit = cur.pit();
- // We used to do cursorLeftIntern() here, but it is
- // not a good idea since it triggers the auto-delete
- // mechanism. So we do a cursorLeftIntern()-lite,
- // without the dreaded mechanism. (JMarc)
- if (cur.pit() != 0) {
- // steps into the above paragraph.
- setCursorIntern(cur, cur.pit() - 1,
- pars_[cur.pit() - 1].size(),
- false);
+ // is previous par empty?
+ else if (prevcur.lastpos() == 0
+ || (prevcur.lastpos() == 1 && prevpar.isSeparator(0))) {
+ recordUndo(cur, Undo::ATOMIC, prevcur.pit(), cur.pit());
+ plist.erase(boost::next(plist.begin(), prevcur.pit()));
+ needsUpdate = true;
}
-
// Pasting is not allowed, if the paragraphs have different
// layout. I think it is a real bug of all other
// word processors to allow it. It confuses the user.
// Correction: Pasting is always allowed with standard-layout
- // Correction (Jug 20050717): Remove check about alignment!
- Buffer & buf = cur.buffer();
- BufferParams const & bufparams = buf.params();
- LyXTextClass const & tclass = bufparams.getLyXTextClass();
- pit_type const cpit = cur.pit();
-
- if (cpit != tmppit
- && (pars_[cpit].layout() == pars_[tmppit].layout()
- || pars_[tmppit].layout() == tclass.defaultLayout()))
- {
- mergeParagraph(bufparams, pars_, cpit);
+ else if (par.layout() == prevpar.layout()
+ || par.layout() == tclass.defaultLayout()) {
+ recordUndo(cur, Undo::ATOMIC, prevcur.pit());
+ mergeParagraph(bufparams, plist, prevcur.pit());
needsUpdate = true;
+ }
- if (cur.pos() != 0 && pars_[cpit].isSeparator(cur.pos() - 1))
- --cur.pos();
-
- // the counters may have changed
- ParIterator par_it(cur);
- updateLabels(cur.buffer(), par_it);
-
- setCursor(cur, cur.pit(), cur.pos(), false);
+ if (needsUpdate) {
+ updateLabels(cur.buffer());
+ setCursorIntern(cur, prevcur.pit(), prevcur.pos());
}
+
return needsUpdate;
}
+
+
bool LyXText::backspace(LCursor & cur)
{
BOOST_ASSERT(this == cur.text());
if (cur.pit() == 0)
return dissolveInset(cur);
- // The cursor is at the beginning of a paragraph, so
- // the the backspace will collapse two paragraphs into
- // one.
-
- if (cur.pit() != 0 && cur.buffer().params().trackChanges) {
+ if (cur.buffer().params().trackChanges) {
// FIXME: Change tracking (MG)
// Previous paragraph, mark "carriage return" as
// deleted:
}
}
+ // The cursor is at the beginning of a paragraph, so
+ // the backspace will collapse two paragraphs into one.
needsUpdate = backspacePos0(cur);
} else {
if (cur.pos() == cur.lastpos())
setCurrentFont(cur);
+ // FIXME: Backspacing has nothing to do with setting a cursor.
+ // Because of the mix between the model (the paragraph contents)
+ // and the view (the paragraph breaking in rows, we have to do this
+ // here before the setCursor() call.
+ if (redoParagraph(cur.bv(), cur.pit()))
+ // A singlePar update is not enough in this case.
+ cur.updateFlags(Update::Force);
setCursor(cur, cur.pit(), cur.pos(), false, cur.boundary());
return needsUpdate;
if (isMainText(*cur.bv().buffer()) || cur.inset().nargs() != 1)
return false;
+ bool const in_ert = cur.inset().lyxCode() == InsetBase::ERT_CODE;
recordUndoInset(cur);
cur.selHandle(false);
// save position
// FIXME: change tracking (MG)
cur.paragraph().eraseChar(cur.pos(), b.params().trackChanges);
if (!plist.empty()) {
+ if (in_ert) {
+ // ERT paragraphs have the Language latex_language.
+ // This is invalid outside of ERT, so we need to
+ // change it to the buffer language.
+ ParagraphList::iterator it = plist.begin();
+ ParagraphList::iterator it_end = plist.end();
+ for (; it != it_end; it++) {
+ it->changeLanguage(b.params(),
+ latex_language,
+ b.getLanguage());
+ }
+ }
+
pasteParagraphList(cur, plist, b.params().textclass,
b.errorList("Paste"));
// restore position
}
}
+ // Optimisation: this is used in the next two loops
+ // so better to calculate that once here.
+ int right_margin = rightMargin(buffer, par);
+
// redo insets
// FIXME: We should always use getFont(), see documentation of
// noFontChange() in insetbase.h.
for (; ii != iend; ++ii) {
Dimension dim;
int const w = maxwidth_ - leftMargin(buffer, pit, ii->pos)
- - rightMargin(buffer, par);
+ - right_margin;
LyXFont const & font = ii->inset->noFontChange() ?
bufferfont :
getFont(buffer, par, ii->pos);
pos_type z = 0;
do {
Row row(z);
- rowBreakPoint(buffer, pit, row);
+ rowBreakPoint(buffer, right_margin, pit, row);
setRowWidth(buffer, pit, row);
setHeightOfRow(bv, pit, row);
par.rows().push_back(row);
dim.asc += par.rows()[0].ascent();
dim.des -= par.rows()[0].ascent();
- bool const same = dim == par.dim();
+ bool const same = dim.height() == par.dim().height();
par.dim() = dim;
//lyxerr << "redoParagraph: " << par.rows().size() << " rows\n";
}
-#if 0
// only used for inset right now. should also be used for main text
-void LyXText::drawSelection(PainterInfo & pi, int x , int) const
-{
- LCursor & cur = pi.base.bv->cursor();
- if (!cur.selection())
- return;
- if (!ptr_cmp(cur.text(), this))
- return;
-
- lyxerr << "draw selection at " << x << endl;
-
- DocIterator beg = cur.selectionBegin();
- DocIterator end = cur.selectionEnd();
-
- BufferView & bv = pi.base.bv;
- Buffer const & buffer = *bv.buffer();
-
- // the selection doesn't touch the visible screen
- if (bv_funcs::status(&bv, beg) == bv_funcs::CUR_BELOW
- || bv_funcs::status(&bv, end) == bv_funcs::CUR_ABOVE)
- return;
-
- Paragraph const & par1 = pars_[beg.pit()];
- Paragraph const & par2 = pars_[end.pit()];
-
- Row const & row1 = par1.getRow(beg.pos(), beg.boundary());
- Row const & row2 = par2.getRow(end.pos(), end.boundary());
-
- int y1,x1,x2;
- if (bv_funcs::status(&bv, beg) == bv_funcs::CUR_ABOVE) {
- y1 = 0;
- x1 = 0;
- x2 = 0;
- } else {
- y1 = bv_funcs::getPos(beg).y_ - row1.ascent();
- int const startx = cursorX(buffer, beg.top(), begin.boundary());
- if (isRTL(buffer, par1)) {
- x1 = startx;
- x2 = 0 + dim_.wid;
- }
- else {
- x1 = 0;
- x2 = startx;
- }
- }
-
- int y2,X1,X2;
- if (bv_funcs::status(&bv, end) == bv_funcs::CUR_BELOW) {
- y2 = bv.workHeight();
- X1 = 0;
- X2 = 0;
- } else {
- y2 = bv_funcs::getPos(end).y_ + row2.descent();
- int const endx = cursorX(buffer, end.top(), end.boundary());
- if (isRTL(buffer, par2)) {
- X1 = 0;
- X2 = endx;
- }
- else {
- X1 = endx;
- X2 = 0 + dim_.wid;
- }
- }
-
- lyxerr << " y1: " << y1 << " y2: " << y2
- << " xo: " << xo_ << " wid: " << dim_.wid
- << endl;
-
- // paint big rectangle in one go
- pi.pain.fillRectangle(x, y1, dim_.wid, y2 - y1, LColor::selection);
-
- // reset background at begin of first selected line
- pi.pain.fillRectangle(x + x1, y1, x2 - x1, row1.height(),
- LColor::background);
-
- // reset background at end of last selected line
- pi.pain.fillRectangle(x + X1, y2 - row2.height(),
- X2 - X1, row2.height(), LColor::background);
-}
-
-#else
-
void LyXText::drawSelection(PainterInfo & pi, int x, int) const
{
LCursor & cur = pi.base.bv->cursor();
if (!ptr_cmp(cur.text(), this))
return;
- lyxerr[Debug::DEBUG]
- << BOOST_CURRENT_FUNCTION
- << "draw selection at " << x
- << endl;
+ if (lyxerr.debugging(Debug::DEBUG)) {
+ lyxerr[Debug::DEBUG]
+ << BOOST_CURRENT_FUNCTION
+ << "draw selection at " << x
+ << endl;
+ }
DocIterator beg = cur.selectionBegin();
DocIterator end = cur.selectionEnd();
return;
}
- lyxerr[Debug::DEBUG] << " y1: " << y1 << " y2: " << y2
- << "X1:" << X1 << " x2: " << X2 << " wid: " << dim_.wid
- << endl;
+ if (lyxerr.debugging(Debug::DEBUG)) {
+ lyxerr[Debug::DEBUG] << " y1: " << y1 << " y2: " << y2
+ << "X1:" << X1 << " x2: " << X2 << " wid: " << dim_.wid
+ << endl;
+ }
// paint upper rectangle
pi.pain.fillRectangle(x + x1, y1, x2 - x1, y2 - y1,
pi.pain.fillRectangle(x, y2, dim_.wid,
Y1 - y2, LColor::selection);
}
-#endif
bool LyXText::isLastRow(pit_type pit, Row const & row) const
{
}
-string LyXText::getPossibleLabel(LCursor & cur) const
+docstring LyXText::getPossibleLabel(LCursor & cur) const
{
pit_type pit = cur.pit();
}
}
- string name = layout->latexname();
+ docstring name = from_ascii(layout->latexname());
// for captions, we want the abbreviation of the float type
if (layout->labeltype == LABEL_SENSITIVE) {
InsetBase * const in = &cur[i].inset();
if (in->lyxCode() == InsetBase::FLOAT_CODE
|| in->lyxCode() == InsetBase::WRAP_CODE) {
- name = to_utf8(in->getInsetName());
+ name = in->getInsetName();
break;
}
}
}
- string text = name.substr(0, 3);
+ docstring text = name.substr(0, 3);
if (name == "theorem")
- text = "thm"; // Create a correct prefix for prettyref
+ text = from_ascii("thm"); // Create a correct prefix for prettyref
text += ':';
if (layout->latextype == LATEX_PARAGRAPH || lyxrc.label_init_length < 0)
text.erase();
- // FIXME UNICODE
- string par_text = to_utf8(pars_[pit].asString(cur.buffer(), false));
+ docstring par_text = pars_[pit].asString(cur.buffer(), false);
for (int i = 0; i < lyxrc.label_init_length; ++i) {
if (par_text.empty())
break;
- string head;
+ docstring head;
par_text = split(par_text, head, ' ');
// Is it legal to use spaces in labels ?
if (i > 0)
}
+void LyXText::charsTranspose(LCursor & cur)
+{
+ BOOST_ASSERT(this == cur.text());
+
+ pos_type pos = cur.pos();
+
+ // If cursor is at beginning or end of paragraph, do nothing.
+ if (pos == cur.lastpos() || pos == 0)
+ return;
+
+ Paragraph & par = cur.paragraph();
+
+ // Get the positions of the characters to be transposed.
+ pos_type pos1 = pos - 1;
+ pos_type pos2 = pos;
+
+ // In change tracking mode, ignore deleted characters.
+ while (pos2 < cur.lastpos() && par.isDeleted(pos2))
+ ++pos2;
+ if (pos2 == cur.lastpos())
+ return;
+
+ while (pos1 >= 0 && par.isDeleted(pos1))
+ --pos1;
+ if (pos1 < 0)
+ return;
+
+ // Don't do anything if one of the "characters" is not regular text.
+ if (par.isInset(pos1) || par.isInset(pos2))
+ return;
+
+ // Store the characters to be transposed (including font information).
+ char_type char1 = par.getChar(pos1);
+ LyXFont const font1 =
+ par.getFontSettings(cur.buffer().params(), pos1);
+
+ char_type char2 = par.getChar(pos2);
+ LyXFont const font2 =
+ par.getFontSettings(cur.buffer().params(), pos2);
+
+ // And finally, we are ready to perform the transposition.
+ // Track the changes if Change Tracking is enabled.
+ bool const trackChanges = cur.buffer().params().trackChanges;
+
+ recordUndo(cur);
+
+ par.eraseChar(pos2, trackChanges);
+ par.eraseChar(pos1, trackChanges);
+ par.insertChar(pos1, char2, font2, trackChanges);
+ par.insertChar(pos2, char1, font1, trackChanges);
+
+ // After the transposition, move cursor to after the transposition.
+ setCursor(cur, cur.pit(), pos2);
+ cur.forwardPos();
+}
+
+
} // namespace lyx