Audacity 3.2.0
Public Member Functions | Static Public Member Functions | Private Member Functions | Private Attributes | List of all members
TagsEditorDialog Class Referencefinal

Derived from ExpandingToolBar, this dialog allows editing of Tags. More...

#include <TagsEditor.h>

Inheritance diagram for TagsEditorDialog:
[legend]
Collaboration diagram for TagsEditorDialog:
[legend]

Public Member Functions

 TagsEditorDialog (wxWindow *parent, const TranslatableString &title, Tags *tags, bool editTitle, bool editTrack)
 
virtual ~TagsEditorDialog ()
 
void PopulateOrExchange (ShuttleGui &S)
 
void OnDontShow (wxCommandEvent &Evt)
 
void OnHelp (wxCommandEvent &Evt)
 
bool TransferDataToWindow () override
 
bool TransferDataFromWindow () override
 
- Public Member Functions inherited from wxDialogWrapper
 wxDialogWrapper ()
 
 wxDialogWrapper (wxWindow *parent, wxWindowID id, const TranslatableString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE, const TranslatableString &name=XO("Dialog"))
 
bool Create (wxWindow *parent, wxWindowID id, const TranslatableString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE, const TranslatableString &name=XO("Dialog"))
 
void SetTitle (const TranslatableString &title)
 
void SetLabel (const TranslatableString &title)
 
void SetName (const TranslatableString &title)
 
void SetName ()
 
- Public Member Functions inherited from wxTabTraversalWrapper< wxDialog >
 wxTabTraversalWrapper (Args &&... args)
 
 wxTabTraversalWrapper (const wxTabTraversalWrapper &)=delete
 
 wxTabTraversalWrapper (wxTabTraversalWrapper &&)=delete
 
wxTabTraversalWrapperoperator= (const wxTabTraversalWrapper &)=delete
 
wxTabTraversalWrapperoperator= (wxTabTraversalWrapper &&)=delete
 

Static Public Member Functions

static AUDACITY_DLL_API bool ShowEditDialog (Tags &tags, wxWindow *parent, const TranslatableString &title, bool force=false)
 
static AUDACITY_DLL_API bool DoEditMetadata (AudacityProject &project, const TranslatableString &title, const TranslatableString &shortUndoDescription, bool force)
 

Private Member Functions

void PopulateGenres ()
 
void SetEditors ()
 
void OnChange (wxGridEvent &event)
 
void OnEdit (wxCommandEvent &event)
 
void OnReset (wxCommandEvent &event)
 
void OnClear (wxCommandEvent &event)
 
void OnLoad (wxCommandEvent &event)
 
void OnSave (wxCommandEvent &event)
 
void OnSaveDefaults (wxCommandEvent &event)
 
void OnAdd (wxCommandEvent &event)
 
void OnRemove (wxCommandEvent &event)
 
void OnOk (wxCommandEvent &event)
 
void DoCancel (bool escKey)
 
void OnCancel (wxCommandEvent &event)
 
void OnKeyDown (wxKeyEvent &event)
 
bool IsWindowRectValid (const wxRect *windowRect) const
 

Private Attributes

TagsmTags
 
bool mEditTitle
 
bool mEditTrack
 
Tags mLocal
 
GridmGrid
 
ComboEditormComboEditor
 
wxGridCellStringRenderer * mStringRenderer
 

Detailed Description

Derived from ExpandingToolBar, this dialog allows editing of Tags.

Definition at line 19 of file TagsEditor.h.

Constructor & Destructor Documentation

◆ TagsEditorDialog()

TagsEditorDialog::TagsEditorDialog ( wxWindow *  parent,
const TranslatableString title,
Tags tags,
bool  editTitle,
bool  editTrack 
)

Definition at line 209 of file TagsEditor.cpp.

214: wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize,
215 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
216 mTags(tags),
217 mEditTitle(editTitle),
218 mEditTrack(editTrack)
219{
220 SetName();
221
222 mGrid = NULL;
223
224 // Make a local copy of the passed in tags
225 mLocal = *mTags;
226
227 // Build, size, and position the dialog
228 ShuttleGui S(this, eIsCreating);
230
232
233 Layout();
234 Fit();
235 Center();
236 wxSize sz = GetSize();
237 SetSizeHints(sz.x, std::min(sz.y, 600));
238
239 // Restore the original tags because TransferDataToWindow() will be called again
240 mLocal.Clear();
241 mLocal = *mTags;
242
243 // Override size and position with last saved
244 wxRect r = GetRect();
245 gPrefs->Read(wxT("/TagsEditorDialog/x"), &r.x, r.x);
246 gPrefs->Read(wxT("/TagsEditorDialog/y"), &r.y, r.y);
247 gPrefs->Read(wxT("/TagsEditorDialog/width"), &r.width, r.width);
248 gPrefs->Read(wxT("/TagsEditorDialog/height"), &r.height, r.height);
249 //On multi-monitor systems, there's a chance the last saved window position is
250 //on a monitor that has been removed or is unavailable.
251 if (IsWindowRectValid(&r))
252 Move(r.GetPosition());
253
254 SetSize(r.GetSize());
255 Layout();
256
257 // Resize value column width based on width of columns and the vertical scrollbar
258 wxScrollBar sb(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
259 r = mGrid->GetClientRect();
260 r.width -= mGrid->GetColSize(0);
261 r.width -= sb.GetSize().GetWidth();
262 r.width -= 10;
263 r.width -= r.x;
264 mGrid->SetColSize(1, r.width);
265 //Bug 2038
266 mGrid->SetFocus();
267
268 // Load the genres
270}
wxT("CloseDown"))
int min(int a, int b)
static const auto title
FileConfig * gPrefs
Definition: Prefs.cpp:70
@ eIsCreating
Definition: ShuttleGui.h:39
#define S(N)
Definition: ToChars.cpp:64
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
bool IsWindowRectValid(const wxRect *windowRect) const
Definition: TagsEditor.cpp:929
void PopulateOrExchange(ShuttleGui &S)
Definition: TagsEditor.cpp:285
bool TransferDataToWindow() override
Definition: TagsEditor.cpp:442
void Clear()
Definition: Tags.cpp:308

References eIsCreating, gPrefs, min(), S, and wxT().

Here is the call graph for this function:

◆ ~TagsEditorDialog()

TagsEditorDialog::~TagsEditorDialog ( )
virtual

Definition at line 272 of file TagsEditor.cpp.

273{
274 // This DELETE is not needed because wxWidgets owns the grid.
275// DELETE mGrid;
276
277// TODO: Need to figure out if these should be deleted. Looks like the wxGrid
278// code takes ownership and uses reference counting, but there's been
279// cases where they show up as memory leaks.
280// PRL: Fixed the leaks, see commit c87eb0804bc5f40659b133cab6e2ade061959645
281// DELETE mStringRenderer;
282// DELETE mComboEditor;
283}

Member Function Documentation

◆ DoCancel()

void TagsEditorDialog::DoCancel ( bool  escKey)
private

Definition at line 861 of file TagsEditor.cpp.

862{
863 if (mGrid->IsCellEditControlShown()) {
864 auto editor = mGrid->GetCellEditor(mGrid->GetGridCursorRow(),
865 mGrid->GetGridCursorCol());
866 editor->Reset();
867 // To avoid memory leak, don't forget DecRef()!
868 editor->DecRef();
869 mGrid->HideCellEditControl();
870#if defined(__WXMSW__)
871 return;
872#endif
873 }
874
875 auto focus = wxWindow::FindFocus();
876 if (escKey && focus == mGrid)
877 return;
878
879 EndModal(wxID_CANCEL);
880}

References mGrid.

Referenced by OnCancel(), and OnKeyDown().

Here is the caller graph for this function:

◆ DoEditMetadata()

bool TagsEditorDialog::DoEditMetadata ( AudacityProject project,
const TranslatableString title,
const TranslatableString shortUndoDescription,
bool  force 
)
static

Invoke ShowEditDialog on project's tags; commit change in undo history, return true if not cancelled

Definition at line 952 of file TagsEditor.cpp.

955{
956 auto &settings = ProjectSettings::Get( project );
957 auto &tags = Tags::Get( project );
958
959 // Back up my tags
960 // Tags (artist name, song properties, MP3 ID3 info, etc.)
961 // The structure may be shared with undo history entries
962 // To keep undo working correctly, always replace this with a NEW duplicate
963 // BEFORE doing any editing of it!
964 auto newTags = tags.Duplicate();
965
967 *newTags, &GetProjectFrame( project ), title, force)) {
968 if (tags != *newTags) {
969 // Commit the change to project state only now.
970 Tags::Set( project, newTags );
971 ProjectHistory::Get( project ).PushState( title, shortUndoDescription);
972 }
973 bool bShowInFuture;
974 gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &bShowInFuture, true);
975 settings.SetShowId3Dialog( bShowInFuture );
976 return true;
977 }
978
979 return false;
980}
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
static Settings & settings()
Definition: TrackInfo.cpp:87
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
static AUDACITY_DLL_API bool ShowEditDialog(Tags &tags, wxWindow *parent, const TranslatableString &title, bool force=false)
Definition: TagsEditor.cpp:24
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:214
static Tags & Set(AudacityProject &project, const std::shared_ptr< Tags > &tags)
Definition: Tags.cpp:224

References ProjectHistory::Get(), Tags::Get(), ProjectSettings::Get(), GetProjectFrame(), gPrefs, ProjectHistory::PushState(), Tags::Set(), settings(), ShowEditDialog(), title, and wxT().

Referenced by anonymous_namespace{TagsEditor.cpp}::OnEditMetadata(), Exporter::Process(), and Exporter::SetAutoExportOptions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsWindowRectValid()

bool TagsEditorDialog::IsWindowRectValid ( const wxRect *  windowRect) const
private

Definition at line 929 of file TagsEditor.cpp.

930{
931 wxDisplay display;
932 wxPoint topLeft(windowRect->GetTopLeft().x, windowRect->GetTopLeft().y);
933 wxPoint topRight(windowRect->GetTopRight().x, windowRect->GetTopRight().y);
934 wxPoint bottomLeft(windowRect->GetBottomLeft().x, windowRect->GetBottomLeft().y);
935 wxPoint bottomRight(windowRect->GetBottomRight().x, windowRect->GetBottomRight().y);
936 display.GetFromPoint(topLeft);
937 if (display.GetFromPoint(topLeft) == -1 &&
938 display.GetFromPoint(topRight) == -1 &&
939 display.GetFromPoint(bottomLeft) == -1 &&
940 display.GetFromPoint(bottomRight) == -1) {
941 return false;
942 }
943
944 return true;
945}

◆ OnAdd()

void TagsEditorDialog::OnAdd ( wxCommandEvent &  event)
private

Definition at line 801 of file TagsEditor.cpp.

802{
803 mGrid->AppendRows();
804}

References mGrid.

◆ OnCancel()

void TagsEditorDialog::OnCancel ( wxCommandEvent &  event)
private

Definition at line 856 of file TagsEditor.cpp.

857{
858 DoCancel(false);
859}
void DoCancel(bool escKey)
Definition: TagsEditor.cpp:861

References DoCancel().

Here is the call graph for this function:

◆ OnChange()

void TagsEditorDialog::OnChange ( wxGridEvent &  event)
private

Definition at line 504 of file TagsEditor.cpp.

505{
506 static bool ischanging = false;
507
508 // Prevent recursion
509 if (ischanging) {
510 return;
511 }
512
513 event.Skip();
514
515 if (event.GetCol() != 0) {
516 return;
517 }
518
519 // Do not permit duplication of any of the tags.
520 // Tags differing only in case are nondistinct.
521 auto row = event.GetRow();
522 const wxString key0 = mGrid->GetCellValue(row, 0).Upper();
523 auto nn = mGrid->GetNumberRows();
524 for (decltype(nn) ii = 0; ii < nn; ++ii) {
525 if (ii == row)
526 continue;
527 auto key = mGrid->GetCellValue(ii, 0).Upper();
528 if (key0.CmpNoCase(key) == 0) {
529 ischanging = true;
530 wxBell();
531 mGrid->SetGridCursor(ii, 0);
532 event.Veto();
533 ischanging = false;
534 break;
535 }
536 }
537
538 return;
539}
static const AudacityProject::AttachedObjects::RegisteredFactory key

References key, anonymous_namespace{TracksPrefs.cpp}::key0, and mGrid.

◆ OnClear()

void TagsEditorDialog::OnClear ( wxCommandEvent &  event)
private

Definition at line 639 of file TagsEditor.cpp.

640{
641 mLocal.Clear();
642
644}

References Tags::Clear(), mLocal, and TransferDataToWindow().

Here is the call graph for this function:

◆ OnDontShow()

void TagsEditorDialog::OnDontShow ( wxCommandEvent &  Evt)

Definition at line 376 of file TagsEditor.cpp.

377{
378 bool bShow = !Evt.IsChecked();
379 gPrefs->Write(wxT("/AudioFiles/ShowId3Dialog"), bShow );
380 gPrefs->Flush();
381}
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143

References FileConfig::Flush(), gPrefs, and wxT().

Here is the call graph for this function:

◆ OnEdit()

void TagsEditorDialog::OnEdit ( wxCommandEvent &  event)
private

Definition at line 541 of file TagsEditor.cpp.

542{
543 if (mGrid->IsCellEditControlShown()) {
544 mGrid->SaveEditControlValue();
545 mGrid->HideCellEditControl();
546 }
547
548 wxDialogWrapper dlg(this, wxID_ANY, XO("Edit Genres"),
549 wxDefaultPosition, wxDefaultSize,
550 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
551 dlg.SetName();
552 wxTextCtrl *tc;
553
554 ShuttleGui S(&dlg, eIsCreating);
555
556 S.StartVerticalLay(true);
557 {
558 tc = S.AddTextWindow(wxT(""));
559 }
560 S.EndVerticalLay();
561
562 S.AddStandardButtons();
563
564 wxArrayString g;
565 int cnt = mLocal.GetNumUserGenres();
566 for (int i = 0; i < cnt; i++) {
567 g.push_back(mLocal.GetUserGenre(i));
568 }
569 std::sort( g.begin(), g.end() );
570
571 for (int i = 0; i < cnt; i++) {
572 tc->AppendText(g[i] + wxT("\n"));
573 }
574
575 dlg.Center();
576 if (dlg.ShowModal() == wxID_CANCEL) {
577 return;
578 }
579
580 wxFileName fn(FileNames::DataDir(), wxT("genres.txt"));
581 wxFile f(fn.GetFullPath(), wxFile::write);
582 if (!f.IsOpened() || !f.Write(tc->GetValue())) {
584 XO("Unable to save genre file."),
585 XO("Reset Genres") );
586 return;
587 }
588
590
592}
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
XO("Cut/Copy/Paste")
static const auto fn
wxString GetUserGenre(int value)
Definition: Tags.cpp:374
int GetNumUserGenres()
Definition: Tags.cpp:343
void LoadGenres()
Definition: Tags.cpp:356
FILES_API FilePath DataDir()
Audacity user data directory.

References AudacityMessageBox(), FileNames::DataDir(), eIsCreating, fn, Tags::GetNumUserGenres(), Tags::GetUserGenre(), Tags::LoadGenres(), mGrid, mLocal, PopulateGenres(), S, wxDialogWrapper::SetName(), wxT(), and XO().

Here is the call graph for this function:

◆ OnHelp()

void TagsEditorDialog::OnHelp ( wxCommandEvent &  Evt)

Definition at line 383 of file TagsEditor.cpp.

384{
385 HelpSystem::ShowHelp(this, L"Metadata_Editor", true);
386}
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:234

References HelpSystem::ShowHelp().

Here is the call graph for this function:

◆ OnKeyDown()

void TagsEditorDialog::OnKeyDown ( wxKeyEvent &  event)
private

Definition at line 882 of file TagsEditor.cpp.

883{
884 if (event.GetKeyCode() == WXK_ESCAPE)
885 DoCancel(true);
886 else
887 event.Skip();
888}

References DoCancel().

Here is the call graph for this function:

◆ OnLoad()

void TagsEditorDialog::OnLoad ( wxCommandEvent &  event)
private

Definition at line 646 of file TagsEditor.cpp.

647{
648 wxString fn;
649
650 // Ask the user for the real name
651 fn = SelectFile(FileNames::Operation::_None,
652 XO("Load Metadata As:"),
654 wxT("Tags.xml"),
655 wxT("xml"),
657 wxFD_OPEN | wxRESIZE_BORDER,
658 this);
659
660 // User canceled...
661 if (fn.empty()) {
662 return;
663 }
664
665 // Load the metadata
666 decltype(mLocal) temp;
667 XMLFileReader reader;
668 if (!reader.Parse(&temp, fn)) {
669 // Inform user of load failure
671 reader.GetErrorStr(),
672 XO("Error Loading Metadata"),
673 wxOK | wxCENTRE,
674 this);
675 return;
676 }
677
678 // Remember title and track in case they're read only
679 wxString title = mLocal.GetTag(TAG_TITLE);
680 wxString track = mLocal.GetTag(TAG_TRACK);
681
682 // Replace existing tags with loaded ones
683 mLocal = temp;
684
685 // Restore title
686 if (!mEditTitle) {
688 }
689
690 // Restore track
691 if (!mEditTrack) {
692 mLocal.SetTag(TAG_TRACK, track);
693 }
694
695 // Go fill up the window
697
698 return;
699}
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
#define TAG_TRACK
Definition: Tags.h:61
#define TAG_TITLE
Definition: Tags.h:58
FILES_API const FileType XMLFiles
Definition: FileNames.h:73
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:441
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:416
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:19
const TranslatableString & GetErrorStr() const
bool Parse(XMLTagHandler *baseHandler, const FilePath &fname)

References AudacityMessageBox(), FileNames::DataDir(), fn, XMLFileReader::GetErrorStr(), Tags::GetTag(), mEditTitle, mEditTrack, mLocal, XMLFileReader::Parse(), SelectFile(), Tags::SetTag(), TAG_TITLE, TAG_TRACK, title, TransferDataToWindow(), wxT(), FileNames::XMLFiles, and XO().

Here is the call graph for this function:

◆ OnOk()

void TagsEditorDialog::OnOk ( wxCommandEvent &  event)
private

Definition at line 827 of file TagsEditor.cpp.

828{
829 if (mGrid->IsCellEditControlShown()) {
830 mGrid->SaveEditControlValue();
831 mGrid->HideCellEditControl();
832#if defined(__WXMAC__)
833 // The cell editors do not capture the ENTER key, so it invokes
834 // the default button ("Ok") when it should just close the
835 // editor. So, cancel the "Ok" action.
836 return;
837#endif
838 }
839
840 if (!Validate() || !TransferDataFromWindow()) {
841 return;
842 }
843
844 *mTags = mLocal;
845
846 wxRect r = GetRect();
847 gPrefs->Write(wxT("/TagsEditorDialog/x"), r.x);
848 gPrefs->Write(wxT("/TagsEditorDialog/y"), r.y);
849 gPrefs->Write(wxT("/TagsEditorDialog/width"), r.width);
850 gPrefs->Write(wxT("/TagsEditorDialog/height"), r.height);
851 gPrefs->Flush();
852
853 EndModal(wxID_OK);
854}
bool TransferDataFromWindow() override
Definition: TagsEditor.cpp:388

References FileConfig::Flush(), gPrefs, mGrid, mLocal, mTags, TransferDataFromWindow(), and wxT().

Here is the call graph for this function:

◆ OnRemove()

void TagsEditorDialog::OnRemove ( wxCommandEvent &  event)
private

Definition at line 806 of file TagsEditor.cpp.

807{
808 size_t row = mGrid->GetGridCursorRow();
809
810 if (!mEditTitle &&
811 mGrid->GetCellValue(row, 0).CmpNoCase(LABEL_TITLE.Translation()) == 0) {
812 return;
813 }
814 else if (!mEditTrack &&
815 mGrid->GetCellValue(row, 0)
816 .CmpNoCase(LABEL_TRACK.Translation()) == 0) {
817 return;
818 }
819 else if (row < STATICCNT) {
820 mGrid->SetCellValue(row, 1, wxEmptyString);
821 }
822 else if (row >= STATICCNT) {
823 mGrid->DeleteRows(row, 1);
824 }
825}
#define LABEL_TITLE
Definition: TagsEditor.cpp:145
#define STATICCNT
Definition: TagsEditor.cpp:178
#define LABEL_TRACK
Definition: TagsEditor.cpp:147

References LABEL_TITLE, LABEL_TRACK, mEditTitle, mEditTrack, mGrid, and STATICCNT.

◆ OnReset()

void TagsEditorDialog::OnReset ( wxCommandEvent &  event)
private

Definition at line 594 of file TagsEditor.cpp.

595{
596 int id = AudacityMessageBox(
597 XO("Are you sure you want to reset the genre list to defaults?"),
598 XO("Reset Genres"),
599 wxYES_NO);
600
601 if (id == wxNO) {
602 return;
603 }
605
606 wxFileName fn(FileNames::DataDir(), wxT("genres.txt"));
607 wxTextFile tf(fn.GetFullPath());
608
609 bool open = (tf.Exists() && tf.Open()) ||
610 (!tf.Exists() && tf.Create());
611
612 if (!open) {
614 XO("Unable to open genre file."),
615 XO("Reset Genres") );
617 return;
618 }
619
620 tf.Clear();
621 int cnt = mLocal.GetNumUserGenres();
622 for (int i = 0; i < cnt; i++) {
623 tf.AddLine(mLocal.GetUserGenre(i));
624 }
625
626 if (!tf.Write()) {
628 XO("Unable to save genre file."),
629 XO("Reset Genres") );
631 return;
632 }
633
635
637}
void LoadDefaultGenres()
Definition: Tags.cpp:348

References AudacityMessageBox(), FileNames::DataDir(), fn, Tags::GetNumUserGenres(), Tags::GetUserGenre(), Tags::LoadDefaultGenres(), Tags::LoadGenres(), mLocal, PopulateGenres(), wxT(), and XO().

Here is the call graph for this function:

◆ OnSave()

void TagsEditorDialog::OnSave ( wxCommandEvent &  event)
private

Definition at line 701 of file TagsEditor.cpp.

702{
703 wxString fn;
704
705 // Refresh tags
707
708 // Ask the user for the real name
709 fn = SelectFile(FileNames::Operation::_None,
710 XO("Save Metadata As:"),
712 wxT("Tags.xml"),
713 wxT("xml"),
715 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
716 this);
717
718 // User canceled...
719 if (fn.empty()) {
720 return;
721 }
722
723 GuardedCall( [&] {
724 // Create/Open the file
725 XMLFileWriter writer{ fn, XO("Error Saving Tags File") };
726
727 // Remember title and track in case they're read only
728 wxString title = mLocal.GetTag(TAG_TITLE);
729 wxString track = mLocal.GetTag(TAG_TRACK);
730
731 // Clear title
732 if (!mEditTitle) {
733 mLocal.SetTag(TAG_TITLE, wxEmptyString);
734 }
735
736 // Clear track
737 if (!mEditTrack) {
738 mLocal.SetTag(TAG_TRACK, wxEmptyString);
739 }
740
741 auto cleanup = finally( [&] {
742 // Restore title
743 if (!mEditTitle) {
745 }
746
747 // Restore track
748 if (!mEditTrack) {
749 mLocal.SetTag(TAG_TRACK, track);
750 }
751 } );
752
753 // Write the metadata
754 mLocal.WriteXML(writer);
755
756 writer.Commit();
757 } );
758}
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
void WriteXML(XMLWriter &xmlFile) const
Definition: Tags.cpp:549
Wrapper to output XML data to files.
Definition: XMLWriter.h:85

References FileNames::DataDir(), fn, Tags::GetTag(), GuardedCall(), mEditTitle, mEditTrack, mLocal, SelectFile(), Tags::SetTag(), TAG_TITLE, TAG_TRACK, title, TransferDataFromWindow(), Tags::WriteXML(), wxT(), FileNames::XMLFiles, and XO().

Here is the call graph for this function:

◆ OnSaveDefaults()

void TagsEditorDialog::OnSaveDefaults ( wxCommandEvent &  event)
private

Definition at line 760 of file TagsEditor.cpp.

761{
762 // Refresh tags
764
765 // Remember title and track in case they're read only
766 wxString title = mLocal.GetTag(TAG_TITLE);
767 wxString track = mLocal.GetTag(TAG_TRACK);
768
769 // Clear title
770 if (!mEditTitle) {
771 mLocal.SetTag(TAG_TITLE, wxEmptyString);
772 }
773
774 // Clear track
775 if (!mEditTrack) {
776 mLocal.SetTag(TAG_TRACK, wxEmptyString);
777 }
778
779 // Remove any previous defaults
780 gPrefs->DeleteGroup(wxT("/Tags"));
781
782 // Write out each tag
783 for (const auto &pair : mLocal.GetRange()) {
784 const auto &n = pair.first;
785 const auto &v = pair.second;
786 gPrefs->Write(wxT("/Tags/") + n, v);
787 }
788 gPrefs->Flush();
789
790 // Restore title
791 if (!mEditTitle) {
793 }
794
795 // Restore track
796 if (!mEditTrack) {
797 mLocal.SetTag(TAG_TRACK, track);
798 }
799}
virtual bool DeleteGroup(const wxString &key) wxOVERRIDE
Definition: FileConfig.cpp:219
Iterators GetRange() const
Definition: Tags.cpp:436

References FileConfig::DeleteGroup(), FileConfig::Flush(), Tags::GetRange(), Tags::GetTag(), gPrefs, mEditTitle, mEditTrack, mLocal, Tags::SetTag(), TAG_TITLE, TAG_TRACK, title, TransferDataFromWindow(), and wxT().

Here is the call graph for this function:

◆ PopulateGenres()

void TagsEditorDialog::PopulateGenres ( )
private

Definition at line 906 of file TagsEditor.cpp.

907{
908 int cnt = mLocal.GetNumUserGenres();
909 int i;
910 wxString parm;
911 wxArrayString g;
912
913 for (i = 0; i < cnt; i++) {
914 g.push_back(mLocal.GetUserGenre(i));
915 }
916 std::sort( g.begin(), g.end() );
917
918 for (i = 0; i < cnt; i++) {
919 parm = parm + (i == 0 ? wxT("") : wxT(",")) + g[i];
920 }
921
922 // Here was a memory leak! wxWidgets docs for wxGrid::GetDefaultEditorForType() say:
923 // "The caller must call DecRef() on the returned pointer."
924 auto editor = mGrid->GetDefaultEditorForType(wxT("Combo"));
925 editor->SetParameters(parm);
926 editor->DecRef();
927}

References Tags::GetNumUserGenres(), Tags::GetUserGenre(), mGrid, mLocal, and wxT().

Referenced by OnEdit(), and OnReset().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ PopulateOrExchange()

void TagsEditorDialog::PopulateOrExchange ( ShuttleGui S)

Definition at line 285 of file TagsEditor.cpp.

286{
287 bool bShow;
288 gPrefs->Read(wxT("/AudioFiles/ShowId3Dialog"), &bShow, true );
289
290 S.StartVerticalLay();
291 {
292 S.StartHorizontalLay(wxALIGN_LEFT, 0);
293 {
294 S.AddUnits(XO("Use arrow keys (or ENTER key after editing) to navigate fields."));
295 }
296 S.EndHorizontalLay();
297
298 if (mGrid == NULL) {
299 mGrid = safenew Grid(S.GetParent(),
300 wxID_ANY,
301 wxDefaultPosition,
302 wxDefaultSize,
303 wxSUNKEN_BORDER);
304
305 mGrid->RegisterDataType(wxT("Combo"),
306 (mStringRenderer = safenew wxGridCellStringRenderer),
307 (mComboEditor = safenew ComboEditor(wxArrayString(), true)));
308
309 mGrid->SetColLabelSize(mGrid->GetDefaultRowSize());
310
311 auto cs = transform_container<wxArrayStringEx>(
312 names, std::mem_fn( &TranslatableString::Translation ) );
313
314 // Build the initial (empty) grid
315 mGrid->CreateGrid(0, 2, wxGrid::wxGridSelectRows);
316 mGrid->SetRowLabelSize(0);
317 mGrid->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
318 mGrid->SetColLabelValue(0, _("Tag"));
319 mGrid->SetColLabelValue(1, _("Value"));
320
321 // Resize the name column and set default row height.
322 wxComboBox tc(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, cs);
323 mGrid->SetColSize(0, tc.GetSize().x);
324 mGrid->SetColMinimalWidth(0, tc.GetSize().x);
325 }
326 S.Prop(1)
327 .Position(wxEXPAND | wxALL)
328 .AddWindow(mGrid);
329
330 S.StartMultiColumn(4, wxALIGN_CENTER);
331 {
332 S.Id(AddID).AddButton(XXO("&Add"));
333 S.Id(RemoveID).AddButton(XXO("&Remove"));
334 S.AddTitle( {} );
335 S.Id(ClearID).AddButton(XXO("Cl&ear"));
336 }
337 S.EndMultiColumn();
338
339 S.StartHorizontalLay(wxALIGN_CENTRE, 0);
340 {
341 S.StartStatic(XO("Genres"));
342 {
343 S.StartMultiColumn(4, wxALIGN_CENTER);
344 {
345 S.Id(EditID).AddButton(XXO("E&dit..."));
346 S.Id(ResetID).AddButton(XXO("Rese&t..."));
347 }
348 S.EndMultiColumn();
349 }
350 S.EndStatic();
351 S.StartStatic(XO("Template"));
352 {
353 S.StartMultiColumn(4, wxALIGN_CENTER);
354 {
355 S.Id(LoadID).AddButton(XXO("&Load..."));
356 S.Id(SaveID).AddButton(XXO("&Save..."));
357 S.AddTitle( {} );
358 S.Id(SaveDefaultsID).AddButton(XXO("Set De&fault"));
359 }
360 S.EndMultiColumn();
361 }
362 S.EndStatic();
363 }
364 S.EndHorizontalLay();
365 S.StartHorizontalLay(wxALIGN_LEFT, 0);
366 {
367 S.Id( DontShowID ).AddCheckBox( XXO("Don't show this when exporting audio"), !bShow );
368 }
369 S.EndHorizontalLay();
370 }
371 S.EndVerticalLay();
372
373 S.AddStandardButtons(eOkButton | eCancelButton | eHelpButton);
374}
XXO("&Cut/Copy/Paste Toolbar")
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
@ eOkButton
Definition: ShuttleGui.h:597
@ eCancelButton
Definition: ShuttleGui.h:598
@ eHelpButton
Definition: ShuttleGui.h:601
@ SaveDefaultsID
Definition: TagsEditor.cpp:186
@ DontShowID
Definition: TagsEditor.cpp:189
@ ClearID
Definition: TagsEditor.cpp:181
@ RemoveID
Definition: TagsEditor.cpp:188
@ LoadID
Definition: TagsEditor.cpp:184
@ ResetID
Definition: TagsEditor.cpp:183
@ SaveID
Definition: TagsEditor.cpp:185
@ EditID
Definition: TagsEditor.cpp:182
@ AddID
Definition: TagsEditor.cpp:187
static TranslatableStrings names
Definition: TagsEditor.cpp:152
Supplies an accessible grid based on wxGrid.
Definition: Grid.h:185
wxGridCellStringRenderer * mStringRenderer
Definition: TagsEditor.h:86
ComboEditor * mComboEditor
Definition: TagsEditor.h:85
wxString Translation() const

References _, AddID, ClearID, DontShowID, eCancelButton, EditID, eHelpButton, eOkButton, gPrefs, LoadID, mComboEditor, mGrid, mStringRenderer, names, RemoveID, ResetID, S, safenew, SaveDefaultsID, SaveID, TranslatableString::Translation(), wxT(), XO(), and XXO().

Here is the call graph for this function:

◆ SetEditors()

void TagsEditorDialog::SetEditors ( )
private

Definition at line 890 of file TagsEditor.cpp.

891{
892 int cnt = mGrid->GetNumberRows();
893
894 for (int i = 0; i < cnt; i++) {
895 wxString label = mGrid->GetCellValue(i, 0);
896 if (label.CmpNoCase(LABEL_GENRE.Translation()) == 0) {
897 // This use of GetDefaultEditorForType does not require DecRef.
898 mGrid->SetCellEditor(i, 1, mGrid->GetDefaultEditorForType(wxT("Combo")));
899 }
900 else {
901 mGrid->SetCellEditor(i, 1, NULL); //mGrid->GetDefaultEditor());
902 }
903 }
904}
TranslatableString label
Definition: TagsEditor.cpp:164
#define LABEL_GENRE
Definition: TagsEditor.cpp:149

References label, LABEL_GENRE, mGrid, and wxT().

Referenced by TransferDataToWindow().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ShowEditDialog()

bool TagsEditorDialog::ShowEditDialog ( Tags tags,
wxWindow *  parent,
const TranslatableString title,
bool  force = false 
)
static

Definition at line 24 of file TagsEditor.cpp.

25{
26 if (force) {
27 TagsEditorDialog dlg(parent, title, &tags, true, true);
28
29 return dlg.ShowModal() == wxID_OK;
30 }
31
32 return true;
33}
Derived from ExpandingToolBar, this dialog allows editing of Tags.
Definition: TagsEditor.h:20

References title.

Referenced by DoEditMetadata(), ExportMultipleDialog::ExportMultipleByLabel(), and ExportMultipleDialog::ExportMultipleByTrack().

Here is the caller graph for this function:

◆ TransferDataFromWindow()

bool TagsEditorDialog::TransferDataFromWindow ( )
override

Definition at line 388 of file TagsEditor.cpp.

389{
390 int i, cnt = mGrid->GetNumberRows();
391
392 if (mGrid->IsCellEditControlShown()) {
393 mGrid->SaveEditControlValue();
394 mGrid->HideCellEditControl();
395 }
396
397 mLocal.Clear();
398 for (i = 0; i < cnt; i++) {
399 // Get tag name from the grid
400
401 auto n = mGrid->GetCellValue(i, 0);
402 wxString v = mGrid->GetCellValue(i, 1);
403
404 if (n.empty()) {
405 continue;
406 }
407
408 bool bSpecialTag = true;
409
410 // Map special tag names back to internal keys
411 if (n.CmpNoCase(LABEL_ARTIST.Translation()) == 0) {
412 n = TAG_ARTIST;
413 }
414 else if (n.CmpNoCase(LABEL_TITLE.Translation()) == 0) {
415 n = TAG_TITLE;
416 }
417 else if (n.CmpNoCase(LABEL_ALBUM.Translation()) == 0) {
418 n = TAG_ALBUM;
419 }
420 else if (n.CmpNoCase(LABEL_TRACK.Translation()) == 0) {
421 n = TAG_TRACK;
422 }
423 else if (n.CmpNoCase(LABEL_YEAR.Translation()) == 0) {
424 n = TAG_YEAR;
425 }
426 else if (n.CmpNoCase(LABEL_GENRE.Translation()) == 0) {
427 n = TAG_GENRE;
428 }
429 else if (n.CmpNoCase(LABEL_COMMENTS.Translation()) == 0) {
430 n = TAG_COMMENTS;
431 }
432 else {
433 bSpecialTag = false;
434 }
435
436 mLocal.SetTag(n, v, bSpecialTag);
437 }
438
439 return true;
440}
#define TAG_COMMENTS
Definition: Tags.h:64
#define TAG_GENRE
Definition: Tags.h:63
#define TAG_ALBUM
Definition: Tags.h:60
#define TAG_YEAR
Definition: Tags.h:62
#define TAG_ARTIST
Definition: Tags.h:59
#define LABEL_COMMENTS
Definition: TagsEditor.cpp:150
#define LABEL_YEAR
Definition: TagsEditor.cpp:148
#define LABEL_ARTIST
Definition: TagsEditor.cpp:144
#define LABEL_ALBUM
Definition: TagsEditor.cpp:146

References Tags::Clear(), LABEL_ALBUM, LABEL_ARTIST, LABEL_COMMENTS, LABEL_GENRE, LABEL_TITLE, LABEL_TRACK, LABEL_YEAR, mGrid, mLocal, Tags::SetTag(), TAG_ALBUM, TAG_ARTIST, TAG_COMMENTS, TAG_GENRE, TAG_TITLE, TAG_TRACK, and TAG_YEAR.

Referenced by OnOk(), OnSave(), and OnSaveDefaults().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TransferDataToWindow()

bool TagsEditorDialog::TransferDataToWindow ( )
override

Definition at line 442 of file TagsEditor.cpp.

443{
444 size_t i;
445 TagMap popTagMap;
446
447 // Disable redrawing until we're done
448 mGrid->BeginBatch();
449
450 // Delete all rows
451 if (mGrid->GetNumberRows()) {
452 mGrid->DeleteRows(0, mGrid->GetNumberRows());
453 }
454
455 // Populate the static rows
456 for (i = 0; i < STATICCNT; i++) {
457 mGrid->AppendRows();
458
459 mGrid->SetReadOnly(i, 0);
460 // The special tag name that's displayed and translated may not match
461 // the key string used for internal lookup.
462 mGrid->SetCellValue(i, 0, labelmap[i].label.Translation() );
463 mGrid->SetCellValue(i, 1, mLocal.GetTag(labelmap[i].name));
464
465 if (!mEditTitle &&
466 mGrid->GetCellValue(i, 0).CmpNoCase(LABEL_TITLE.Translation()) == 0) {
467 mGrid->SetReadOnly(i, 1);
468 }
469
470 if (!mEditTrack &&
471 mGrid->GetCellValue(i, 0).CmpNoCase(LABEL_TRACK.Translation()) == 0) {
472 mGrid->SetReadOnly(i, 1);
473 }
474
475 popTagMap[ labelmap[i].name ] = mGrid->GetCellValue(i, 1);
476 }
477
478 // Populate the rest
479 for (const auto &pair : mLocal.GetRange()) {
480 const auto &n = pair.first;
481 const auto &v = pair.second;
482 if (popTagMap.find(n) == popTagMap.end()) {
483 mGrid->AppendRows();
484 mGrid->SetCellValue(i, 0, n);
485 mGrid->SetCellValue(i, 1, v);
486 i++;
487 }
488 }
489
490 // Add an extra one to help with initial sizing and to show it can be done
491 mGrid->AppendRows(1);
492
493 // We're done, so allow the grid to redraw
494 mGrid->EndBatch();
495
496 // Set the editors
497 SetEditors();
498 Layout();
499 Fit();
500
501 return true;
502}
std::unordered_map< wxString, wxString > TagMap
Definition: Tags.h:56
static const struct @81 labelmap[]

References Tags::GetRange(), Tags::GetTag(), label, LABEL_TITLE, LABEL_TRACK, labelmap, mEditTitle, mEditTrack, mGrid, mLocal, SetEditors(), STATICCNT, and TranslatableString::Translation().

Referenced by OnClear(), and OnLoad().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mComboEditor

ComboEditor* TagsEditorDialog::mComboEditor
private

Definition at line 85 of file TagsEditor.h.

Referenced by PopulateOrExchange().

◆ mEditTitle

bool TagsEditorDialog::mEditTitle
private

Definition at line 79 of file TagsEditor.h.

Referenced by OnLoad(), OnRemove(), OnSave(), OnSaveDefaults(), and TransferDataToWindow().

◆ mEditTrack

bool TagsEditorDialog::mEditTrack
private

Definition at line 80 of file TagsEditor.h.

Referenced by OnLoad(), OnRemove(), OnSave(), OnSaveDefaults(), and TransferDataToWindow().

◆ mGrid

Grid* TagsEditorDialog::mGrid
private

◆ mLocal

Tags TagsEditorDialog::mLocal
private

◆ mStringRenderer

wxGridCellStringRenderer* TagsEditorDialog::mStringRenderer
private

Definition at line 86 of file TagsEditor.h.

Referenced by PopulateOrExchange().

◆ mTags

Tags* TagsEditorDialog::mTags
private

Definition at line 78 of file TagsEditor.h.

Referenced by OnOk().


The documentation for this class was generated from the following files: