Bug 2501 - Undo for label edit results in a blank label

This commit is contained in:
Leland Lucius 2021-01-24 23:27:50 -06:00
parent a7360e74b7
commit a03a6abb4b
3 changed files with 188 additions and 22 deletions

View File

@ -183,6 +183,13 @@ void OnUndo(const CommandContext &context)
return;
}
for (auto lt : tracks.Selected< LabelTrack >()) {
auto &view = LabelTrackView::Get( *lt );
if (!view.Undo( project )) {
return;
}
}
undoManager.Undo(
[&]( const UndoStackElem &elem ){
ProjectHistory::Get( project ).PopState( elem.state ); } );

View File

@ -43,6 +43,71 @@ Paul Licameli split from TrackPanel.cpp
#include <wx/frame.h>
#include <wx/menu.h>
LabelTrackView::Index::Index()
: mIndex(-1),
mModified(false)
{
}
LabelTrackView::Index::Index(int index)
: mIndex(index),
mModified(false)
{
}
LabelTrackView::Index &LabelTrackView::Index::operator =(int index)
{
if (index != mIndex) {
mModified = false;
}
mIndex = index;
return *this;
}
LabelTrackView::Index &LabelTrackView::Index::operator +(int index)
{
mModified = false;
mIndex += index;
return *this;
}
LabelTrackView::Index &LabelTrackView::Index::operator -(int index)
{
mModified = false;
mIndex -= index;
return *this;
}
LabelTrackView::Index &LabelTrackView::Index::operator ++()
{
mModified = false;
mIndex += 1;
return *this;
}
LabelTrackView::Index &LabelTrackView::Index::operator --()
{
mModified = false;
mIndex -= 1;
return *this;
}
LabelTrackView::Index::operator int() const
{
return mIndex;
}
bool LabelTrackView::Index::IsModified() const
{
return mModified;
}
void LabelTrackView::Index::SetModified(bool modified)
{
mModified = modified;
}
LabelTrackView::LabelTrackView( const std::shared_ptr<Track> &pTrack )
: CommonTrackView{ pTrack }
{
@ -100,8 +165,11 @@ void LabelTrackView::CopyTo( Track &track ) const
auto &other = TrackView::Get( track );
if ( const auto pOther = dynamic_cast< const LabelTrackView* >( &other ) ) {
// only one field is important to preserve in undo/redo history
pOther->mSelIndex = mSelIndex;
pOther->mInitialCursorPos = mInitialCursorPos;
pOther->mCurrentCursorPos = mCurrentCursorPos;
pOther->mDrawCursor = mDrawCursor;
pOther->mUndoLabel = mUndoLabel;
}
}
@ -951,6 +1019,22 @@ bool LabelTrackView::IsTextSelected( AudacityProject &project ) const
return true;
}
bool LabelTrackView::Undo( AudacityProject &project )
{
if (HasSelection( project )) {
const auto pTrack = FindLabelTrack();
const auto &mLabels = pTrack->GetLabels();
auto labelStruct = mLabels[mSelIndex];
auto &title = labelStruct.title;
if (title.size() == 0) {
return true;
}
return mSelIndex.IsModified();
}
return true;
}
/// Cut the selected text in the text box
/// @return true if text is selected in text box, false otherwise
bool LabelTrackView::CutSelectedText( AudacityProject &project )
@ -965,6 +1049,10 @@ bool LabelTrackView::CutSelectedText( AudacityProject &project )
auto labelStruct = mLabels[mSelIndex];
auto &text = labelStruct.title;
if (!mSelIndex.IsModified()) {
mUndoLabel = text;
}
int init = mInitialCursorPos;
int cur = mCurrentCursorPos;
if (init > cur)
@ -995,6 +1083,8 @@ bool LabelTrackView::CutSelectedText( AudacityProject &project )
// set cursor positions
mInitialCursorPos = mCurrentCursorPos = left.length();
mSelIndex.SetModified(true);
return true;
}
@ -1053,6 +1143,10 @@ bool LabelTrackView::PasteSelectedText(
text = data.GetText();
}
if (!mSelIndex.IsModified()) {
mUndoLabel = text;
}
// Convert control characters to blanks
for (int i = 0; i < (int)text.length(); i++) {
if (wxIscntrl(text[i])) {
@ -1076,6 +1170,8 @@ bool LabelTrackView::PasteSelectedText(
pTrack->SetLabel( mSelIndex, labelStruct );
mInitialCursorPos = mCurrentCursorPos = left.length() + text.length();
mSelIndex.SetModified(true);
return true;
}
@ -1296,12 +1392,26 @@ unsigned LabelTrackView::KeyDown(
double bkpSel0 = viewInfo.selectedRegion.t0(),
bkpSel1 = viewInfo.selectedRegion.t1();
if (!mSelIndex.IsModified() && HasSelection( *project )) {
const auto pTrack = FindLabelTrack();
const auto &mLabels = pTrack->GetLabels();
auto labelStruct = mLabels[mSelIndex];
auto &title = labelStruct.title;
mUndoLabel = title;
}
// Pass keystroke to labeltrack's handler and add to history if any
// updates were done
if (DoKeyDown( *project, viewInfo.selectedRegion, event )) {
ProjectHistory::Get( *project ).PushState(XO("Modified Label"),
XO("Label Edit"),
UndoPush::CONSOLIDATE);
mSelIndex.IsModified() ? UndoPush::CONSOLIDATE : UndoPush::NONE);
mSelIndex.SetModified(true);
}
if (!mSelIndex.IsModified()) {
mUndoLabel.clear();
}
// Make sure caret is in view
@ -1328,10 +1438,25 @@ unsigned LabelTrackView::Char(
// Pass keystroke to labeltrack's handler and add to history if any
// updates were done
if (DoChar( *project, viewInfo.selectedRegion, event ))
if (!mSelIndex.IsModified() && HasSelection( *project )) {
const auto pTrack = FindLabelTrack();
const auto &mLabels = pTrack->GetLabels();
auto labelStruct = mLabels[mSelIndex];
auto &title = labelStruct.title;
mUndoLabel = title;
}
if (DoChar( *project, viewInfo.selectedRegion, event )) {
ProjectHistory::Get( *project ).PushState(XO("Modified Label"),
XO("Label Edit"),
UndoPush::CONSOLIDATE);
mSelIndex.IsModified() ? UndoPush::CONSOLIDATE : UndoPush::NONE);
mSelIndex.SetModified(true);
}
if (!mSelIndex.IsModified()) {
mUndoLabel.clear();
}
// If selection modified, refresh
// Otherwise, refresh track display if the keystroke was handled
@ -1475,10 +1600,18 @@ bool LabelTrackView::DoKeyDown(
}
break;
case WXK_ESCAPE:
if (mSelIndex.IsModified()) {
title = mUndoLabel;
pTrack->SetLabel(mSelIndex, labelStruct);
ProjectHistory::Get( project ).PushState(XO("Modified Label"),
XO("Label Edit"),
mSelIndex.IsModified() ? UndoPush::CONSOLIDATE : UndoPush::NONE);
}
case WXK_RETURN:
case WXK_NUMPAD_ENTER:
case WXK_ESCAPE:
if (mRestoreFocus >= 0) {
auto track = *TrackList::Get( project ).Any()
.begin().advance(mRestoreFocus);
@ -1492,9 +1625,9 @@ bool LabelTrackView::DoKeyDown(
case WXK_TAB:
case WXK_NUMPAD_TAB:
if (event.ShiftDown()) {
mSelIndex--;
--mSelIndex;
} else {
mSelIndex++;
++mSelIndex;
}
mSelIndex = (mSelIndex + (int)mLabels.size()) % (int)mLabels.size(); // wrap round if necessary
@ -1533,7 +1666,7 @@ bool LabelTrackView::DoKeyDown(
if (newSel.t0() > mLabels[0].getT0()) {
while (mSelIndex >= 0 &&
mLabels[mSelIndex].getT0() > newSel.t0()) {
mSelIndex--;
--mSelIndex;
}
}
} else {
@ -1541,7 +1674,7 @@ bool LabelTrackView::DoKeyDown(
if (newSel.t0() < mLabels[len - 1].getT0()) {
while (mSelIndex < len &&
mLabels[mSelIndex].getT0() < newSel.t0()) {
mSelIndex++;
++mSelIndex;
}
}
}
@ -1745,7 +1878,7 @@ void LabelTrackView::OnContextMenu(
{
ProjectHistory::Get( project ).PushState(XO("Modified Label"),
XO("Label Edit"),
UndoPush::CONSOLIDATE);
mSelIndex.IsModified() ? UndoPush::CONSOLIDATE : UndoPush::NONE);
}
break;
@ -1761,7 +1894,7 @@ void LabelTrackView::OnContextMenu(
{
ProjectHistory::Get( project ).PushState(XO("Modified Label"),
XO("Label Edit"),
UndoPush::CONSOLIDATE);
mSelIndex.IsModified() ? UndoPush::CONSOLIDATE : UndoPush::NONE);
}
break;
@ -1906,7 +2039,7 @@ void LabelTrackView::OnLabelDeleted( LabelTrackEvent &e )
// THEN the NEW selected label number is one less.
else if( index < mSelIndex )
{
mSelIndex--;
--mSelIndex;
}
}

View File

@ -112,6 +112,8 @@ public:
int GetSelectedIndex( AudacityProject &project ) const;
void SetSelectedIndex( int index );
bool Undo( AudacityProject &project );
bool CutSelectedText( AudacityProject &project );
bool CopySelectedText( AudacityProject &project );
bool PasteSelectedText(
@ -123,10 +125,32 @@ public:
private:
static wxBitmap & GetGlyph( int i);
struct Index
{
Index();
Index(int index);
operator int() const;
Index &operator =(int index);
Index &operator +(int index);
Index &operator -(int index);
Index &operator ++();
Index &operator --();
bool IsModified() const;
void SetModified(bool modified);
private:
int mIndex;
int mFlag;
bool mModified;
};
public:
struct Flags {
int mInitialCursorPos, mCurrentCursorPos, mSelIndex;
int mInitialCursorPos, mCurrentCursorPos;
Index mSelIndex{-1};
bool mDrawCursor;
wxString mUndoLabel;
};
void ResetFlags();
@ -134,7 +158,7 @@ public:
{
return {
mInitialCursorPos, mCurrentCursorPos, mSelIndex,
mDrawCursor
mDrawCursor, mUndoLabel
};
}
void RestoreFlags( const Flags& flags );
@ -168,8 +192,10 @@ public:
private:
void OnContextMenu( AudacityProject &project, wxCommandEvent & evt);
mutable int mSelIndex{-1}; /// Keeps track of the currently selected label
mutable Index mSelIndex{-1}; /// Keeps track of the currently selected label
mutable wxString mUndoLabel;
static int mIconHeight;
static int mIconWidth;
static int mTextHeight;
@ -178,13 +204,13 @@ private:
static wxBitmap mBoundaryGlyphs[NUM_GLYPH_CONFIGS * NUM_GLYPH_HIGHLIGHTS];
static int mFontHeight;
int mCurrentCursorPos; /// current cursor position
int mInitialCursorPos; /// initial cursor position
mutable int mCurrentCursorPos; /// current cursor position
mutable int mInitialCursorPos; /// initial cursor position
bool mDrawCursor; /// flag to tell if drawing the
/// cursor or not
mutable bool mDrawCursor; /// flag to tell if drawing the
/// cursor or not
int mRestoreFocus{-2}; /// Restore focus to this track
/// when done editing
/// when done editing
void ComputeTextPosition(const wxRect & r, int index) const;
void ComputeLayout(const wxRect & r, const ZoomInfo &zoomInfo) const;