mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-01 16:19:43 +02:00
Bug1327, 1337: Changes to tags (edit, import or export) should undo and redo
This commit is contained in:
commit
b3f60bc222
@ -42,6 +42,7 @@
|
||||
#include "../images/Arrow.xpm"
|
||||
#include "../images/Empty9x16.xpm"
|
||||
#include "BatchCommands.h"
|
||||
#include "Track.h"
|
||||
#include "UndoManager.h"
|
||||
|
||||
#include "Theme.h"
|
||||
|
@ -36,6 +36,7 @@ undo memory so as to free up space.
|
||||
#include "UndoManager.h"
|
||||
#include "Project.h"
|
||||
#include "ShuttleGui.h"
|
||||
#include "Track.h"
|
||||
|
||||
enum {
|
||||
ID_AVAIL = 1000,
|
||||
|
@ -58,6 +58,7 @@ for drawing different aspects of the label and its text box.
|
||||
#include "Project.h"
|
||||
#include "TrackArtist.h"
|
||||
#include "TrackPanel.h"
|
||||
#include "UndoManager.h"
|
||||
#include "commands/CommandManager.h"
|
||||
|
||||
#include "effects/TimeWarper.h"
|
||||
@ -1132,7 +1133,7 @@ double LabelTrack::GetEndTime() const
|
||||
return end;
|
||||
}
|
||||
|
||||
Track *LabelTrack::Duplicate()
|
||||
Track *LabelTrack::Duplicate() const
|
||||
{
|
||||
return new LabelTrack(*this);
|
||||
}
|
||||
@ -2066,7 +2067,7 @@ void LabelTrack::OnContextMenu(wxCommandEvent & evt)
|
||||
{
|
||||
p->PushState(_("Modified Label"),
|
||||
_("Label Edit"),
|
||||
PUSH_CONSOLIDATE);
|
||||
UndoPush::CONSOLIDATE);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -2081,7 +2082,7 @@ void LabelTrack::OnContextMenu(wxCommandEvent & evt)
|
||||
{
|
||||
p->PushState(_("Modified Label"),
|
||||
_("Label Edit"),
|
||||
true /* consolidate */);
|
||||
UndoPush::CONSOLIDATE);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -2093,7 +2094,7 @@ void LabelTrack::OnContextMenu(wxCommandEvent & evt)
|
||||
DeleteLabel(ndx);
|
||||
p->PushState(_("Deleted Label"),
|
||||
_("Label Edit"),
|
||||
true /* consolidate */);
|
||||
UndoPush::CONSOLIDATE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class AUDACITY_DLL_API LabelTrack : public Track
|
||||
virtual double GetStartTime() const;
|
||||
virtual double GetEndTime() const;
|
||||
|
||||
virtual Track *Duplicate();
|
||||
virtual Track *Duplicate() const;
|
||||
|
||||
virtual void SetSelected(bool s);
|
||||
|
||||
|
@ -119,6 +119,7 @@ simplifies construction of menu items.
|
||||
|
||||
#include "Snap.h"
|
||||
|
||||
#include "UndoManager.h"
|
||||
#include "WaveTrack.h"
|
||||
|
||||
#if defined(EXPERIMENTAL_CRASH_REPORT)
|
||||
@ -1598,10 +1599,10 @@ void AudacityProject::CreateRecentFilesMenu(CommandManager *c)
|
||||
void AudacityProject::ModifyUndoMenuItems()
|
||||
{
|
||||
wxString desc;
|
||||
int cur = mUndoManager.GetCurrentState();
|
||||
int cur = GetUndoManager()->GetCurrentState();
|
||||
|
||||
if (mUndoManager.UndoAvailable()) {
|
||||
mUndoManager.GetShortDescription(cur, &desc);
|
||||
if (GetUndoManager()->UndoAvailable()) {
|
||||
GetUndoManager()->GetShortDescription(cur, &desc);
|
||||
mCommandManager.Modify(wxT("Undo"),
|
||||
wxString::Format(_("&Undo %s"),
|
||||
desc.c_str()));
|
||||
@ -1611,8 +1612,8 @@ void AudacityProject::ModifyUndoMenuItems()
|
||||
wxString::Format(_("&Undo")));
|
||||
}
|
||||
|
||||
if (mUndoManager.RedoAvailable()) {
|
||||
mUndoManager.GetShortDescription(cur+1, &desc);
|
||||
if (GetUndoManager()->RedoAvailable()) {
|
||||
GetUndoManager()->GetShortDescription(cur+1, &desc);
|
||||
mCommandManager.Modify(wxT("Redo"),
|
||||
wxString::Format(_("&Redo %s"),
|
||||
desc.c_str()));
|
||||
@ -1756,16 +1757,16 @@ wxUint32 AudacityProject::GetUpdateFlags()
|
||||
if((msClipT1 - msClipT0) > 0.0)
|
||||
flags |= ClipboardFlag;
|
||||
|
||||
if (mUndoManager.UnsavedChanges())
|
||||
if (GetUndoManager()->UnsavedChanges())
|
||||
flags |= UnsavedChangesFlag;
|
||||
|
||||
if (!mLastEffect.IsEmpty())
|
||||
flags |= HasLastEffectFlag;
|
||||
|
||||
if (mUndoManager.UndoAvailable())
|
||||
if (GetUndoManager()->UndoAvailable())
|
||||
flags |= UndoAvailableFlag;
|
||||
|
||||
if (mUndoManager.RedoAvailable())
|
||||
if (GetUndoManager()->RedoAvailable())
|
||||
flags |= RedoAvailableFlag;
|
||||
|
||||
if (ZoomInAvailable() && (flags & TracksExistFlag))
|
||||
@ -3761,7 +3762,7 @@ void AudacityProject::OnPrint()
|
||||
|
||||
void AudacityProject::OnUndo()
|
||||
{
|
||||
if (!mUndoManager.UndoAvailable()) {
|
||||
if (!GetUndoManager()->UndoAvailable()) {
|
||||
wxMessageBox(_("Nothing to undo"));
|
||||
return;
|
||||
}
|
||||
@ -3771,8 +3772,8 @@ void AudacityProject::OnUndo()
|
||||
return;
|
||||
}
|
||||
|
||||
TrackList *l = mUndoManager.Undo(&mViewInfo.selectedRegion);
|
||||
PopState(l);
|
||||
const UndoState &state = GetUndoManager()->Undo(&mViewInfo.selectedRegion);
|
||||
PopState(state);
|
||||
|
||||
mTrackPanel->SetFocusedTrack(NULL);
|
||||
mTrackPanel->EnsureVisible(mTrackPanel->GetFirstSelectedTrack());
|
||||
@ -3787,7 +3788,7 @@ void AudacityProject::OnUndo()
|
||||
|
||||
void AudacityProject::OnRedo()
|
||||
{
|
||||
if (!mUndoManager.RedoAvailable()) {
|
||||
if (!GetUndoManager()->RedoAvailable()) {
|
||||
wxMessageBox(_("Nothing to redo"));
|
||||
return;
|
||||
}
|
||||
@ -3796,8 +3797,8 @@ void AudacityProject::OnRedo()
|
||||
return;
|
||||
}
|
||||
|
||||
TrackList *l = mUndoManager.Redo(&mViewInfo.selectedRegion);
|
||||
PopState(l);
|
||||
const UndoState &state = GetUndoManager()->Redo(&mViewInfo.selectedRegion);
|
||||
PopState(state);
|
||||
|
||||
mTrackPanel->SetFocusedTrack(NULL);
|
||||
mTrackPanel->EnsureVisible(mTrackPanel->GetFirstSelectedTrack());
|
||||
@ -5262,7 +5263,7 @@ void AudacityProject::OnShowClipping()
|
||||
void AudacityProject::OnHistory()
|
||||
{
|
||||
if (!mHistoryWindow)
|
||||
mHistoryWindow = new HistoryWindow(this, &mUndoManager);
|
||||
mHistoryWindow = new HistoryWindow(this, GetUndoManager());
|
||||
mHistoryWindow->Show();
|
||||
mHistoryWindow->Raise();
|
||||
mHistoryWindow->UpdateDisplay();
|
||||
@ -5581,8 +5582,24 @@ void AudacityProject::OnImportRaw()
|
||||
|
||||
void AudacityProject::OnEditMetadata()
|
||||
{
|
||||
if (mTags->ShowEditDialog(this, _("Edit Metadata Tags"), true))
|
||||
PushState(_("Edit Metadata Tags"), _("Metadata Tags"));
|
||||
(void)DoEditMetadata(_("Edit Metadata Tags"), _("Metadata Tags"), true);
|
||||
}
|
||||
|
||||
bool AudacityProject::DoEditMetadata
|
||||
(const wxString &title, const wxString &shortUndoDescription, bool force)
|
||||
{
|
||||
// Back up my tags
|
||||
auto newTags = mTags->Duplicate();
|
||||
|
||||
if (newTags->ShowEditDialog(this, title, force)) {
|
||||
// Commit the change to project state only now.
|
||||
mTags = newTags;
|
||||
PushState(title, shortUndoDescription);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudacityProject::HandleMixAndRender(bool toNewTrack)
|
||||
|
@ -320,6 +320,7 @@ void OnImportMIDI();
|
||||
void OnImportRaw();
|
||||
|
||||
void OnEditMetadata();
|
||||
bool DoEditMetadata(const wxString &title, const wxString &shortUndoDescription, bool force);
|
||||
|
||||
void OnMixAndRender();
|
||||
void OnMixAndRenderToNewTrack();
|
||||
|
@ -27,6 +27,7 @@
|
||||
#endif
|
||||
#include "Project.h"
|
||||
#include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER
|
||||
#include "UndoManager.h"
|
||||
#include "WaveTrack.h"
|
||||
|
||||
#include "widgets/Meter.h"
|
||||
@ -405,7 +406,7 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
|
||||
mProject->RefreshTPTrack(mLeftTrack);
|
||||
#endif
|
||||
if (bWantPushState)
|
||||
mProject->TP_PushState(_("Moved gain slider"), _("Gain"), PUSH_CONSOLIDATE );
|
||||
mProject->TP_PushState(_("Moved gain slider"), _("Gain"), UndoPush::CONSOLIDATE );
|
||||
}
|
||||
|
||||
void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
|
||||
@ -424,7 +425,7 @@ void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
|
||||
#endif
|
||||
|
||||
if (bWantPushState)
|
||||
mProject->TP_PushState(_("Moved pan slider"), _("Pan"), PUSH_CONSOLIDATE );
|
||||
mProject->TP_PushState(_("Moved pan slider"), _("Pan"), UndoPush::CONSOLIDATE );
|
||||
}
|
||||
|
||||
void MixerTrackCluster::ResetMeter(const bool bResetClipping)
|
||||
|
@ -135,7 +135,7 @@ NoteTrack::~NoteTrack()
|
||||
}
|
||||
}
|
||||
|
||||
Track *NoteTrack::Duplicate()
|
||||
Track *NoteTrack::Duplicate() const
|
||||
{
|
||||
NoteTrack *duplicate = new NoteTrack(mDirManager);
|
||||
duplicate->Init(*this);
|
||||
|
@ -57,7 +57,7 @@ class AUDACITY_DLL_API NoteTrack:public Track {
|
||||
NoteTrack(DirManager * projDirManager);
|
||||
virtual ~NoteTrack();
|
||||
|
||||
virtual Track *Duplicate();
|
||||
virtual Track *Duplicate() const;
|
||||
|
||||
virtual int GetKind() const { return Note; }
|
||||
|
||||
|
107
src/Project.cpp
107
src/Project.cpp
@ -143,6 +143,8 @@ scroll information. It also has some status flags.
|
||||
|
||||
#include "FileDialog.h"
|
||||
|
||||
#include "UndoManager.h"
|
||||
|
||||
#include "toolbars/ToolManager.h"
|
||||
#include "toolbars/ControlToolBar.h"
|
||||
#include "toolbars/DeviceToolBar.h"
|
||||
@ -796,6 +798,7 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
|
||||
mSelectionFormat(gPrefs->Read(wxT("/SelectionFormat"), wxT(""))),
|
||||
mFrequencySelectionFormatName(gPrefs->Read(wxT("/FrequencySelectionFormatName"), wxT(""))),
|
||||
mBandwidthSelectionFormatName(gPrefs->Read(wxT("/BandwidthSelectionFormatName"), wxT(""))),
|
||||
mUndoManager(safenew UndoManager),
|
||||
mDirty(false),
|
||||
mRuler(NULL),
|
||||
mTrackPanel(NULL),
|
||||
@ -1023,6 +1026,9 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
|
||||
// MM: Give track panel the focus to ensure keyboard commands work
|
||||
mTrackPanel->SetFocus();
|
||||
|
||||
// Create tags object
|
||||
mTags = std::make_shared<Tags>();
|
||||
|
||||
InitialState();
|
||||
FixScrollbars();
|
||||
mRuler->SetLeftOffset(mTrackPanel->GetLeftOffset()); // bevel on AdornedRuler
|
||||
@ -1048,9 +1054,6 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id,
|
||||
#endif
|
||||
mIconized = false;
|
||||
|
||||
// Create tags object
|
||||
mTags = new Tags();
|
||||
|
||||
mTrackFactory = new TrackFactory(mDirManager, &mViewInfo);
|
||||
|
||||
int widths[] = {0, GetControlToolBar()->WidthForStatusBar(mStatusBar), -1, 150};
|
||||
@ -1247,9 +1250,9 @@ bool AudacityProject::IsAudioActive() const
|
||||
gAudioIO->IsStreamActive(GetAudioIOToken());
|
||||
}
|
||||
|
||||
Tags *AudacityProject::GetTags()
|
||||
const Tags *AudacityProject::GetTags()
|
||||
{
|
||||
return mTags;
|
||||
return mTags.get();
|
||||
}
|
||||
|
||||
wxString AudacityProject::GetName()
|
||||
@ -2211,7 +2214,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event)
|
||||
// We may not bother to prompt the user to save, if the
|
||||
// project is now empty.
|
||||
if (event.CanVeto() && (mEmptyCanBeDirty || bHasTracks)) {
|
||||
if (mUndoManager.UnsavedChanges()) {
|
||||
if (GetUndoManager()->UnsavedChanges()) {
|
||||
|
||||
wxString Message = _("Save changes before closing?");
|
||||
if( !bHasTracks )
|
||||
@ -2317,8 +2320,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event)
|
||||
delete mTrackFactory;
|
||||
mTrackFactory = NULL;
|
||||
|
||||
delete mTags;
|
||||
mTags = NULL;
|
||||
mTags.reset();
|
||||
|
||||
delete mImportXMLTagHandler;
|
||||
mImportXMLTagHandler = NULL;
|
||||
@ -2336,7 +2338,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event)
|
||||
|
||||
// This must be done before the following Deref() since it holds
|
||||
// references to the DirManager.
|
||||
mUndoManager.ClearStates();
|
||||
GetUndoManager()->ClearStates();
|
||||
|
||||
// MM: Tell the DirManager it can now DELETE itself
|
||||
// if it finds it is no longer needed. If it is still
|
||||
@ -3179,7 +3181,7 @@ bool AudacityProject::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
|
||||
XMLTagHandler *AudacityProject::HandleXMLChild(const wxChar *tag)
|
||||
{
|
||||
if (!wxStrcmp(tag, wxT("tags"))) {
|
||||
return mTags;
|
||||
return mTags.get();
|
||||
}
|
||||
|
||||
if (!wxStrcmp(tag, wxT("wavetrack"))) {
|
||||
@ -3411,7 +3413,7 @@ bool AudacityProject::Save(bool overwrite /* = true */ ,
|
||||
bool bHasTracks = (iter.First() != NULL);
|
||||
if (!bHasTracks)
|
||||
{
|
||||
if (mUndoManager.UnsavedChanges() && mEmptyCanBeDirty) {
|
||||
if (GetUndoManager()->UnsavedChanges() && mEmptyCanBeDirty) {
|
||||
int result = wxMessageBox(_("Your project is now empty.\nIf saved, the project will have no tracks.\n\nTo save any previously open tracks:\nClick 'No', Edit > Undo until all tracks\nare open, then File > Save Project.\n\nSave anyway?"),
|
||||
_("Warning - Empty Project"),
|
||||
wxYES_NO | wxICON_QUESTION, this);
|
||||
@ -3596,7 +3598,7 @@ bool AudacityProject::Save(bool overwrite /* = true */ ,
|
||||
t = iter.Next();
|
||||
}
|
||||
|
||||
mUndoManager.StateSaved();
|
||||
GetUndoManager()->StateSaved();
|
||||
}
|
||||
|
||||
// If we get here, saving the project was successful, so we can DELETE
|
||||
@ -3790,12 +3792,40 @@ bool AudacityProject::Import(const wxString &fileName, WaveTrackArray* pTrackArr
|
||||
{
|
||||
Track **newTracks;
|
||||
int numTracks;
|
||||
wxString errorMessage=wxT("");
|
||||
wxString errorMessage = wxEmptyString;
|
||||
|
||||
// Backup Tags, before the import. Be prepared to roll back changes.
|
||||
struct TempTags {
|
||||
TempTags(std::shared_ptr<Tags> & pTags_)
|
||||
: pTags(pTags_)
|
||||
{
|
||||
oldTags = pTags;
|
||||
if (oldTags)
|
||||
pTags = oldTags->Duplicate();
|
||||
}
|
||||
|
||||
~TempTags()
|
||||
{
|
||||
if (oldTags) {
|
||||
// roll back
|
||||
pTags = oldTags;
|
||||
}
|
||||
}
|
||||
|
||||
void Commit()
|
||||
{
|
||||
oldTags.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<Tags> & pTags;
|
||||
std::shared_ptr<Tags> oldTags;
|
||||
};
|
||||
TempTags tempTags(mTags);
|
||||
|
||||
numTracks = Importer::Get().Import(fileName,
|
||||
mTrackFactory,
|
||||
&newTracks,
|
||||
mTags,
|
||||
mTags.get(),
|
||||
errorMessage);
|
||||
|
||||
if (!errorMessage.IsEmpty()) {
|
||||
@ -3811,9 +3841,17 @@ bool AudacityProject::Import(const wxString &fileName, WaveTrackArray* pTrackArr
|
||||
|
||||
wxGetApp().AddFileToHistory(fileName);
|
||||
|
||||
// no more errors
|
||||
tempTags.Commit();
|
||||
|
||||
// for LOF ("list of files") files, do not import the file as if it
|
||||
// were an audio file itself
|
||||
if (fileName.AfterLast('.').IsSameAs(wxT("lof"), false)) {
|
||||
// PRL: don't redundantly do the steps below, because we already
|
||||
// did it in case of LOF, because of some weird recursion back to this
|
||||
// same function. I think this should be untangled.
|
||||
|
||||
// So Undo history push is not bypassed, despite appearances.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3827,6 +3865,7 @@ bool AudacityProject::Import(const wxString &fileName, WaveTrackArray* pTrackArr
|
||||
}
|
||||
}
|
||||
|
||||
// PRL: Undo history is incremented inside this:
|
||||
AddImportedTracks(fileName, newTracks, numTracks);
|
||||
|
||||
int mode = gPrefs->Read(wxT("/AudioFiles/NormalizeOnLoad"), 0L);
|
||||
@ -3979,12 +4018,12 @@ void AudacityProject::InitialState()
|
||||
mImportXMLTagHandler = NULL;
|
||||
}
|
||||
|
||||
mUndoManager.ClearStates();
|
||||
GetUndoManager()->ClearStates();
|
||||
|
||||
mUndoManager.PushState(mTracks, mViewInfo.selectedRegion,
|
||||
GetUndoManager()->PushState(mTracks, mViewInfo.selectedRegion, mTags,
|
||||
_("Created new project"), wxT(""));
|
||||
|
||||
mUndoManager.StateSaved();
|
||||
GetUndoManager()->StateSaved();
|
||||
|
||||
if (mHistoryWindow)
|
||||
mHistoryWindow->UpdateDisplay();
|
||||
@ -3996,11 +4035,16 @@ void AudacityProject::InitialState()
|
||||
this->UpdateMixerBoard();
|
||||
}
|
||||
|
||||
void AudacityProject::PushState(const wxString &desc, const wxString &shortDesc)
|
||||
{
|
||||
PushState(desc, shortDesc, UndoPush::AUTOSAVE);
|
||||
}
|
||||
|
||||
void AudacityProject::PushState(const wxString &desc,
|
||||
const wxString &shortDesc,
|
||||
int flags )
|
||||
UndoPush flags )
|
||||
{
|
||||
mUndoManager.PushState(mTracks, mViewInfo.selectedRegion,
|
||||
GetUndoManager()->PushState(mTracks, mViewInfo.selectedRegion, mTags,
|
||||
desc, shortDesc, flags);
|
||||
|
||||
mDirty = true;
|
||||
@ -4025,7 +4069,7 @@ void AudacityProject::PushState(const wxString &desc,
|
||||
|
||||
if (GetTracksFitVerticallyZoomed())
|
||||
this->DoZoomFitV();
|
||||
if( (flags & PUSH_AUTOSAVE)!= 0)
|
||||
if((flags & UndoPush::AUTOSAVE) != UndoPush::MINIMAL)
|
||||
AutoSave();
|
||||
}
|
||||
|
||||
@ -4036,7 +4080,7 @@ void AudacityProject::RollbackState()
|
||||
|
||||
void AudacityProject::ModifyState(bool bWantsAutoSave)
|
||||
{
|
||||
mUndoManager.ModifyState(mTracks, mViewInfo.selectedRegion);
|
||||
GetUndoManager()->ModifyState(mTracks, mViewInfo.selectedRegion, mTags);
|
||||
if (bWantsAutoSave)
|
||||
AutoSave();
|
||||
}
|
||||
@ -4044,10 +4088,15 @@ void AudacityProject::ModifyState(bool bWantsAutoSave)
|
||||
// LL: Is there a memory leak here as "l" and "t" are not deleted???
|
||||
// Vaughan, 2010-08-29: No, as "l" is a TrackList* of an Undo stack state.
|
||||
// Need to keep it and its tracks "t" available for Undo/Redo/SetStateTo.
|
||||
void AudacityProject::PopState(TrackList * l)
|
||||
void AudacityProject::PopState(const UndoState &state)
|
||||
{
|
||||
// Restore tags
|
||||
mTags = state.tags;
|
||||
|
||||
TrackList *const tracks = state.tracks.get();
|
||||
|
||||
mTracks->Clear(true);
|
||||
TrackListIterator iter(l);
|
||||
TrackListIterator iter(tracks);
|
||||
Track *t = iter.First();
|
||||
bool odUsed = false;
|
||||
ODComputeSummaryTask* computeTask = NULL;
|
||||
@ -4096,9 +4145,9 @@ void AudacityProject::PopState(TrackList * l)
|
||||
|
||||
void AudacityProject::SetStateTo(unsigned int n)
|
||||
{
|
||||
TrackList *l =
|
||||
mUndoManager.SetStateTo(n, &mViewInfo.selectedRegion);
|
||||
PopState(l);
|
||||
const UndoState &state =
|
||||
GetUndoManager()->SetStateTo(n, &mViewInfo.selectedRegion);
|
||||
PopState(state);
|
||||
|
||||
HandleResize();
|
||||
mTrackPanel->SetFocusedTrack(NULL);
|
||||
@ -4699,7 +4748,7 @@ void AudacityProject::RefreshTPTrack(Track* pTrk, bool refreshbacking /*= true*/
|
||||
|
||||
// TrackPanel callback method
|
||||
void AudacityProject::TP_PushState(const wxString &desc, const wxString &shortDesc,
|
||||
int flags)
|
||||
UndoPush flags)
|
||||
{
|
||||
PushState(desc, shortDesc, flags);
|
||||
}
|
||||
@ -4965,7 +5014,7 @@ void AudacityProject::SetTrackGain(Track * track, LWSlider * slider)
|
||||
if (link)
|
||||
link->SetGain(newValue);
|
||||
|
||||
PushState(_("Adjusted gain"), _("Gain"), PUSH_CONSOLIDATE);
|
||||
PushState(_("Adjusted gain"), _("Gain"), UndoPush::CONSOLIDATE);
|
||||
|
||||
GetTrackPanel()->RefreshTrack(track);
|
||||
}
|
||||
@ -4982,7 +5031,7 @@ void AudacityProject::SetTrackPan(Track * track, LWSlider * slider)
|
||||
if (link)
|
||||
link->SetPan(newValue);
|
||||
|
||||
PushState(_("Adjusted Pan"), _("Pan"), PUSH_CONSOLIDATE);
|
||||
PushState(_("Adjusted Pan"), _("Pan"), UndoPush::CONSOLIDATE);
|
||||
|
||||
GetTrackPanel()->RefreshTrack(track);
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "Experimental.h"
|
||||
|
||||
#include "DirManager.h"
|
||||
#include "UndoManager.h"
|
||||
#include "ViewInfo.h"
|
||||
#include "TrackPanelListener.h"
|
||||
#include "AudioIOListener.h"
|
||||
@ -85,11 +84,14 @@ class MixerBoard;
|
||||
class MixerBoardFrame;
|
||||
|
||||
struct AudioIOStartStreamOptions;
|
||||
struct UndoState;
|
||||
|
||||
class WaveTrackArray;
|
||||
class Regions;
|
||||
|
||||
class LWSlider;
|
||||
class UndoManager;
|
||||
enum class UndoPush;
|
||||
|
||||
AudacityProject *CreateNewAudacityProject();
|
||||
AUDACITY_DLL_API AudacityProject *GetActiveProject();
|
||||
@ -157,7 +159,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
|
||||
AudioIOStartStreamOptions GetDefaultPlayOptions();
|
||||
|
||||
TrackList *GetTracks() { return mTracks; }
|
||||
UndoManager *GetUndoManager() { return &mUndoManager; }
|
||||
UndoManager *GetUndoManager() { return mUndoManager.get(); }
|
||||
|
||||
sampleFormat GetDefaultFormat() { return mDefaultFormat; }
|
||||
|
||||
@ -183,7 +185,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
|
||||
DirManager *GetDirManager();
|
||||
TrackFactory *GetTrackFactory();
|
||||
AdornedRulerPanel *GetRulerPanel();
|
||||
Tags *GetTags();
|
||||
const Tags *GetTags();
|
||||
int GetAudioIOToken() const;
|
||||
bool IsAudioActive() const;
|
||||
void SetAudioIOToken(int token);
|
||||
@ -399,7 +401,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
|
||||
virtual ToolsToolBar * TP_GetToolsToolBar();
|
||||
|
||||
virtual void TP_PushState(const wxString &longDesc, const wxString &shortDesc,
|
||||
int flags) override;
|
||||
UndoPush flags) override;
|
||||
virtual void TP_ModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
virtual void TP_RedrawScrollbars();
|
||||
@ -486,8 +488,8 @@ public:
|
||||
static void AllProjectsDeleteLock();
|
||||
static void AllProjectsDeleteUnlock();
|
||||
|
||||
void PushState(const wxString &desc, const wxString &shortDesc,
|
||||
int flags = PUSH_AUTOSAVE);
|
||||
void PushState(const wxString &desc, const wxString &shortDesc); // use UndoPush::AUTOSAVE
|
||||
void PushState(const wxString &desc, const wxString &shortDesc, UndoPush flags);
|
||||
void RollbackState();
|
||||
|
||||
private:
|
||||
@ -497,7 +499,7 @@ public:
|
||||
void InitialState();
|
||||
void ModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
void PopState(TrackList * l);
|
||||
void PopState(const UndoState &state);
|
||||
|
||||
void UpdateLyrics();
|
||||
void UpdateMixerBoard();
|
||||
@ -524,7 +526,10 @@ public:
|
||||
wxMenu *mRecentFilesMenu;
|
||||
|
||||
// Tags (artist name, song properties, MP3 ID3 info, etc.)
|
||||
Tags *mTags;
|
||||
// The structure may be shared with undo history entries
|
||||
// To keep undo working correctly, always replace this with a new duplicate
|
||||
// BEFORE doing any editing of it!
|
||||
std::shared_ptr<Tags> mTags;
|
||||
|
||||
// List of tracks and display info
|
||||
TrackList *mTracks;
|
||||
@ -546,7 +551,7 @@ public:
|
||||
static ODLock *msAllProjectDeleteMutex;
|
||||
|
||||
// History/Undo manager
|
||||
UndoManager mUndoManager;
|
||||
std::unique_ptr<UndoManager> mUndoManager;
|
||||
bool mDirty;
|
||||
|
||||
// Commands
|
||||
|
66
src/Tags.cpp
66
src/Tags.cpp
@ -233,6 +233,11 @@ Tags::~Tags()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<Tags> Tags::Duplicate() const
|
||||
{
|
||||
return std::make_shared<Tags>(*this);
|
||||
}
|
||||
|
||||
Tags & Tags::operator=(const Tags & src)
|
||||
{
|
||||
mEditTitle = src.mEditTitle;
|
||||
@ -371,53 +376,38 @@ int Tags::GetGenre(const wxString & name)
|
||||
return 255;
|
||||
}
|
||||
|
||||
bool Tags::HasTag(const wxString & name)
|
||||
bool Tags::HasTag(const wxString & name) const
|
||||
{
|
||||
wxString key = name;
|
||||
key.UpperCase();
|
||||
|
||||
TagMap::iterator iter = mXref.find(key);
|
||||
auto iter = mXref.find(key);
|
||||
return (iter != mXref.end());
|
||||
}
|
||||
|
||||
wxString Tags::GetTag(const wxString & name)
|
||||
wxString Tags::GetTag(const wxString & name) const
|
||||
{
|
||||
wxString key = name;
|
||||
key.UpperCase();
|
||||
|
||||
TagMap::iterator iter = mXref.find(key);
|
||||
auto iter = mXref.find(key);
|
||||
|
||||
if (iter == mXref.end()) {
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
return mMap[iter->second];
|
||||
auto iter2 = mMap.find(iter->second);
|
||||
if (iter2 == mMap.end()) {
|
||||
wxASSERT(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
else
|
||||
return iter2->second;
|
||||
}
|
||||
|
||||
bool Tags::GetFirst(wxString & name, wxString & value)
|
||||
Tags::Iterators Tags::GetRange() const
|
||||
{
|
||||
mIter = mMap.begin();
|
||||
if (mIter == mMap.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = mIter->first;
|
||||
value = mIter->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tags::GetNext(wxString & name, wxString & value)
|
||||
{
|
||||
++mIter;
|
||||
if (mIter == mMap.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
name = mIter->first;
|
||||
value = mIter->second;
|
||||
|
||||
return true;
|
||||
return std::make_pair(mMap.begin(), mMap.end());
|
||||
}
|
||||
|
||||
void Tags::SetTag(const wxString & name, const wxString & value)
|
||||
@ -510,8 +500,9 @@ void Tags::WriteXML(XMLWriter &xmlFile)
|
||||
{
|
||||
xmlFile.StartTag(wxT("tags"));
|
||||
|
||||
wxString n, v;
|
||||
for (bool cont = GetFirst(n, v); cont; cont = GetNext(n, v)) {
|
||||
for (const auto &pair : GetRange()) {
|
||||
const auto &n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
xmlFile.StartTag(wxT("tag"));
|
||||
xmlFile.WriteAttr(wxT("name"), n);
|
||||
xmlFile.WriteAttr(wxT("value"), v);
|
||||
@ -863,8 +854,6 @@ bool TagsEditor::TransferDataFromWindow()
|
||||
bool TagsEditor::TransferDataToWindow()
|
||||
{
|
||||
size_t i;
|
||||
wxString n;
|
||||
wxString v;
|
||||
TagMap popTagMap;
|
||||
|
||||
// Disable redrawing until we're done
|
||||
@ -895,12 +884,14 @@ bool TagsEditor::TransferDataToWindow()
|
||||
}
|
||||
|
||||
// Populate the rest
|
||||
for (bool cont = mLocal.GetFirst(n, v); cont; cont = mLocal.GetNext(n, v)) {
|
||||
if ( popTagMap.find(n) == popTagMap.end() ) {
|
||||
for (const auto &pair : mLocal.GetRange()) {
|
||||
const auto &n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
if (popTagMap.find(n) == popTagMap.end()) {
|
||||
mGrid->AppendRows();
|
||||
mGrid->SetCellValue(i, 0, n);
|
||||
mGrid->SetCellValue(i, 1, v);
|
||||
i++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1186,8 +1177,9 @@ void TagsEditor::OnSaveDefaults(wxCommandEvent & WXUNUSED(event))
|
||||
gPrefs->DeleteGroup(wxT("/Tags"));
|
||||
|
||||
// Write out each tag
|
||||
wxString n, v;
|
||||
for (bool cont = mLocal.GetFirst(n, v); cont; cont = mLocal.GetNext(n, v)) {
|
||||
for (const auto &pair : mLocal.GetRange()) {
|
||||
const auto &n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
gPrefs->Write(wxT("/Tags/") + n, v);
|
||||
}
|
||||
gPrefs->Flush();
|
||||
|
18
src/Tags.h
18
src/Tags.h
@ -33,6 +33,7 @@
|
||||
#include "widgets/Grid.h"
|
||||
#include "xml/XMLTagHandler.h"
|
||||
|
||||
#include <utility>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/hashmap.h>
|
||||
#include <wx/notebook.h>
|
||||
@ -76,6 +77,8 @@ class AUDACITY_DLL_API Tags: public XMLTagHandler {
|
||||
Tags(); // constructor
|
||||
virtual ~Tags();
|
||||
|
||||
std::shared_ptr<Tags> Duplicate() const;
|
||||
|
||||
Tags & operator= (const Tags & src );
|
||||
|
||||
bool ShowEditDialog(wxWindow *parent, const wxString &title, bool force = false);
|
||||
@ -96,11 +99,17 @@ class AUDACITY_DLL_API Tags: public XMLTagHandler {
|
||||
wxString GetGenre(int value);
|
||||
int GetGenre(const wxString & name);
|
||||
|
||||
bool HasTag(const wxString & name);
|
||||
wxString GetTag(const wxString & name);
|
||||
bool HasTag(const wxString & name) const;
|
||||
wxString GetTag(const wxString & name) const;
|
||||
|
||||
bool GetFirst(wxString & name, wxString & value);
|
||||
bool GetNext(wxString & name, wxString & value);
|
||||
using IterPair = std::pair<TagMap::const_iterator, TagMap::const_iterator>;
|
||||
struct Iterators : public IterPair {
|
||||
Iterators(IterPair p) : IterPair(p) {}
|
||||
// Define begin() and end() for convenience in range-for
|
||||
auto begin() -> decltype(first) const { return first; }
|
||||
auto end() -> decltype(second) const { return second; }
|
||||
};
|
||||
Iterators GetRange() const;
|
||||
|
||||
void SetTag(const wxString & name, const wxString & value);
|
||||
void SetTag(const wxString & name, const int & value);
|
||||
@ -111,7 +120,6 @@ class AUDACITY_DLL_API Tags: public XMLTagHandler {
|
||||
private:
|
||||
void LoadDefaults();
|
||||
|
||||
TagMap::iterator mIter;
|
||||
TagMap mXref;
|
||||
TagMap mMap;
|
||||
|
||||
|
@ -64,7 +64,7 @@ TimeTrack::TimeTrack(DirManager *projDirManager, const ZoomInfo *zoomInfo):
|
||||
blankPen.SetColour(214, 214, 214);
|
||||
}
|
||||
|
||||
TimeTrack::TimeTrack(TimeTrack &orig):
|
||||
TimeTrack::TimeTrack(const TimeTrack &orig):
|
||||
Track(orig)
|
||||
, mZoomInfo(orig.mZoomInfo)
|
||||
{
|
||||
@ -109,7 +109,7 @@ TimeTrack::~TimeTrack()
|
||||
delete mRuler;
|
||||
}
|
||||
|
||||
Track *TimeTrack::Duplicate()
|
||||
Track *TimeTrack::Duplicate() const
|
||||
{
|
||||
return new TimeTrack(*this);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class TimeTrack: public Track {
|
||||
* copy-constructor to encapsulate this.
|
||||
* @param orig The original track to copy from
|
||||
*/
|
||||
TimeTrack(TimeTrack &orig);
|
||||
TimeTrack(const TimeTrack &orig);
|
||||
|
||||
virtual ~TimeTrack();
|
||||
|
||||
@ -131,7 +131,7 @@ class TimeTrack: public Track {
|
||||
* @param orig the TimeTrack to copy from
|
||||
*/
|
||||
void Init(const TimeTrack &orig);
|
||||
virtual Track *Duplicate();
|
||||
virtual Track *Duplicate() const;
|
||||
|
||||
friend class TrackFactory;
|
||||
|
||||
|
27
src/Track.h
27
src/Track.h
@ -29,7 +29,6 @@
|
||||
|
||||
class wxTextFile;
|
||||
class DirManager;
|
||||
class UndoStack;
|
||||
class Track;
|
||||
class LabelTrack;
|
||||
class TimeTrack;
|
||||
@ -146,7 +145,7 @@ class AUDACITY_DLL_API Track: public XMLTagHandler
|
||||
virtual ~ Track();
|
||||
|
||||
void Init(const Track &orig);
|
||||
virtual Track *Duplicate() = 0;
|
||||
virtual Track *Duplicate() const = 0;
|
||||
|
||||
// Called when this track is merged to stereo with another, and should
|
||||
// take on some paramaters of its partner.
|
||||
@ -240,6 +239,30 @@ class AUDACITY_DLL_API TrackListIterator
|
||||
TrackListNode *cur;
|
||||
};
|
||||
|
||||
class AUDACITY_DLL_API TrackListConstIterator
|
||||
{
|
||||
public:
|
||||
TrackListConstIterator(const TrackList * val = NULL)
|
||||
: mIter(const_cast<TrackList*>(val))
|
||||
{}
|
||||
~TrackListConstIterator() {}
|
||||
|
||||
// Iterate functions
|
||||
const Track *First(const TrackList * val = NULL)
|
||||
{ return mIter.First(const_cast<TrackList*>(val)); }
|
||||
const Track *StartWith(const Track * val)
|
||||
{ return mIter.StartWith(const_cast<Track*>(val)); }
|
||||
const Track *Next(bool skiplinked = false)
|
||||
{ return mIter.Next(skiplinked); }
|
||||
const Track *Prev(bool skiplinked = false)
|
||||
{ return mIter.Prev(skiplinked); }
|
||||
const Track *Last(bool skiplinked = false)
|
||||
{ return mIter.Last(skiplinked); }
|
||||
|
||||
private:
|
||||
TrackListIterator mIter;
|
||||
};
|
||||
|
||||
// TrackListCondIterator (base class for iterators that iterate over all tracks)
|
||||
// that meet a condition)
|
||||
class AUDACITY_DLL_API TrackListCondIterator: public TrackListIterator
|
||||
|
@ -181,6 +181,7 @@ is time to refresh some aspect of the screen.
|
||||
#include "TimeTrack.h"
|
||||
#include "TrackArtist.h"
|
||||
#include "TrackPanelAx.h"
|
||||
#include "UndoManager.h"
|
||||
#include "WaveTrack.h"
|
||||
|
||||
#include "commands/Keyboard.h"
|
||||
@ -1492,11 +1493,16 @@ void TrackPanel::OnPaint(wxPaintEvent & /* event */)
|
||||
/// Makes our Parent (well, whoever is listening to us) push their state.
|
||||
/// this causes application state to be preserved on a stack for undo ops.
|
||||
void TrackPanel::MakeParentPushState(const wxString &desc, const wxString &shortDesc,
|
||||
int flags)
|
||||
UndoPush flags)
|
||||
{
|
||||
mListener->TP_PushState(desc, shortDesc, flags);
|
||||
}
|
||||
|
||||
void TrackPanel::MakeParentPushState(const wxString &desc, const wxString &shortDesc)
|
||||
{
|
||||
MakeParentPushState(desc, shortDesc, UndoPush::AUTOSAVE);
|
||||
}
|
||||
|
||||
void TrackPanel::MakeParentModifyState(bool bWantsAutoSave)
|
||||
{
|
||||
mListener->TP_ModifyState(bWantsAutoSave);
|
||||
@ -3300,7 +3306,7 @@ void TrackPanel::Stretch(int mouseXCoordinate, int trackLeftEdge,
|
||||
break;
|
||||
}
|
||||
MakeParentPushState(_("Stretch Note Track"), _("Stretch"),
|
||||
PUSH_CONSOLIDATE | PUSH_AUTOSAVE);
|
||||
UndoPush::CONSOLIDATE | UndoPush::AUTOSAVE);
|
||||
mStretched = true;
|
||||
Refresh(false);
|
||||
}
|
||||
@ -3831,7 +3837,7 @@ void TrackPanel::HandleSlide(wxMouseEvent & event)
|
||||
consolidate = true;
|
||||
}
|
||||
MakeParentPushState(msg, _("Time-Shift"),
|
||||
consolidate ? (PUSH_CONSOLIDATE) : (PUSH_AUTOSAVE));
|
||||
consolidate ? (UndoPush::CONSOLIDATE) : (UndoPush::AUTOSAVE));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5170,7 +5176,7 @@ void TrackPanel::HandleSampleEditingButtonUp( wxMouseEvent & WXUNUSED(event))
|
||||
mDrawingTrack=NULL; //Set this to NULL so it will catch improper drag events.
|
||||
MakeParentPushState(_("Moved Samples"),
|
||||
_("Sample Edit"),
|
||||
PUSH_CONSOLIDATE|PUSH_AUTOSAVE);
|
||||
UndoPush::CONSOLIDATE | UndoPush::AUTOSAVE);
|
||||
}
|
||||
|
||||
|
||||
@ -5420,7 +5426,7 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan)
|
||||
#endif
|
||||
MakeParentPushState(pan ? _("Moved pan slider") : _("Moved gain slider"),
|
||||
pan ? _("Pan") : _("Gain"),
|
||||
PUSH_CONSOLIDATE);
|
||||
UndoPush::CONSOLIDATE);
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
} else {
|
||||
MakeParentPushState(_("Moved velocity slider"), _("Velocity"), true);
|
||||
@ -6435,7 +6441,7 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
||||
if (lt->OnKeyDown(mViewInfo->selectedRegion, event))
|
||||
MakeParentPushState(_("Modified Label"),
|
||||
_("Label Edit"),
|
||||
PUSH_CONSOLIDATE);
|
||||
UndoPush::CONSOLIDATE);
|
||||
|
||||
// Make sure caret is in view
|
||||
int x;
|
||||
@ -6479,7 +6485,7 @@ void TrackPanel::OnChar(wxKeyEvent & event)
|
||||
if (((LabelTrack *)t)->OnChar(mViewInfo->selectedRegion, event))
|
||||
MakeParentPushState(_("Modified Label"),
|
||||
_("Label Edit"),
|
||||
PUSH_CONSOLIDATE);
|
||||
UndoPush::CONSOLIDATE);
|
||||
|
||||
// If selection modified, refresh
|
||||
// Otherwise, refresh track display if the keystroke was handled
|
||||
@ -6731,7 +6737,7 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &rect,
|
||||
}
|
||||
}
|
||||
|
||||
MakeParentPushState(_("Merged Clips"),_("Merge"), PUSH_CONSOLIDATE);
|
||||
MakeParentPushState(_("Merged Clips"),_("Merge"), UndoPush::CONSOLIDATE);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@ -6880,7 +6886,7 @@ void TrackPanel::HandleGlyphDragRelease(LabelTrack * lTrack, wxMouseEvent & even
|
||||
*mViewInfo, &mViewInfo->selectedRegion)) {
|
||||
MakeParentPushState(_("Modified Label"),
|
||||
_("Label Edit"),
|
||||
PUSH_CONSOLIDATE);
|
||||
UndoPush::CONSOLIDATE);
|
||||
}
|
||||
|
||||
//If we are adjusting a label on a labeltrack, do not do anything
|
||||
|
@ -21,9 +21,9 @@
|
||||
|
||||
#include "Experimental.h"
|
||||
#include "audacity/Types.h"
|
||||
#include "UndoManager.h" //JKC: Included for PUSH_XXX definitions.
|
||||
#include "widgets/NumericTextCtrl.h"
|
||||
|
||||
#include "SelectedRegion.h"
|
||||
#include "WaveTrackLocation.h"
|
||||
|
||||
#include "Snap.h"
|
||||
@ -457,8 +457,9 @@ protected:
|
||||
virtual void MakeParentRedrawScrollbars();
|
||||
|
||||
// AS: Pushing the state preserves state for Undo operations.
|
||||
virtual void MakeParentPushState(const wxString &desc, const wxString &shortDesc); // use UndoPush::AUTOSAVE
|
||||
virtual void MakeParentPushState(const wxString &desc, const wxString &shortDesc,
|
||||
int flags = PUSH_AUTOSAVE);
|
||||
UndoPush flags);
|
||||
virtual void MakeParentModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
class ToolsToolBar;
|
||||
class ControlToolBar;
|
||||
enum class UndoPush;
|
||||
|
||||
class AUDACITY_DLL_API TrackPanelListener {
|
||||
|
||||
@ -26,7 +27,7 @@ class AUDACITY_DLL_API TrackPanelListener {
|
||||
virtual ToolsToolBar * TP_GetToolsToolBar() = 0;
|
||||
|
||||
virtual void TP_PushState(const wxString &shortDesc, const wxString &longDesc,
|
||||
int flags = PUSH_AUTOSAVE) = 0;
|
||||
UndoPush flags) = 0;
|
||||
virtual void TP_ModifyState(bool bWantsAutoSave) = 0; // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||
virtual void TP_RedrawScrollbars() = 0;
|
||||
|
@ -31,11 +31,30 @@ UndoManager
|
||||
#include "WaveTrack.h" // temp
|
||||
#include "NoteTrack.h" // for Sonify* function declarations
|
||||
#include "Diags.h"
|
||||
#include "Tags.h"
|
||||
|
||||
#include "UndoManager.h"
|
||||
|
||||
WX_DECLARE_HASH_SET(BlockFile *, wxPointerHash, wxPointerEqual, Set );
|
||||
|
||||
struct UndoStackElem {
|
||||
|
||||
UndoStackElem(std::unique_ptr<TrackList> &&tracks_,
|
||||
const wxString &description_,
|
||||
const wxString &shortDescription_,
|
||||
const SelectedRegion &selectedRegion_,
|
||||
const std::shared_ptr<Tags> &tags_)
|
||||
: state(std::move(tracks_), tags_, selectedRegion_)
|
||||
, description(description_)
|
||||
, shortDescription(shortDescription_)
|
||||
{
|
||||
}
|
||||
|
||||
UndoState state;
|
||||
wxString description;
|
||||
wxString shortDescription;
|
||||
};
|
||||
|
||||
UndoManager::UndoManager()
|
||||
{
|
||||
current = -1;
|
||||
@ -54,14 +73,14 @@ void UndoManager::CalculateSpaceUsage()
|
||||
TIMER_START( "CalculateSpaceUsage", space_calc );
|
||||
TrackListOfKindIterator iter(Track::Wave);
|
||||
|
||||
space.Clear();
|
||||
space.Add(0, stack.GetCount());
|
||||
space.clear();
|
||||
space.resize(stack.size(), 0);
|
||||
|
||||
Set s1, s2;
|
||||
Set *prev = &s1;
|
||||
Set *cur = &s2;
|
||||
|
||||
for (size_t i = 0, cnt = stack.GetCount(); i < cnt; i++)
|
||||
for (size_t i = 0, cnt = stack.size(); i < cnt; i++)
|
||||
{
|
||||
// Swap map pointers
|
||||
std::swap(cur, prev);
|
||||
@ -70,7 +89,7 @@ void UndoManager::CalculateSpaceUsage()
|
||||
cur->clear();
|
||||
|
||||
// Scan all tracks at current level
|
||||
WaveTrack *wt = (WaveTrack *) iter.First(stack[i]->tracks);
|
||||
WaveTrack *wt = (WaveTrack *) iter.First(stack[i]->state.tracks.get());
|
||||
while (wt)
|
||||
{
|
||||
// Scan all clips within current track
|
||||
@ -109,8 +128,8 @@ wxLongLong_t UndoManager::GetLongDescription(unsigned int n, wxString *desc,
|
||||
{
|
||||
n -= 1; // 1 based to zero based
|
||||
|
||||
wxASSERT(n < stack.Count());
|
||||
wxASSERT(space.Count() == stack.Count());
|
||||
wxASSERT(n < stack.size());
|
||||
wxASSERT(space.size() == stack.size());
|
||||
|
||||
*desc = stack[n]->description;
|
||||
|
||||
@ -123,7 +142,7 @@ void UndoManager::GetShortDescription(unsigned int n, wxString *desc)
|
||||
{
|
||||
n -= 1; // 1 based to zero based
|
||||
|
||||
wxASSERT(n < stack.Count());
|
||||
wxASSERT(n < stack.size());
|
||||
|
||||
*desc = stack[n]->shortDescription;
|
||||
}
|
||||
@ -132,19 +151,14 @@ void UndoManager::SetLongDescription(unsigned int n, const wxString &desc)
|
||||
{
|
||||
n -= 1;
|
||||
|
||||
wxASSERT(n < stack.Count());
|
||||
wxASSERT(n < stack.size());
|
||||
|
||||
stack[n]->description = desc;
|
||||
}
|
||||
|
||||
void UndoManager::RemoveStateAt(int n)
|
||||
{
|
||||
stack[n]->tracks->Clear(true);
|
||||
delete stack[n]->tracks;
|
||||
|
||||
UndoStackElem *tmpStackElem = stack[n];
|
||||
stack.RemoveAt(n);
|
||||
delete tmpStackElem;
|
||||
stack.erase(stack.begin() + n);
|
||||
}
|
||||
|
||||
|
||||
@ -160,12 +174,12 @@ void UndoManager::RemoveStates(int num)
|
||||
|
||||
void UndoManager::ClearStates()
|
||||
{
|
||||
RemoveStates(stack.Count());
|
||||
RemoveStates(stack.size());
|
||||
}
|
||||
|
||||
unsigned int UndoManager::GetNumStates()
|
||||
{
|
||||
return stack.Count();
|
||||
return stack.size();
|
||||
}
|
||||
|
||||
unsigned int UndoManager::GetCurrentState()
|
||||
@ -180,49 +194,52 @@ bool UndoManager::UndoAvailable()
|
||||
|
||||
bool UndoManager::RedoAvailable()
|
||||
{
|
||||
return (current < (int)stack.Count() - 1);
|
||||
return (current < (int)stack.size() - 1);
|
||||
}
|
||||
|
||||
void UndoManager::ModifyState(TrackList * l,
|
||||
const SelectedRegion &selectedRegion)
|
||||
void UndoManager::ModifyState(const TrackList * l,
|
||||
const SelectedRegion &selectedRegion,
|
||||
const std::shared_ptr<Tags> &tags)
|
||||
{
|
||||
if (current == wxNOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
SonifyBeginModifyState();
|
||||
// Delete current
|
||||
stack[current]->tracks->Clear(true);
|
||||
delete stack[current]->tracks;
|
||||
// Delete current -- not necessary, but let's reclaim space early
|
||||
stack[current]->state.tracks.reset();
|
||||
|
||||
// Duplicate
|
||||
TrackList *tracksCopy = new TrackList();
|
||||
TrackListIterator iter(l);
|
||||
Track *t = iter.First();
|
||||
auto tracksCopy = std::make_unique<TrackList>(true);
|
||||
TrackListConstIterator iter(l);
|
||||
const Track *t = iter.First();
|
||||
while (t) {
|
||||
tracksCopy->Add(t->Duplicate());
|
||||
t = iter.Next();
|
||||
}
|
||||
|
||||
// Replace
|
||||
stack[current]->tracks = tracksCopy;
|
||||
stack[current]->selectedRegion = selectedRegion;
|
||||
stack[current]->state.tracks = std::move(tracksCopy);
|
||||
stack[current]->state.tags = tags;
|
||||
|
||||
stack[current]->state.selectedRegion = selectedRegion;
|
||||
SonifyEndModifyState();
|
||||
}
|
||||
|
||||
void UndoManager::PushState(TrackList * l,
|
||||
void UndoManager::PushState(const TrackList * l,
|
||||
const SelectedRegion &selectedRegion,
|
||||
const std::shared_ptr<Tags> &tags,
|
||||
const wxString &longDescription,
|
||||
const wxString &shortDescription,
|
||||
int flags)
|
||||
UndoPush flags)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
// If consolidate is set to true, group up to 3 identical operations.
|
||||
if (((flags&PUSH_CONSOLIDATE)!=0) && lastAction == longDescription &&
|
||||
if (((flags & UndoPush::CONSOLIDATE) != UndoPush::MINIMAL) && lastAction == longDescription &&
|
||||
consolidationCount < 2) {
|
||||
consolidationCount++;
|
||||
ModifyState(l, selectedRegion);
|
||||
ModifyState(l, selectedRegion, tags);
|
||||
// MB: If the "saved" state was modified by ModifyState, reset
|
||||
// it so that UnsavedChanges returns true.
|
||||
if (current == saved) {
|
||||
@ -234,25 +251,26 @@ void UndoManager::PushState(TrackList * l,
|
||||
consolidationCount = 0;
|
||||
|
||||
i = current + 1;
|
||||
while (i < stack.Count()) {
|
||||
while (i < stack.size()) {
|
||||
RemoveStateAt(i);
|
||||
}
|
||||
|
||||
TrackList *tracksCopy = new TrackList();
|
||||
TrackListIterator iter(l);
|
||||
Track *t = iter.First();
|
||||
auto tracksCopy = std::make_unique<TrackList>(true);
|
||||
TrackListConstIterator iter(l);
|
||||
const Track *t = iter.First();
|
||||
while (t) {
|
||||
tracksCopy->Add(t->Duplicate());
|
||||
t = iter.Next();
|
||||
}
|
||||
|
||||
UndoStackElem *push = new UndoStackElem();
|
||||
push->tracks = tracksCopy;
|
||||
push->selectedRegion = selectedRegion;
|
||||
push->description = longDescription;
|
||||
push->shortDescription = shortDescription;
|
||||
// Assume tags was duplicted before any changes.
|
||||
// Just save a new shared_ptr to it.
|
||||
stack.emplace_back(
|
||||
std::make_unique<UndoStackElem>
|
||||
(std::move(tracksCopy),
|
||||
longDescription, shortDescription, selectedRegion, tags)
|
||||
);
|
||||
|
||||
stack.Add(push);
|
||||
current++;
|
||||
|
||||
if (saved >= current) {
|
||||
@ -262,49 +280,49 @@ void UndoManager::PushState(TrackList * l,
|
||||
lastAction = longDescription;
|
||||
}
|
||||
|
||||
TrackList *UndoManager::SetStateTo(unsigned int n,
|
||||
SelectedRegion *selectedRegion)
|
||||
const UndoState &UndoManager::SetStateTo
|
||||
(unsigned int n, SelectedRegion *selectedRegion)
|
||||
{
|
||||
n -= 1;
|
||||
|
||||
wxASSERT(n < stack.Count());
|
||||
wxASSERT(n < stack.size());
|
||||
|
||||
current = n;
|
||||
|
||||
if (current == int(stack.Count()-1)) {
|
||||
*selectedRegion = stack[current]->selectedRegion;
|
||||
if (current == int(stack.size()-1)) {
|
||||
*selectedRegion = stack[current]->state.selectedRegion;
|
||||
}
|
||||
else {
|
||||
*selectedRegion = stack[current + 1]->selectedRegion;
|
||||
*selectedRegion = stack[current + 1]->state.selectedRegion;
|
||||
}
|
||||
|
||||
lastAction = wxT("");
|
||||
consolidationCount = 0;
|
||||
|
||||
return stack[current]->tracks;
|
||||
return stack[current]->state;
|
||||
}
|
||||
|
||||
TrackList *UndoManager::Undo(SelectedRegion *selectedRegion)
|
||||
const UndoState &UndoManager::Undo(SelectedRegion *selectedRegion)
|
||||
{
|
||||
wxASSERT(UndoAvailable());
|
||||
|
||||
current--;
|
||||
|
||||
*selectedRegion = stack[current]->selectedRegion;
|
||||
*selectedRegion = stack[current]->state.selectedRegion;
|
||||
|
||||
lastAction = wxT("");
|
||||
consolidationCount = 0;
|
||||
|
||||
return stack[current]->tracks;
|
||||
return stack[current]->state;
|
||||
}
|
||||
|
||||
TrackList *UndoManager::Redo(SelectedRegion *selectedRegion)
|
||||
const UndoState &UndoManager::Redo(SelectedRegion *selectedRegion)
|
||||
{
|
||||
wxASSERT(RedoAvailable());
|
||||
|
||||
current++;
|
||||
|
||||
*selectedRegion = stack[current]->selectedRegion;
|
||||
*selectedRegion = stack[current]->state.selectedRegion;
|
||||
|
||||
/*
|
||||
if (!RedoAvailable()) {
|
||||
@ -322,7 +340,7 @@ TrackList *UndoManager::Redo(SelectedRegion *selectedRegion)
|
||||
lastAction = wxT("");
|
||||
consolidationCount = 0;
|
||||
|
||||
return stack[current]->tracks;
|
||||
return stack[current]->state;
|
||||
}
|
||||
|
||||
bool UndoManager::UnsavedChanges()
|
||||
|
@ -48,44 +48,58 @@
|
||||
#ifndef __AUDACITY_UNDOMANAGER__
|
||||
#define __AUDACITY_UNDOMANAGER__
|
||||
|
||||
#include <wx/dynarray.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <wx/string.h>
|
||||
#include "ondemand/ODTaskThread.h"
|
||||
#include "SelectedRegion.h"
|
||||
|
||||
class Tags;
|
||||
class Track;
|
||||
class TrackList;
|
||||
|
||||
struct UndoStackElem {
|
||||
TrackList *tracks;
|
||||
wxString description;
|
||||
wxString shortDescription;
|
||||
SelectedRegion selectedRegion;
|
||||
struct UndoStackElem;
|
||||
struct UndoState {
|
||||
UndoState(std::unique_ptr<TrackList> &&tracks_,
|
||||
const std::shared_ptr<Tags> &tags_,
|
||||
const SelectedRegion &selectedRegion_)
|
||||
: tracks(std::move(tracks_)), tags(tags_), selectedRegion(selectedRegion_)
|
||||
{}
|
||||
|
||||
std::unique_ptr<TrackList> tracks;
|
||||
std::shared_ptr<Tags> tags;
|
||||
SelectedRegion selectedRegion; // by value
|
||||
};
|
||||
|
||||
WX_DEFINE_USER_EXPORTED_ARRAY(UndoStackElem *, UndoStack, class AUDACITY_DLL_API);
|
||||
// wxWidgets arrays have a base size and to use wxLongLong_t we need to use DOUBLE
|
||||
// to ensure we get a size big enough to hold a wxLongLong_t.
|
||||
WX_DEFINE_USER_EXPORTED_ARRAY_DOUBLE(wxLongLong_t, SpaceArray, class AUDACITY_DLL_API);
|
||||
using UndoStack = std::vector <std::unique_ptr<UndoStackElem>> ;
|
||||
using SpaceArray = std::vector <wxLongLong_t> ;
|
||||
|
||||
// These flags control what extra to do on a PushState
|
||||
// Default is PUSH_AUTOSAVE
|
||||
// Frequent/faster actions use PUSH_CONSOLIDATE
|
||||
const int PUSH_MINIMAL = 0;
|
||||
const int PUSH_CONSOLIDATE = 1;
|
||||
const int PUSH_AUTOSAVE = 2;
|
||||
// Default is AUTOSAVE
|
||||
// Frequent/faster actions use CONSOLIDATE
|
||||
enum class UndoPush {
|
||||
MINIMAL = 0,
|
||||
CONSOLIDATE = 1 << 0,
|
||||
AUTOSAVE = 1 << 1
|
||||
};
|
||||
|
||||
inline UndoPush operator | (UndoPush a, UndoPush b)
|
||||
{ return static_cast<UndoPush>(static_cast<int>(a) | static_cast<int>(b)); }
|
||||
inline UndoPush operator & (UndoPush a, UndoPush b)
|
||||
{ return static_cast<UndoPush>(static_cast<int>(a) & static_cast<int>(b)); }
|
||||
|
||||
class AUDACITY_DLL_API UndoManager {
|
||||
public:
|
||||
UndoManager();
|
||||
~UndoManager();
|
||||
|
||||
void PushState(TrackList * l,
|
||||
void PushState(const TrackList * l,
|
||||
const SelectedRegion &selectedRegion,
|
||||
const std::shared_ptr<Tags> &tags,
|
||||
const wxString &longDescription, const wxString &shortDescription,
|
||||
int flags = PUSH_AUTOSAVE);
|
||||
void ModifyState(TrackList * l,
|
||||
const SelectedRegion &selectedRegion);
|
||||
UndoPush flags = UndoPush::AUTOSAVE);
|
||||
void ModifyState(const TrackList * l,
|
||||
const SelectedRegion &selectedRegion, const std::shared_ptr<Tags> &tags);
|
||||
void ClearStates();
|
||||
void RemoveStates(int num); // removes the 'num' oldest states
|
||||
void RemoveStateAt(int n); // removes the n'th state (1 is oldest)
|
||||
@ -96,9 +110,9 @@ class AUDACITY_DLL_API UndoManager {
|
||||
wxLongLong_t GetLongDescription(unsigned int n, wxString *desc, wxString *size);
|
||||
void SetLongDescription(unsigned int n, const wxString &desc);
|
||||
|
||||
TrackList *SetStateTo(unsigned int n, SelectedRegion *selectedRegion);
|
||||
TrackList *Undo(SelectedRegion *selectedRegion);
|
||||
TrackList *Redo(SelectedRegion *selectedRegion);
|
||||
const UndoState &SetStateTo(unsigned int n, SelectedRegion *selectedRegion);
|
||||
const UndoState &Undo(SelectedRegion *selectedRegion);
|
||||
const UndoState &Redo(SelectedRegion *selectedRegion);
|
||||
|
||||
bool UndoAvailable();
|
||||
bool RedoAvailable();
|
||||
|
@ -116,7 +116,7 @@ WaveTrack::WaveTrack(DirManager *projDirManager, sampleFormat format, double rat
|
||||
mAutoSaveIdent = 0;
|
||||
}
|
||||
|
||||
WaveTrack::WaveTrack(WaveTrack &orig):
|
||||
WaveTrack::WaveTrack(const WaveTrack &orig):
|
||||
Track(orig)
|
||||
, mpSpectrumSettings(orig.mpSpectrumSettings
|
||||
? new SpectrogramSettings(*orig.mpSpectrumSettings) : 0
|
||||
@ -362,7 +362,7 @@ void WaveTrack::SetSpectrumBounds(float min, float max)
|
||||
mSpectrumMax = max;
|
||||
}
|
||||
|
||||
Track *WaveTrack::Duplicate()
|
||||
Track *WaveTrack::Duplicate() const
|
||||
{
|
||||
return new WaveTrack(*this);
|
||||
}
|
||||
|
@ -72,10 +72,10 @@ class AUDACITY_DLL_API WaveTrack : public Track {
|
||||
WaveTrack(DirManager * projDirManager,
|
||||
sampleFormat format = (sampleFormat)0,
|
||||
double rate = 0);
|
||||
WaveTrack(WaveTrack &orig);
|
||||
WaveTrack(const WaveTrack &orig);
|
||||
|
||||
void Init(const WaveTrack &orig);
|
||||
virtual Track *Duplicate();
|
||||
virtual Track *Duplicate() const;
|
||||
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
|
||||
void VirtualStereoInit();
|
||||
#endif
|
||||
|
@ -364,7 +364,7 @@ bool Exporter::Process(AudacityProject *project, bool selectedOnly, double t0, d
|
||||
|
||||
// Let user edit MetaData
|
||||
if (mPlugins[mFormat]->GetCanMetaData(mSubFormat)) {
|
||||
if (!(project->GetTags()->ShowEditDialog(project, _("Edit Metadata Tags"), mProject->GetShowId3Dialog()))) {
|
||||
if (!(project->DoEditMetadata(_("Edit Metadata Tags for Export"), _("Exported Tags"), mProject->GetShowId3Dialog()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) = 0;
|
||||
|
||||
protected:
|
||||
|
@ -291,7 +291,7 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
};
|
||||
|
||||
@ -318,7 +318,7 @@ int ExportCL::Export(AudacityProject *project,
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec,
|
||||
Tags *WXUNUSED(metadata),
|
||||
const Tags *WXUNUSED(metadata),
|
||||
int WXUNUSED(subformat))
|
||||
{
|
||||
wxString output;
|
||||
|
@ -101,16 +101,16 @@ public:
|
||||
bool CheckFileName(wxFileName &filename, int format = 0);
|
||||
|
||||
/// Format intialization
|
||||
bool Init(const char *shortname, AudacityProject *project, Tags *metadata, int subformat);
|
||||
bool Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat);
|
||||
|
||||
/// Codec intialization
|
||||
bool InitCodecs(AudacityProject *project);
|
||||
|
||||
/// Writes metadata
|
||||
bool AddTags(Tags *metadata);
|
||||
bool AddTags(const Tags *metadata);
|
||||
|
||||
/// Sets individual metadata values
|
||||
void SetMetadata(Tags *tags, const char *name, const wxChar *tag);
|
||||
void SetMetadata(const Tags *tags, const char *name, const wxChar *tag);
|
||||
|
||||
/// Encodes audio
|
||||
bool EncodeAudioFrame(int16_t *pFrame, int frameSize);
|
||||
@ -145,7 +145,7 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
private:
|
||||
@ -256,7 +256,7 @@ bool ExportFFmpeg::CheckFileName(wxFileName & WXUNUSED(filename), int WXUNUSED(f
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, Tags *metadata, int subformat)
|
||||
bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, const Tags *metadata, int subformat)
|
||||
{
|
||||
int err;
|
||||
//FFmpegLibsInst->LoadLibs(NULL,true); //Loaded at startup or from Prefs now
|
||||
@ -312,7 +312,8 @@ bool ExportFFmpeg::Init(const char *shortname, AudacityProject *project, Tags *m
|
||||
if (!InitCodecs(project))
|
||||
return false;
|
||||
|
||||
if (metadata == NULL) metadata = project->GetTags();
|
||||
if (metadata == NULL)
|
||||
metadata = project->GetTags();
|
||||
|
||||
// Add metadata BEFORE writing the header.
|
||||
// At the moment that works with ffmpeg-git and ffmpeg-0.5 for MP4.
|
||||
@ -792,7 +793,7 @@ bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, int frameSize)
|
||||
|
||||
int ExportFFmpeg::Export(AudacityProject *project,
|
||||
int channels, const wxString &fName,
|
||||
bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, Tags *metadata, int subformat)
|
||||
bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, const Tags *metadata, int subformat)
|
||||
{
|
||||
if (!CheckFFmpegPresence())
|
||||
return false;
|
||||
@ -873,7 +874,7 @@ void AddStringTagANSI(char field[], int size, wxString value)
|
||||
memcpy(field,value.mb_str(),(int)strlen(value.mb_str()) > size -1 ? size -1 : strlen(value.mb_str()));
|
||||
}
|
||||
|
||||
bool ExportFFmpeg::AddTags(Tags *tags)
|
||||
bool ExportFFmpeg::AddTags(const Tags *tags)
|
||||
{
|
||||
if (tags == NULL)
|
||||
{
|
||||
@ -891,7 +892,7 @@ bool ExportFFmpeg::AddTags(Tags *tags)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExportFFmpeg::SetMetadata(Tags *tags, const char *name, const wxChar *tag)
|
||||
void ExportFFmpeg::SetMetadata(const Tags *tags, const char *name, const wxChar *tag)
|
||||
{
|
||||
if (tags->HasTag(tag))
|
||||
{
|
||||
|
@ -190,12 +190,12 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
private:
|
||||
|
||||
bool GetMetadata(AudacityProject *project, Tags *tags);
|
||||
bool GetMetadata(AudacityProject *project, const Tags *tags);
|
||||
|
||||
FLAC__StreamMetadata *mMetadata;
|
||||
};
|
||||
@ -225,7 +225,7 @@ int ExportFLAC::Export(AudacityProject *project,
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec,
|
||||
Tags *metadata,
|
||||
const Tags *metadata,
|
||||
int WXUNUSED(subformat))
|
||||
{
|
||||
double rate = project->GetRate();
|
||||
@ -380,7 +380,7 @@ wxWindow *ExportFLAC::OptionsCreate(wxWindow *parent, int format)
|
||||
// expects that array to be valid until the stream is initialized.
|
||||
//
|
||||
// This has been fixed in 1.1.4.
|
||||
bool ExportFLAC::GetMetadata(AudacityProject *project, Tags *tags)
|
||||
bool ExportFLAC::GetMetadata(AudacityProject *project, const Tags *tags)
|
||||
{
|
||||
// Retrieve tags if needed
|
||||
if (tags == NULL)
|
||||
@ -388,8 +388,10 @@ bool ExportFLAC::GetMetadata(AudacityProject *project, Tags *tags)
|
||||
|
||||
mMetadata = ::FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
|
||||
wxString n, v;
|
||||
for (bool cont = tags->GetFirst(n, v); cont; cont = tags->GetNext(n, v)) {
|
||||
wxString n;
|
||||
for (const auto &pair : tags->GetRange()) {
|
||||
n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
if (n == TAG_YEAR) {
|
||||
n = wxT("DATE");
|
||||
}
|
||||
|
@ -181,12 +181,12 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
private:
|
||||
|
||||
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, Tags *tags);
|
||||
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, const Tags *tags);
|
||||
#ifdef USE_LIBID3TAG
|
||||
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
|
||||
#endif
|
||||
@ -211,7 +211,7 @@ void ExportMP2::Destroy()
|
||||
|
||||
int ExportMP2::Export(AudacityProject *project,
|
||||
int channels, const wxString &fName,
|
||||
bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, Tags *metadata,
|
||||
bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, const Tags *metadata,
|
||||
int WXUNUSED(subformat))
|
||||
{
|
||||
bool stereo = (channels == 2);
|
||||
@ -339,13 +339,14 @@ wxWindow *ExportMP2::OptionsCreate(wxWindow *parent, int format)
|
||||
}
|
||||
|
||||
// returns buffer len; caller frees
|
||||
int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool *endOfFile, Tags *tags)
|
||||
int ExportMP2::AddTags(AudacityProject * WXUNUSED(project), char **buffer, bool *endOfFile, const Tags *tags)
|
||||
{
|
||||
#ifdef USE_LIBID3TAG
|
||||
struct id3_tag *tp = id3_tag_new();
|
||||
|
||||
wxString n, v;
|
||||
for (bool cont = tags->GetFirst(n, v); cont; cont = tags->GetNext(n, v)) {
|
||||
for (const auto &pair : tags->GetRange()) {
|
||||
const auto &n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
const char *name = "TXXX";
|
||||
|
||||
if (n.CmpNoCase(TAG_TITLE) == 0) {
|
||||
|
@ -1569,7 +1569,7 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
private:
|
||||
@ -1577,7 +1577,7 @@ private:
|
||||
int FindValue(CHOICES *choices, int cnt, int needle, int def);
|
||||
wxString FindName(CHOICES *choices, int cnt, int needle);
|
||||
int AskResample(int bitrate, int rate, int lowrate, int highrate);
|
||||
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, Tags *tags);
|
||||
int AddTags(AudacityProject *project, char **buffer, bool *endOfFile, const Tags *tags);
|
||||
#ifdef USE_LIBID3TAG
|
||||
void AddFrame(struct id3_tag *tp, const wxString & n, const wxString & v, const char *name);
|
||||
#endif
|
||||
@ -1624,7 +1624,7 @@ int ExportMP3::Export(AudacityProject *project,
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec,
|
||||
Tags *metadata,
|
||||
const Tags *metadata,
|
||||
int WXUNUSED(subformat))
|
||||
{
|
||||
int rate = lrint(project->GetRate());
|
||||
@ -1965,13 +1965,14 @@ int ExportMP3::AskResample(int bitrate, int rate, int lowrate, int highrate)
|
||||
}
|
||||
|
||||
// returns buffer len; caller frees
|
||||
int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *endOfFile, Tags *tags)
|
||||
int ExportMP3::AddTags(AudacityProject *WXUNUSED(project), char **buffer, bool *endOfFile, const Tags *tags)
|
||||
{
|
||||
#ifdef USE_LIBID3TAG
|
||||
struct id3_tag *tp = id3_tag_new();
|
||||
|
||||
wxString n, v;
|
||||
for (bool cont = tags->GetFirst(n, v); cont; cont = tags->GetNext(n, v)) {
|
||||
for (const auto &pair : tags->GetRange()) {
|
||||
const auto &n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
const char *name = "TXXX";
|
||||
|
||||
if (n.CmpNoCase(TAG_TITLE) == 0) {
|
||||
|
@ -911,7 +911,7 @@ int ExportMultiple::DoExport(int channels,
|
||||
bool selectedOnly,
|
||||
double t0,
|
||||
double t1,
|
||||
Tags tags)
|
||||
const Tags &tags)
|
||||
{
|
||||
wxLogDebug(wxT("Doing multiple Export: File name \"%s\""), (name.GetFullName()).c_str());
|
||||
wxLogDebug(wxT("Channels: %i, Start: %lf, End: %lf "), channels, t0, t1);
|
||||
|
@ -79,7 +79,7 @@ private:
|
||||
bool selectedOnly,
|
||||
double t0,
|
||||
double t1,
|
||||
Tags tags);
|
||||
const Tags &tags);
|
||||
/** \brief Takes an arbitrary text string and converts it to a form that can
|
||||
* be used as a file name, if necessary prompting the user to edit the file
|
||||
* name produced */
|
||||
|
@ -140,12 +140,12 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
|
||||
private:
|
||||
|
||||
bool FillComment(AudacityProject *project, vorbis_comment *comment, Tags *metadata);
|
||||
bool FillComment(AudacityProject *project, vorbis_comment *comment, const Tags *metadata);
|
||||
};
|
||||
|
||||
ExportOGG::ExportOGG()
|
||||
@ -171,7 +171,7 @@ int ExportOGG::Export(AudacityProject *project,
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec,
|
||||
Tags *metadata,
|
||||
const Tags *metadata,
|
||||
int WXUNUSED(subformat))
|
||||
{
|
||||
double rate = project->GetRate();
|
||||
@ -341,7 +341,7 @@ wxWindow *ExportOGG::OptionsCreate(wxWindow *parent, int format)
|
||||
return safenew ExportOGGOptions(parent, format);
|
||||
}
|
||||
|
||||
bool ExportOGG::FillComment(AudacityProject *project, vorbis_comment *comment, Tags *metadata)
|
||||
bool ExportOGG::FillComment(AudacityProject *project, vorbis_comment *comment, const Tags *metadata)
|
||||
{
|
||||
// Retrieve tags from project if not over-ridden
|
||||
if (metadata == NULL)
|
||||
@ -349,8 +349,10 @@ bool ExportOGG::FillComment(AudacityProject *project, vorbis_comment *comment, T
|
||||
|
||||
vorbis_comment_init(comment);
|
||||
|
||||
wxString n, v;
|
||||
for (bool cont = metadata->GetFirst(n, v); cont; cont = metadata->GetNext(n, v)) {
|
||||
wxString n;
|
||||
for (const auto &pair : metadata->GetRange()) {
|
||||
n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
if (n == TAG_YEAR) {
|
||||
n = wxT("DATE");
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ public:
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec = NULL,
|
||||
Tags *metadata = NULL,
|
||||
const Tags *metadata = NULL,
|
||||
int subformat = 0) override;
|
||||
// optional
|
||||
wxString GetExtension(int index);
|
||||
@ -329,8 +329,8 @@ public:
|
||||
private:
|
||||
|
||||
char *AdjustString(const wxString & wxStr, int sf_format);
|
||||
bool AddStrings(AudacityProject *project, SNDFILE *sf, Tags *tags, int sf_format);
|
||||
void AddID3Chunk(wxString fName, Tags *tags, int sf_format);
|
||||
bool AddStrings(AudacityProject *project, SNDFILE *sf, const Tags *tags, int sf_format);
|
||||
void AddID3Chunk(wxString fName, const Tags *tags, int sf_format);
|
||||
|
||||
};
|
||||
|
||||
@ -395,7 +395,7 @@ int ExportPCM::Export(AudacityProject *project,
|
||||
double t0,
|
||||
double t1,
|
||||
MixerSpec *mixerSpec,
|
||||
Tags *metadata,
|
||||
const Tags *metadata,
|
||||
int subformat)
|
||||
{
|
||||
double rate = project->GetRate();
|
||||
@ -664,7 +664,7 @@ char *ExportPCM::AdjustString(const wxString & wxStr, int sf_format)
|
||||
return pDest;
|
||||
}
|
||||
|
||||
bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, Tags *tags, int sf_format)
|
||||
bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, const Tags *tags, int sf_format)
|
||||
{
|
||||
if (tags->HasTag(TAG_TITLE)) {
|
||||
char * ascii7Str = AdjustString(tags->GetTag(TAG_TITLE), sf_format);
|
||||
@ -741,13 +741,14 @@ bool ExportPCM::AddStrings(AudacityProject * WXUNUSED(project), SNDFILE *sf, Tag
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExportPCM::AddID3Chunk(wxString fName, Tags *tags, int sf_format)
|
||||
void ExportPCM::AddID3Chunk(wxString fName, const Tags *tags, int sf_format)
|
||||
{
|
||||
#ifdef USE_LIBID3TAG
|
||||
struct id3_tag *tp = id3_tag_new();
|
||||
|
||||
wxString n, v;
|
||||
for (bool cont = tags->GetFirst(n, v); cont; cont = tags->GetNext(n, v)) {
|
||||
for (const auto &pair : tags->GetRange()) {
|
||||
const auto &n = pair.first;
|
||||
const auto &v = pair.second;
|
||||
const char *name = "TXXX";
|
||||
|
||||
if (n.CmpNoCase(TAG_TITLE) == 0) {
|
||||
|
@ -22,6 +22,7 @@ in a background thread.
|
||||
#include "ODManager.h"
|
||||
#include "../WaveTrack.h"
|
||||
#include "../Project.h"
|
||||
#include "../UndoManager.h"
|
||||
//temporarilly commented out till it is added to all projects
|
||||
//#include "../Profiler.h"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user