mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-22 10:00:33 +00:00
Make sure that undo is recorded when magic tricks are played with InsetBibitem.
Fixes bug #7111: Assertion with undo and InsetBibitem * add Paragraph::brokenBiblio(), with tells whether there is something to fix. * rename Paragraph::checkBiblio to fixBiblio; simplify it greatly by using InsetList methods * In TextMetrics::redoParagraph, call recordUndo before fixBiblio (only when there is something to fix obviously) Special care is taken to update cursor only when it makes sense. Note that there are cases where undo information is not recorded (current cursor not in the slice where action happens)
This commit is contained in:
parent
33b2bc45a7
commit
7b93cc5fc4
@ -3167,70 +3167,61 @@ char_type Paragraph::transformChar(char_type c, pos_type pos) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Paragraph::checkBiblio(Buffer const & buffer)
|
bool Paragraph::brokenBiblio() const
|
||||||
{
|
{
|
||||||
// FIXME From JS:
|
// there is a problem if there is no bibitem at position 0 or
|
||||||
// This is getting more and more a mess. ...We really should clean
|
// if there is another bibitem in the paragraph.
|
||||||
// up this bibitem issue for 1.6.
|
return d->layout_->labeltype == LABEL_BIBLIO
|
||||||
|
&& (d->insetlist_.find(BIBITEM_CODE) != 0
|
||||||
|
|| d->insetlist_.find(BIBITEM_CODE, 1) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Paragraph::fixBiblio(Buffer const & buffer)
|
||||||
|
{
|
||||||
|
// FIXME: What about the case where paragraph is not BIBLIO
|
||||||
|
// but there is an InsetBibitem?
|
||||||
|
// FIXME: when there was already an inset at 0, the return value is 1,
|
||||||
|
// which does not tell whether another inset has been remove; the
|
||||||
|
// cursor cannot be correctly updated.
|
||||||
|
|
||||||
// Add bibitem insets if necessary
|
|
||||||
if (d->layout_->labeltype != LABEL_BIBLIO)
|
if (d->layout_->labeltype != LABEL_BIBLIO)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bool hasbibitem = !d->insetlist_.empty()
|
bool const track_changes = buffer.params().trackChanges;
|
||||||
// Insist on it being in pos 0
|
int bibitem_pos = d->insetlist_.find(BIBITEM_CODE);
|
||||||
&& d->text_[0] == META_INSET
|
bool const hasbibitem0 = bibitem_pos == 0;
|
||||||
&& d->insetlist_.begin()->inset->lyxCode() == BIBITEM_CODE;
|
|
||||||
|
|
||||||
bool track_changes = buffer.params().trackChanges;
|
if (hasbibitem0) {
|
||||||
|
bibitem_pos = d->insetlist_.find(BIBITEM_CODE, 1);
|
||||||
docstring oldkey;
|
// There was an InsetBibitem at pos 0, and no other one => OK
|
||||||
docstring oldlabel;
|
if (bibitem_pos == -1)
|
||||||
|
|
||||||
// remove a bibitem in pos != 0
|
|
||||||
// restore it later in pos 0 if necessary
|
|
||||||
// (e.g. if a user inserts contents _before_ the item)
|
|
||||||
// we're assuming there's only one of these, which there
|
|
||||||
// should be.
|
|
||||||
int erasedInsetPosition = -1;
|
|
||||||
InsetList::iterator it = d->insetlist_.begin();
|
|
||||||
InsetList::iterator end = d->insetlist_.end();
|
|
||||||
for (; it != end; ++it)
|
|
||||||
if (it->inset->lyxCode() == BIBITEM_CODE
|
|
||||||
&& it->pos > 0) {
|
|
||||||
InsetCommand * olditem = it->inset->asInsetCommand();
|
|
||||||
oldkey = olditem->getParam("key");
|
|
||||||
oldlabel = olditem->getParam("label");
|
|
||||||
erasedInsetPosition = it->pos;
|
|
||||||
eraseChar(erasedInsetPosition, track_changes);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There was an InsetBibitem at the beginning, and we didn't
|
|
||||||
// have to erase one.
|
|
||||||
if (hasbibitem && erasedInsetPosition < 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
// there is a bibitem at the 0 position, but since
|
||||||
// There was an InsetBibitem at the beginning and we did have to
|
// there is a second one, we copy the second on the
|
||||||
// erase one. So we give its properties to the beginning inset.
|
// first. We're assuming there are at most two of
|
||||||
if (hasbibitem) {
|
// these, which there should be.
|
||||||
InsetCommand * inset = d->insetlist_.begin()->inset->asInsetCommand();
|
// FIXME: why does it make sense to do that rather
|
||||||
if (!oldkey.empty())
|
// than keep the first? (JMarc)
|
||||||
inset->setParam("key", oldkey);
|
Inset * inset = d->insetlist_.release(bibitem_pos);
|
||||||
inset->setParam("label", oldlabel);
|
eraseChar(bibitem_pos, track_changes);
|
||||||
return -erasedInsetPosition;
|
d->insetlist_.begin()->inset = inset;
|
||||||
|
return -bibitem_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There was no inset at the beginning, so we need to create one with
|
// We need to create an inset at the beginning
|
||||||
// the key and label of the one we erased.
|
Inset * inset = 0;
|
||||||
InsetBibitem * inset =
|
if (bibitem_pos > 0) {
|
||||||
new InsetBibitem(const_cast<Buffer *>(&buffer), InsetCommandParams(BIBITEM_CODE));
|
// there was one somewhere in the paragraph, let's move it
|
||||||
// restore values of previously deleted item in this par.
|
inset = d->insetlist_.release(bibitem_pos);
|
||||||
if (!oldkey.empty())
|
eraseChar(bibitem_pos, track_changes);
|
||||||
inset->setParam("key", oldkey);
|
} else
|
||||||
inset->setParam("label", oldlabel);
|
// make a fresh one
|
||||||
insertInset(0, inset,
|
inset = new InsetBibitem(const_cast<Buffer *>(&buffer),
|
||||||
Change(track_changes ? Change::INSERTED : Change::UNCHANGED));
|
InsetCommandParams(BIBITEM_CODE));
|
||||||
|
|
||||||
|
insertInset(0, inset, Change(track_changes ? Change::INSERTED
|
||||||
|
: Change::UNCHANGED));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -440,6 +440,8 @@ public:
|
|||||||
///
|
///
|
||||||
ParagraphParameters const & params() const;
|
ParagraphParameters const & params() const;
|
||||||
|
|
||||||
|
/// Check whether a call to fixBiblio is needed.
|
||||||
|
bool brokenBiblio() const;
|
||||||
/// Check if we are in a Biblio environment and insert or
|
/// Check if we are in a Biblio environment and insert or
|
||||||
/// delete InsetBibitems as necessary.
|
/// delete InsetBibitems as necessary.
|
||||||
/// \retval int 1, if we had to add an inset, in which case
|
/// \retval int 1, if we had to add an inset, in which case
|
||||||
@ -447,7 +449,7 @@ public:
|
|||||||
/// an inset, in which case pos is the position from which the inset
|
/// an inset, in which case pos is the position from which the inset
|
||||||
/// was deleted, and the cursor will need to be moved back one if it
|
/// was deleted, and the cursor will need to be moved back one if it
|
||||||
/// was previously past that position. Return 0 otherwise.
|
/// was previously past that position. Return 0 otherwise.
|
||||||
int checkBiblio(Buffer const & buffer);
|
int fixBiblio(Buffer const & buffer);
|
||||||
|
|
||||||
/// For each author, set 'used' to true if there is a change
|
/// For each author, set 'used' to true if there is a change
|
||||||
/// by this author in the paragraph.
|
/// by this author in the paragraph.
|
||||||
|
@ -375,19 +375,28 @@ bool TextMetrics::redoParagraph(pit_type const pit)
|
|||||||
main_text_ = (text_ == &buffer.text());
|
main_text_ = (text_ == &buffer.text());
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
|
// Check whether there are InsetBibItems that need fixing
|
||||||
// FIXME: This check ought to be done somewhere else. It is the reason
|
// FIXME: This check ought to be done somewhere else. It is the reason
|
||||||
// why text_ is not const. But then, where else to do it?
|
// why text_ is not const. But then, where else to do it?
|
||||||
// Well, how can you end up with either (a) a biblio environment that
|
// Well, how can you end up with either (a) a biblio environment that
|
||||||
// has no InsetBibitem or (b) a biblio environment with more than one
|
// has no InsetBibitem or (b) a biblio environment with more than one
|
||||||
// InsetBibitem? I think the answer is: when paragraphs are merged;
|
// InsetBibitem? I think the answer is: when paragraphs are merged;
|
||||||
// when layout is set; when material is pasted.
|
// when layout is set; when material is pasted.
|
||||||
int const moveCursor = par.checkBiblio(buffer);
|
if (par.brokenBiblio()) {
|
||||||
if (moveCursor > 0)
|
Cursor & cur = const_cast<Cursor &>(bv_->cursor());
|
||||||
const_cast<Cursor &>(bv_->cursor()).posForward();
|
// In some cases, we do not know how to record undo
|
||||||
else if (moveCursor < 0) {
|
if (&cur.inset() == &text_->inset())
|
||||||
Cursor & cursor = const_cast<Cursor &>(bv_->cursor());
|
cur.recordUndo(ATOMIC_UNDO, pit, pit);
|
||||||
if (cursor.pos() >= -moveCursor)
|
|
||||||
cursor.posBackward();
|
int const moveCursor = par.fixBiblio(buffer);
|
||||||
|
|
||||||
|
// Is it necessary to update the cursor?
|
||||||
|
if (&cur.inset() == &text_->inset() && cur.pit() == pit) {
|
||||||
|
if (moveCursor > 0)
|
||||||
|
cur.posForward();
|
||||||
|
else if (moveCursor < 0 && cur.pos() >= -moveCursor)
|
||||||
|
cur.posBackward();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimisation: this is used in the next two loops
|
// Optimisation: this is used in the next two loops
|
||||||
|
@ -95,6 +95,8 @@ What's new
|
|||||||
- Fix various crashes when single document is edited in more windows
|
- Fix various crashes when single document is edited in more windows
|
||||||
(bug 8203).
|
(bug 8203).
|
||||||
|
|
||||||
|
- Fix crash when using undo in a paragraph with layout Bibliography (bug 7111).
|
||||||
|
|
||||||
- Replace current selection when pasting (bug 8027).
|
- Replace current selection when pasting (bug 8027).
|
||||||
|
|
||||||
- Make sure that undo restores environment depth correctly (bug 8159).
|
- Make sure that undo restores environment depth correctly (bug 8159).
|
||||||
|
Loading…
Reference in New Issue
Block a user