par.insertInset(par.size(), inset, font, change);
else {
lex.eatLine();
- docstring line = from_utf8(lex.getString());
+ docstring line = lex.getDocString();
errorList.push_back(ErrorItem(_("Unknown Inset"), line,
par.id(), 0, par.size()));
}
par.insertInset(par.size(), new InsetLine, font, change);
} else if (token == "\\newpage") {
par.insertInset(par.size(), new InsetPagebreak, font, change);
+ } else if (token == "\\clearpage") {
+ par.insertInset(par.size(), new InsetClearPage, font, change);
+ } else if (token == "\\cleardoublepage") {
+ par.insertInset(par.size(), new InsetClearDoublePage, font, change);
} else if (token == "\\change_unchanged") {
change = Change(Change::UNCHANGED);
} else if (token == "\\change_inserted") {
lex.eatLine();
errorList.push_back(ErrorItem(_("Unknown token"),
bformat(_("Unknown token: %1$s %2$s\n"), from_utf8(token),
- from_utf8(lex.getString())),
+ lex.getDocString()),
par.id(), 0, par.size()));
}
}
}
-namespace {
-
-}
-
void LyXText::breakParagraph(LCursor & cur, bool keep_layout)
{
BOOST_ASSERT(this == cur.text());
// this is only allowed, if the current paragraph is not empty
// or caption and if it has not the keepempty flag active
- if (cur.lastpos() == 0 && !cpar.allowEmpty()
- && layout->labeltype != LABEL_SENSITIVE)
+ if (cur.lastpos() == 0 && !cpar.allowEmpty() &&
+ layout->labeltype != LABEL_SENSITIVE)
return;
// a layout change may affect also the following paragraph
// Always break behind a space
// It is better to erase the space (Dekel)
if (cur.pos() != cur.lastpos() && cpar.isLineSeparator(cur.pos()))
- // FIXME: change tracking (MG)
cpar.eraseChar(cur.pos(), cur.buffer().params().trackChanges);
- // How should the layout for the new paragraph be?
+ // What should the layout for the new paragraph be?
int preserve_layout = 0;
if (keep_layout)
preserve_layout = 2;
}
while (!pars_[next_par].empty() && pars_[next_par].isNewline(0))
- // FIXME: change tracking (MG)
pars_[next_par].eraseChar(0, cur.buffer().params().trackChanges);
ParIterator current_it(cur);
updateLabels(cur.buffer(), current_it, last_it);
- // Mark "carriage return" as inserted if change tracking:
- if (cur.buffer().params().trackChanges) {
- // FIXME: Change tracking (MG)
- cur.paragraph().setChange(cur.paragraph().size(),
- 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!
}
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();
}
void LyXText::acceptChange(LCursor & cur)
{
+ // FIXME: change tracking (MG)
+
BOOST_ASSERT(this == cur.text());
+
if (!cur.selection() && cur.lastpos() != 0)
return;
+ // FIXME: we must handle start = end = 0
+
recordUndoSelection(cur, Undo::INSERT);
DocIterator it = cur.selectionBegin();
DocIterator et = cur.selectionEnd();
pit_type pit = it.pit();
- bool isDeleted = pars_[pit].isDeleted(it.pos());
for (; pit <= et.pit(); ++pit) {
- pos_type left = ( pit == it.pit() ? it.pos() : 0 );
- pos_type right =
- ( pit == et.pit() ? et.pos() : pars_[pit].size() + 1 );
+ pos_type left = (pit == it.pit() ? it.pos() : 0);
+ pos_type right = (pit == et.pit() ? et.pos() : pars_[pit].size());
pars_[pit].acceptChanges(left, right);
- }
- if (isDeleted) {
- ParagraphList & plist = paragraphs();
- if (it.pit() + 1 < et.pit())
- pars_.erase(boost::next(plist.begin(), it.pit() + 1),
- boost::next(plist.begin(), et.pit()));
- // Paragraph merge if appropriate:
- // FIXME: change tracking (MG)
- if (pars_[it.pit()].isDeleted(pars_[it.pit()].size())) {
- setCursorIntern(cur, it.pit() + 1, 0);
- backspacePos0(cur);
- }
+ // merge paragraph if appropriate:
+ // if (right >= pars_[pit].size() && pit + 1 < et.pit() &&
+ // pars_[pit].isDeleted(pars_[pit].size())) {
+ // setCursorIntern(cur, pit + 1, 0);
+ // backspacePos0(cur);
+ //}
}
finishUndo();
cur.clearSelection();
void LyXText::rejectChange(LCursor & cur)
{
+ // FIXME: change tracking (MG)
+
BOOST_ASSERT(this == cur.text());
+
if (!cur.selection() && cur.lastpos() != 0)
return;
+ // FIXME: we must handle start = end = 0
+
recordUndoSelection(cur, Undo::INSERT);
DocIterator it = cur.selectionBegin();
DocIterator et = cur.selectionEnd();
pit_type pit = it.pit();
- bool isInserted = pars_[pit].isInserted(it.pos());
for (; pit <= et.pit(); ++pit) {
- pos_type left = ( pit == it.pit() ? it.pos() : 0 );
- pos_type right =
- ( pit == et.pit() ? et.pos() : pars_[pit].size() + 1 );
+ pos_type left = (pit == it.pit() ? it.pos() : 0);
+ pos_type right = (pit == et.pit() ? et.pos() : pars_[pit].size());
pars_[pit].rejectChanges(left, right);
- }
- if (isInserted) {
- ParagraphList & plist = paragraphs();
- if (it.pit() + 1 < et.pit())
- pars_.erase(boost::next(plist.begin(), it.pit() + 1),
- boost::next(plist.begin(), et.pit()));
- // Paragraph merge if appropriate:
- // FIXME: change tracking (MG)
- if (pars_[it.pit()].isInserted(pars_[it.pit()].size())) {
- setCursorIntern(cur, it.pit() + 1, 0);
- backspacePos0(cur);
- }
+
+ // merge paragraph if appropriate:
+ // if (right >= pars_[pit].size() && pit + 1 < et.pit() &&
+ // pars_[pit].isInserted(pars_[pit].size())) {
+ // setCursorIntern(cur, pit + 1, 0);
+ // backspacePos0(cur);
+ //}
}
finishUndo();
cur.clearSelection();
// this is the code for a normal delete, not pasting
// any paragraphs
recordUndo(cur, Undo::DELETE);
- // FIXME: change tracking (MG)
par.eraseChar(cur.pos(), cur.buffer().params().trackChanges);
if (par.isDeleted(cur.pos()))
- cur.forwardPos();
+ cur.forwardPosNoDescend();
needsUpdate = true;
- } else if (cur.pit() != cur.lastpit()) {
- if (cur.buffer().params().trackChanges
- && par.isInserted(cur.pos())) {
- // mark "carriage return" as deleted:
- // FIXME: Change tracking (MG)
+ } else {
+ if (cur.pit() == cur.lastpit())
+ return dissolveInset(cur);
+
+ if (!par.isMergedOnEndOfParDeletion(cur.buffer().params().trackChanges)) {
par.setChange(cur.pos(), Change(Change::DELETED));
cur.forwardPos();
needsUpdate = true;
} else {
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);
+ }
- // Make sure the cursor is correct. Is this really needed?
- if (needsUpdate)
- setCursorIntern(cur, cur.pit(), cur.pos());
+ // 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!
+ cur.text()->setCursorIntern(cur, cur.pit(), cur.pos());
+ }
return needsUpdate;
}
needsUpdate = true;
}
// Pasting is not allowed, if the paragraphs have different
- // layout. I think it is a real bug of all other
+ // layouts. 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
else if (par.layout() == prevpar.layout()
}
-
-
bool LyXText::backspace(LCursor & cur)
{
BOOST_ASSERT(this == cur.text());
if (cur.pit() == 0)
return dissolveInset(cur);
- if (cur.buffer().params().trackChanges) {
- // FIXME: Change tracking (MG)
- // Previous paragraph, mark "carriage return" as
- // deleted:
- Paragraph & par = pars_[cur.pit() - 1];
- // Take care of a just inserted para break:
- // FIXME: change tracking (MG)
- if (!par.isInserted(par.size())) {
- // FIXME: change tracking (MG)
- par.setChange(par.size(), Change(Change::DELETED));
- setCursorIntern(cur, cur.pit() - 1, par.size());
- return true;
- }
- }
+ Paragraph & prev_par = pars_[cur.pit() - 1];
+ if (!prev_par.isMergedOnEndOfParDeletion(cur.buffer().params().trackChanges)) {
+ prev_par.setChange(prev_par.size(), Change(Change::DELETED));
+ setCursorIntern(cur, cur.pit() - 1, prev_par.size());
+ return true;
+ }
// The cursor is at the beginning of a paragraph, so
// the backspace will collapse two paragraphs into one.
needsUpdate = backspacePos0(cur);
// without the dreaded mechanism. (JMarc)
setCursorIntern(cur, cur.pit(), cur.pos() - 1,
false, cur.boundary());
- // FIXME: change tracking (MG)
cur.paragraph().eraseChar(cur.pos(), cur.buffer().params().trackChanges);
}
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
spos += cur.pos();
spit += cur.pit();
Buffer & b = cur.buffer();
- // 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
Paragraph & par = pars_[pit];
Buffer const & buffer = *bv.buffer();
+ bool changed = false;
+
// Add bibitem insets if necessary
if (par.layout()->labeltype == LABEL_BIBLIO) {
bool hasbibitem(false);
// FIXME: We should always use getFont(), see documentation of
// noFontChange() in insetbase.h.
LyXFont const bufferfont = buffer.params().getFont();
- InsetList::iterator ii = par.insetlist.begin();
- InsetList::iterator iend = par.insetlist.end();
+ InsetList::const_iterator ii = par.insetlist.begin();
+ InsetList::const_iterator iend = par.insetlist.end();
for (; ii != iend; ++ii) {
Dimension dim;
int const w = maxwidth_ - leftMargin(buffer, pit, ii->pos)
bufferfont :
getFont(buffer, par, ii->pos);
MetricsInfo mi(&bv, font, w);
- ii->inset->metrics(mi, dim);
+ changed |= ii->inset->metrics(mi, dim);
}
// rebreak the paragraph
dim.asc += par.rows()[0].ascent();
dim.des -= par.rows()[0].ascent();
- bool const same = dim == par.dim();
+ changed |= dim.height() != par.dim().height();
par.dim() = dim;
//lyxerr << "redoParagraph: " << par.rows().size() << " rows\n";
- return !same;
+ return changed;
}
-void LyXText::metrics(MetricsInfo & mi, Dimension & dim)
+bool LyXText::metrics(MetricsInfo & mi, Dimension & dim)
{
//BOOST_ASSERT(mi.base.textwidth);
if (mi.base.textwidth)
// save the caller's font locally:
font_ = mi.base.font;
+ bool changed = false;
+
unsigned int h = 0;
unsigned int w = 0;
for (pit_type pit = 0, n = paragraphs().size(); pit != n; ++pit) {
- redoParagraph(*mi.base.bv, pit);
+ changed |= redoParagraph(*mi.base.bv, pit);
Paragraph & par = paragraphs()[pit];
h += par.height();
if (w < par.width())
dim.asc = pars_[0].ascent();
dim.des = h - dim.asc;
+ changed |= dim_ != dim;
dim_ = dim;
+ return changed;
}
}
+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