Audacity  2.2.2
Public Member Functions | Private Member Functions | Private Attributes | List of all members
TagsEditor Class Referencefinal

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

#include <Tags.h>

Inheritance diagram for TagsEditor:
wxDialogWrapper wxTabTraversalWrapper< wxDialog >

Public Member Functions

 TagsEditor (wxWindow *parent, const wxString &title, Tags *tags, bool editTitle, bool editTrackNumber)
 
virtual ~TagsEditor ()
 
bool IsEscapeKey (const wxKeyEvent &) override
 
void PopulateOrExchange (ShuttleGui &S)
 
bool TransferDataToWindow () override
 
bool TransferDataFromWindow () override
 
- Public Member Functions inherited from wxDialogWrapper
 wxDialogWrapper ()
 
 wxDialogWrapper (wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE, const wxString &name=_("Dialog"))
 
bool Create (wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE, const wxString &name=_("Dialog"))
 
- Public Member Functions inherited from wxTabTraversalWrapper< wxDialog >
 wxTabTraversalWrapper (Args &&...args)
 
 wxTabTraversalWrapper (const wxTabTraversalWrapper &)=delete
 
 wxTabTraversalWrapper (wxTabTraversalWrapper &&)=delete
 
wxTabTraversalWrapperoperator= (const wxTabTraversalWrapper &)=delete
 
wxTabTraversalWrapperoperator= (wxTabTraversalWrapper &&)=delete
 

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 129 of file Tags.h.

Constructor & Destructor Documentation

TagsEditor::TagsEditor ( wxWindow *  parent,
const wxString &  title,
Tags tags,
bool  editTitle,
bool  editTrackNumber 
)

Definition at line 775 of file Tags.cpp.

References eIsCreating, and gPrefs.

780 : wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize,
781  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
782  mTags(tags),
783  mEditTitle(editTitle),
784  mEditTrack(editTrack)
785 {
786  SetName(GetTitle());
787 
788  mGrid = NULL;
789 
790  // Make a local copy of the passed in tags
791  mLocal = *mTags;
792 
793  // Build, size, and position the dialog
794  ShuttleGui S(this, eIsCreating);
796 
798 
799  Layout();
800  Fit();
801  Center();
802  SetSizeHints(GetSize());
803 
804  // Restore the original tags because TransferDataToWindow() will be called again
805  mLocal.Clear();
806  mLocal = *mTags;
807 
808  // Override size and position with last saved
809  wxRect r = GetRect();
810  gPrefs->Read(wxT("/TagsEditor/x"), &r.x, r.x);
811  gPrefs->Read(wxT("/TagsEditor/y"), &r.y, r.y);
812  gPrefs->Read(wxT("/TagsEditor/width"), &r.width, r.width);
813  gPrefs->Read(wxT("/TagsEditor/height"), &r.height, r.height);
814  //On multi-monitor systems, there's a chance the last saved window position is
815  //on a monitor that has been removed or is unavailable.
816  if (IsWindowRectValid(&r))
817  Move(r.GetPosition());
818 
819  SetSize(r.GetSize());
820  Layout();
821 
822  // Resize value column width based on width of columns and the vertical scrollbar
823  wxScrollBar sb(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
824  r = mGrid->GetClientRect();
825  r.width -= mGrid->GetColSize(0);
826  r.width -= sb.GetSize().GetWidth();
827  r.width -= 10;
828  r.width -= r.x;
829  mGrid->SetColSize(1, r.width);
830 
831  // Load the genres
832  PopulateGenres();
833 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
void PopulateGenres()
Definition: Tags.cpp:1425
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
bool TransferDataToWindow() override
Definition: Tags.cpp:978
bool IsWindowRectValid(const wxRect *windowRect) const
Definition: Tags.cpp:1447
void Clear()
Definition: Tags.cpp:300
bool mEditTitle
Definition: Tags.h:178
Tags mLocal
Definition: Tags.h:181
Grid * mGrid
Definition: Tags.h:183
bool mEditTrack
Definition: Tags.h:179
void PopulateOrExchange(ShuttleGui &S)
Definition: Tags.cpp:848
Tags * mTags
Definition: Tags.h:177
TagsEditor::~TagsEditor ( )
virtual

Definition at line 835 of file Tags.cpp.

836 {
837  // This DELETE is not needed because wxWidgets owns the grid.
838 // DELETE mGrid;
839 
840 // TODO: Need to figure out if these should be deleted. Looks like the wxGrid
841 // code takes ownership and uses reference counting, but there's been
842 // cases where they show up as memory leaks.
843 // PRL: Fixed the leaks, see commit c87eb0804bc5f40659b133cab6e2ade061959645
844 // DELETE mStringRenderer;
845 // DELETE mComboEditor;
846 }

Member Function Documentation

void TagsEditor::DoCancel ( bool  escKey)
private

Definition at line 1380 of file Tags.cpp.

References mGrid.

Referenced by OnCancel(), and OnKeyDown().

1381 {
1382  if (mGrid->IsCellEditControlShown()) {
1383  auto editor = mGrid->GetCellEditor(mGrid->GetGridCursorRow(),
1384  mGrid->GetGridCursorCol());
1385  editor->Reset();
1386  // To avoid memory leak, don't forget DecRef()!
1387  editor->DecRef();
1388  mGrid->HideCellEditControl();
1389 #if defined(__WXMSW__)
1390  return;
1391 #endif
1392  }
1393 
1394  auto focus = wxWindow::FindFocus();
1395  if (escKey && focus == mGrid)
1396  return;
1397 
1398  EndModal(wxID_CANCEL);
1399 }
Grid * mGrid
Definition: Tags.h:183
bool TagsEditor::IsEscapeKey ( const wxKeyEvent &  )
inlineoverride

Definition at line 142 of file Tags.h.

142 { return false; }
bool TagsEditor::IsWindowRectValid ( const wxRect *  windowRect) const
private

Definition at line 1447 of file Tags.cpp.

1448 {
1449  wxDisplay display;
1450  wxPoint topLeft(windowRect->GetTopLeft().x, windowRect->GetTopLeft().y);
1451  wxPoint topRight(windowRect->GetTopRight().x, windowRect->GetTopRight().y);
1452  wxPoint bottomLeft(windowRect->GetBottomLeft().x, windowRect->GetBottomLeft().y);
1453  wxPoint bottomRight(windowRect->GetBottomRight().x, windowRect->GetBottomRight().y);
1454  display.GetFromPoint(topLeft);
1455  if (display.GetFromPoint(topLeft) == -1 &&
1456  display.GetFromPoint(topRight) == -1 &&
1457  display.GetFromPoint(bottomLeft) == -1 &&
1458  display.GetFromPoint(bottomRight) == -1) {
1459  return false;
1460  }
1461 
1462  return true;
1463 }
void TagsEditor::OnAdd ( wxCommandEvent &  event)
private

Definition at line 1326 of file Tags.cpp.

References mGrid.

1327 {
1328  mGrid->AppendRows();
1329 }
Grid * mGrid
Definition: Tags.h:183
void TagsEditor::OnCancel ( wxCommandEvent &  event)
private

Definition at line 1375 of file Tags.cpp.

References DoCancel().

1376 {
1377  DoCancel(false);
1378 }
void DoCancel(bool escKey)
Definition: Tags.cpp:1380
void TagsEditor::OnChange ( wxGridEvent &  event)
private

Definition at line 1040 of file Tags.cpp.

References mGrid.

1041 {
1042  static bool ischanging = false;
1043 
1044  // Prevent recursion
1045  if (ischanging) {
1046  return;
1047  }
1048 
1049  event.Skip();
1050 
1051  if (event.GetCol() != 0) {
1052  return;
1053  }
1054 
1055  // Do not permit duplication of any of the tags.
1056  // Tags differing only in case are nondistinct.
1057  auto row = event.GetRow();
1058  const wxString key0 = mGrid->GetCellValue(row, 0).Upper();
1059  auto nn = mGrid->GetNumberRows();
1060  for (decltype(nn) ii = 0; ii < nn; ++ii) {
1061  if (ii == row)
1062  continue;
1063  auto key = mGrid->GetCellValue(ii, 0).Upper();
1064  if (key0.CmpNoCase(key) == 0) {
1065  ischanging = true;
1066  wxBell();
1067  mGrid->SetGridCursor(ii, 0);
1068  event.Veto();
1069  ischanging = false;
1070  break;
1071  }
1072  }
1073 
1074  return;
1075 }
Grid * mGrid
Definition: Tags.h:183
void TagsEditor::OnClear ( wxCommandEvent &  event)
private

Definition at line 1167 of file Tags.cpp.

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

1168 {
1169  mLocal.Clear();
1170 
1172 }
bool TransferDataToWindow() override
Definition: Tags.cpp:978
void Clear()
Definition: Tags.cpp:300
Tags mLocal
Definition: Tags.h:181
void TagsEditor::OnEdit ( wxCommandEvent &  event)
private

Definition at line 1077 of file Tags.cpp.

References _(), ShuttleGui::AddStandardButtons(), ShuttleGuiBase::AddTextWindow(), AudacityMessageBox(), FileNames::DataDir(), eIsCreating, ShuttleGuiBase::EndVerticalLay(), Tags::GetNumUserGenres(), Tags::GetUserGenre(), Tags::LoadGenres(), mGrid, mLocal, PopulateGenres(), and ShuttleGuiBase::StartVerticalLay().

1078 {
1079  if (mGrid->IsCellEditControlShown()) {
1080  mGrid->SaveEditControlValue();
1081  mGrid->HideCellEditControl();
1082  }
1083 
1084  wxDialogWrapper dlg(this, wxID_ANY, _("Edit Genres"),
1085  wxDefaultPosition, wxDefaultSize,
1086  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
1087  dlg.SetName(dlg.GetTitle());
1088  wxTextCtrl *tc;
1089 
1090  ShuttleGui S(&dlg, eIsCreating);
1091 
1092  S.StartVerticalLay(true);
1093  {
1094  tc = S.AddTextWindow(wxT(""));
1095  }
1096  S.EndVerticalLay();
1097 
1098  S.AddStandardButtons();
1099 
1100  wxSortedArrayString g;
1101  int cnt = mLocal.GetNumUserGenres();
1102  for (int i = 0; i < cnt; i++) {
1103  g.Add(mLocal.GetUserGenre(i));
1104  }
1105 
1106  for (int i = 0; i < cnt; i++) {
1107  tc->AppendText(g[i] + wxT("\n"));
1108  }
1109 
1110  dlg.Center();
1111  if (dlg.ShowModal() == wxID_CANCEL) {
1112  return;
1113  }
1114 
1115  wxFileName fn(FileNames::DataDir(), wxT("genres.txt"));
1116  wxFile f(fn.GetFullPath(), wxFile::write);
1117  if (!f.IsOpened() || !f.Write(tc->GetValue())) {
1118  AudacityMessageBox(_("Unable to save genre file."), _("Reset Genres"));
1119  return;
1120  }
1121 
1122  mLocal.LoadGenres();
1123 
1124  PopulateGenres();
1125 }
void PopulateGenres()
Definition: Tags.cpp:1425
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
void LoadGenres()
Definition: Tags.cpp:364
wxString GetUserGenre(int value)
Definition: Tags.cpp:382
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
int GetNumUserGenres()
Definition: Tags.cpp:351
Tags mLocal
Definition: Tags.h:181
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
Grid * mGrid
Definition: Tags.h:183
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
void TagsEditor::OnKeyDown ( wxKeyEvent &  event)
private

Definition at line 1401 of file Tags.cpp.

References DoCancel().

1402 {
1403  if (event.GetKeyCode() == WXK_ESCAPE)
1404  DoCancel(true);
1405  else
1406  event.Skip();
1407 }
void DoCancel(bool escKey)
Definition: Tags.cpp:1380
void TagsEditor::OnLoad ( wxCommandEvent &  event)
private

Definition at line 1174 of file Tags.cpp.

References _(), FileNames::_None, AudacityMessageBox(), Tags::Clear(), FileNames::DataDir(), XMLFileReader::GetErrorStr(), Tags::GetTag(), mEditTitle, mEditTrack, mLocal, XMLFileReader::Parse(), FileNames::SelectFile(), Tags::SetTag(), TAG_TITLE, TAG_TRACK, and TransferDataToWindow().

1175 {
1176  wxString fn;
1177 
1178  // Ask the user for the real name
1180  _("Load Metadata As:"),
1182  wxT("Tags.xml"),
1183  wxT("xml"),
1184  wxT("*.xml"),
1185  wxFD_OPEN | wxRESIZE_BORDER,
1186  this);
1187 
1188  // User canceled...
1189  if (fn.IsEmpty()) {
1190  return;
1191  }
1192 
1193  // Remember title and track in case they're read only
1194  wxString title = mLocal.GetTag(TAG_TITLE);
1195  wxString track = mLocal.GetTag(TAG_TRACK);
1196 
1197  // Clear current contents
1198  mLocal.Clear();
1199 
1200  // Load the metadata
1201  XMLFileReader reader;
1202  if (!reader.Parse(&mLocal, fn)) {
1203  // Inform user of load failure
1205  _("Error Loading Metadata"),
1206  wxOK | wxCENTRE,
1207  this);
1208  }
1209 
1210  // Restore title
1211  if (!mEditTitle) {
1212  mLocal.SetTag(TAG_TITLE, title);
1213  }
1214 
1215  // Restore track
1216  if (!mEditTrack) {
1217  mLocal.SetTag(TAG_TRACK, track);
1218  }
1219 
1220  // Go fill up the window
1222 
1223  return;
1224 }
void SetTag(const wxString &name, const wxString &value)
Definition: Tags.cpp:449
#define TAG_TRACK
Definition: Tags.h:63
#define TAG_TITLE
Definition: Tags.h:60
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
bool TransferDataToWindow() override
Definition: Tags.cpp:978
bool Parse(XMLTagHandler *baseHandler, const wxString &fname)
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:18
void Clear()
Definition: Tags.cpp:300
bool mEditTitle
Definition: Tags.h:178
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:424
Tags mLocal
Definition: Tags.h:181
static wxString SelectFile(Operation op, const wxString &message, const wxString &default_path, const wxString &default_filename, const wxString &default_extension, const wxString &wildcard, int flags, wxWindow *parent)
Definition: FileNames.cpp:411
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
bool mEditTrack
Definition: Tags.h:179
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
wxString GetErrorStr()
void TagsEditor::OnOk ( wxCommandEvent &  event)
private

Definition at line 1352 of file Tags.cpp.

References gPrefs, mGrid, mLocal, mTags, and TransferDataFromWindow().

1353 {
1354  if (mGrid->IsCellEditControlShown()) {
1355  mGrid->SaveEditControlValue();
1356  mGrid->HideCellEditControl();
1357  }
1358 
1359  if (!Validate() || !TransferDataFromWindow()) {
1360  return;
1361  }
1362 
1363  *mTags = mLocal;
1364 
1365  wxRect r = GetRect();
1366  gPrefs->Write(wxT("/TagsEditor/x"), r.x);
1367  gPrefs->Write(wxT("/TagsEditor/y"), r.y);
1368  gPrefs->Write(wxT("/TagsEditor/width"), r.width);
1369  gPrefs->Write(wxT("/TagsEditor/height"), r.height);
1370  gPrefs->Flush();
1371 
1372  EndModal(wxID_OK);
1373 }
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
bool TransferDataFromWindow() override
Definition: Tags.cpp:929
Tags mLocal
Definition: Tags.h:181
Grid * mGrid
Definition: Tags.h:183
Tags * mTags
Definition: Tags.h:177
void TagsEditor::OnRemove ( wxCommandEvent &  event)
private

Definition at line 1331 of file Tags.cpp.

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

1332 {
1333  size_t row = mGrid->GetGridCursorRow();
1334 
1335  if (!mEditTitle &&
1336  mGrid->GetCellValue(row, 0).CmpNoCase(wxGetTranslation(LABEL_TITLE)) == 0) {
1337  return;
1338  }
1339  else if (!mEditTrack &&
1340  mGrid->GetCellValue(row, 0)
1341  .CmpNoCase(wxGetTranslation(LABEL_TRACK)) == 0) {
1342  return;
1343  }
1344  else if (row < STATICCNT) {
1345  mGrid->SetCellValue(row, 1, wxEmptyString);
1346  }
1347  else if (row >= STATICCNT) {
1348  mGrid->DeleteRows(row, 1);
1349  }
1350 }
#define LABEL_TRACK
Definition: Tags.cpp:698
#define LABEL_TITLE
Definition: Tags.cpp:696
bool mEditTitle
Definition: Tags.h:178
#define STATICCNT
Definition: Tags.cpp:747
Grid * mGrid
Definition: Tags.h:183
bool mEditTrack
Definition: Tags.h:179
void TagsEditor::OnReset ( wxCommandEvent &  event)
private

Definition at line 1127 of file Tags.cpp.

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

1128 {
1129  int id = AudacityMessageBox(_("Are you sure you want to reset the genre list to defaults?"),
1130  _("Reset Genres"),
1131  wxYES_NO);
1132 
1133  if (id == wxNO) {
1134  return;
1135  }
1137 
1138  wxFileName fn(FileNames::DataDir(), wxT("genres.txt"));
1139  wxTextFile tf(fn.GetFullPath());
1140 
1141  bool open = (tf.Exists() && tf.Open()) ||
1142  (!tf.Exists() && tf.Create());
1143 
1144  if (!open) {
1145  AudacityMessageBox(_("Unable to open genre file."), _("Reset Genres"));
1146  mLocal.LoadGenres();
1147  return;
1148  }
1149 
1150  tf.Clear();
1151  int cnt = mLocal.GetNumUserGenres();
1152  for (int i = 0; i < cnt; i++) {
1153  tf.AddLine(mLocal.GetUserGenre(i));
1154  }
1155 
1156  if (!tf.Write()) {
1157  AudacityMessageBox(_("Unable to save genre file."), _("Reset Genres"));
1158  mLocal.LoadGenres();
1159  return;
1160  }
1161 
1162  mLocal.LoadGenres();
1163 
1164  PopulateGenres();
1165 }
void PopulateGenres()
Definition: Tags.cpp:1425
void LoadDefaultGenres()
Definition: Tags.cpp:356
void LoadGenres()
Definition: Tags.cpp:364
wxString GetUserGenre(int value)
Definition: Tags.cpp:382
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
int GetNumUserGenres()
Definition: Tags.cpp:351
Tags mLocal
Definition: Tags.h:181
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
void TagsEditor::OnSave ( wxCommandEvent &  event)
private

Definition at line 1226 of file Tags.cpp.

References _(), FileNames::_None, FileNames::DataDir(), Tags::GetTag(), GuardedCall(), mEditTitle, mEditTrack, mLocal, FileNames::SelectFile(), Tags::SetTag(), TAG_TITLE, TAG_TRACK, TransferDataFromWindow(), and Tags::WriteXML().

1227 {
1228  wxString fn;
1229 
1230  // Refresh tags
1232 
1233  // Ask the user for the real name
1235  _("Save Metadata As:"),
1237  wxT("Tags.xml"),
1238  wxT("xml"),
1239  wxT("*.xml"),
1240  wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
1241  this);
1242 
1243  // User canceled...
1244  if (fn.IsEmpty()) {
1245  return;
1246  }
1247 
1248  GuardedCall( [&] {
1249  // Create/Open the file
1250  XMLFileWriter writer{ fn, _("Error Saving Tags File") };
1251 
1252  // Remember title and track in case they're read only
1253  wxString title = mLocal.GetTag(TAG_TITLE);
1254  wxString track = mLocal.GetTag(TAG_TRACK);
1255 
1256  // Clear title
1257  if (!mEditTitle) {
1258  mLocal.SetTag(TAG_TITLE, wxEmptyString);
1259  }
1260 
1261  // Clear track
1262  if (!mEditTrack) {
1263  mLocal.SetTag(TAG_TRACK, wxEmptyString);
1264  }
1265 
1266  auto cleanup = finally( [&] {
1267  // Restore title
1268  if (!mEditTitle) {
1269  mLocal.SetTag(TAG_TITLE, title);
1270  }
1271 
1272  // Restore track
1273  if (!mEditTrack) {
1274  mLocal.SetTag(TAG_TRACK, track);
1275  }
1276  } );
1277 
1278  // Write the metadata
1279  mLocal.WriteXML(writer);
1280 
1281  writer.Commit();
1282  } );
1283 }
void SetTag(const wxString &name, const wxString &value)
Definition: Tags.cpp:449
#define TAG_TRACK
Definition: Tags.h:63
#define TAG_TITLE
Definition: Tags.h:60
Wrapper to output XML data to files.
Definition: XMLWriter.h:74
bool TransferDataFromWindow() override
Definition: Tags.cpp:929
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), const F3 &delayedHandler={})
bool mEditTitle
Definition: Tags.h:178
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:424
Tags mLocal
Definition: Tags.h:181
static wxString SelectFile(Operation op, const wxString &message, const wxString &default_path, const wxString &default_filename, const wxString &default_extension, const wxString &wildcard, int flags, wxWindow *parent)
Definition: FileNames.cpp:411
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
bool mEditTrack
Definition: Tags.h:179
static wxString DataDir()
Audacity user data directory.
Definition: FileNames.cpp:130
void WriteXML(XMLWriter &xmlFile) const
Definition: Tags.cpp:559
void TagsEditor::OnSaveDefaults ( wxCommandEvent &  event)
private

Definition at line 1285 of file Tags.cpp.

References Tags::GetRange(), Tags::GetTag(), gPrefs, mEditTitle, mEditTrack, mLocal, Tags::SetTag(), TAG_TITLE, TAG_TRACK, and TransferDataFromWindow().

1286 {
1287  // Refresh tags
1289 
1290  // Remember title and track in case they're read only
1291  wxString title = mLocal.GetTag(TAG_TITLE);
1292  wxString track = mLocal.GetTag(TAG_TRACK);
1293 
1294  // Clear title
1295  if (!mEditTitle) {
1296  mLocal.SetTag(TAG_TITLE, wxEmptyString);
1297  }
1298 
1299  // Clear track
1300  if (!mEditTrack) {
1301  mLocal.SetTag(TAG_TRACK, wxEmptyString);
1302  }
1303 
1304  // Remove any previous defaults
1305  gPrefs->DeleteGroup(wxT("/Tags"));
1306 
1307  // Write out each tag
1308  for (const auto &pair : mLocal.GetRange()) {
1309  const auto &n = pair.first;
1310  const auto &v = pair.second;
1311  gPrefs->Write(wxT("/Tags/") + n, v);
1312  }
1313  gPrefs->Flush();
1314 
1315  // Restore title
1316  if (!mEditTitle) {
1317  mLocal.SetTag(TAG_TITLE, title);
1318  }
1319 
1320  // Restore track
1321  if (!mEditTrack) {
1322  mLocal.SetTag(TAG_TRACK, track);
1323  }
1324 }
void SetTag(const wxString &name, const wxString &value)
Definition: Tags.cpp:449
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
#define TAG_TRACK
Definition: Tags.h:63
#define TAG_TITLE
Definition: Tags.h:60
bool TransferDataFromWindow() override
Definition: Tags.cpp:929
bool mEditTitle
Definition: Tags.h:178
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:424
Tags mLocal
Definition: Tags.h:181
bool mEditTrack
Definition: Tags.h:179
Iterators GetRange() const
Definition: Tags.cpp:444
void TagsEditor::PopulateGenres ( )
private

Definition at line 1425 of file Tags.cpp.

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

Referenced by OnEdit(), and OnReset().

1426 {
1427  int cnt = mLocal.GetNumUserGenres();
1428  int i;
1429  wxString parm;
1430  wxSortedArrayString g;
1431 
1432  for (i = 0; i < cnt; i++) {
1433  g.Add(mLocal.GetUserGenre(i));
1434  }
1435 
1436  for (i = 0; i < cnt; i++) {
1437  parm = parm + (i == 0 ? wxT("") : wxT(",")) + g[i];
1438  }
1439 
1440  // Here was a memory leak! wxWidgets docs for wxGrid::GetDefaultEditorForType() say:
1441  // "The caller must call DecRef() on the returned pointer."
1442  auto editor = mGrid->GetDefaultEditorForType(wxT("Combo"));
1443  editor->SetParameters(parm);
1444  editor->DecRef();
1445 }
wxString GetUserGenre(int value)
Definition: Tags.cpp:382
int GetNumUserGenres()
Definition: Tags.cpp:351
Tags mLocal
Definition: Tags.h:181
Grid * mGrid
Definition: Tags.h:183
void TagsEditor::PopulateOrExchange ( ShuttleGui S)

Definition at line 848 of file Tags.cpp.

References _(), ShuttleGuiBase::AddButton(), AddID, ShuttleGui::AddStandardButtons(), ShuttleGuiBase::AddTitle(), ShuttleGuiBase::AddUnits(), ShuttleGuiBase::AddWindow(), ClearID, eCancelButton, EditID, ShuttleGuiBase::EndHorizontalLay(), ShuttleGuiBase::EndMultiColumn(), ShuttleGuiBase::EndStatic(), ShuttleGuiBase::EndVerticalLay(), eOkButton, ShuttleGuiBase::GetParent(), ShuttleGui::Id(), LoadID, mComboEditor, mGrid, mStringRenderer, names(), ShuttleGui::Prop(), RemoveID, ResetID, safenew, SaveDefaultsID, SaveID, ShuttleGuiBase::StartHorizontalLay(), ShuttleGuiBase::StartMultiColumn(), ShuttleGuiBase::StartStatic(), and ShuttleGuiBase::StartVerticalLay().

849 {
850  S.StartVerticalLay();
851  {
852  S.StartHorizontalLay(wxALIGN_LEFT, false);
853  {
854  S.AddUnits(_("Use arrow keys (or ENTER key after editing) to navigate fields."));
855  }
856  S.EndHorizontalLay();
857 
858  if (mGrid == NULL) {
859  mGrid = safenew Grid(S.GetParent(),
860  wxID_ANY,
861  wxDefaultPosition,
862  wxDefaultSize,
863  wxSUNKEN_BORDER);
864 
865  mGrid->RegisterDataType(wxT("Combo"),
866  (mStringRenderer = safenew wxGridCellStringRenderer),
867  (mComboEditor = safenew ComboEditor(wxArrayString(), true)));
868 
869  mGrid->SetColLabelSize(mGrid->GetDefaultRowSize());
870 
871  wxArrayString cs(names());
872 
873  // Build the initial (empty) grid
874  mGrid->CreateGrid(0, 2);
875  mGrid->SetRowLabelSize(0);
876  mGrid->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
877  mGrid->SetColLabelValue(0, _("Tag"));
878  mGrid->SetColLabelValue(1, _("Value"));
879 
880  // Resize the name column and set default row height.
881  wxComboBox tc(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, cs);
882  mGrid->SetColSize(0, tc.GetSize().x);
883  mGrid->SetColMinimalWidth(0, tc.GetSize().x);
884  }
885  S.Prop(true);
886  S.AddWindow(mGrid, wxEXPAND | wxALL);
887 
888  S.StartMultiColumn(4, wxALIGN_CENTER);
889  {
890  S.Id(AddID).AddButton(_("&Add"));
891  S.Id(RemoveID).AddButton(_("&Remove"));
892  S.AddTitle( {} );
893  S.Id(ClearID).AddButton(_("Cl&ear"));
894  }
895  S.EndMultiColumn();
896 
897  S.StartHorizontalLay(wxALIGN_CENTRE, false);
898  {
899  S.StartStatic(_("Genres"));
900  {
901  S.StartMultiColumn(4, wxALIGN_CENTER);
902  {
903  S.Id(EditID).AddButton(_("E&dit..."));
904  S.Id(ResetID).AddButton(_("Rese&t..."));
905  }
906  S.EndMultiColumn();
907  }
908  S.EndStatic();
909  S.StartStatic(_("Template"));
910  {
911  S.StartMultiColumn(4, wxALIGN_CENTER);
912  {
913  S.Id(LoadID).AddButton(_("&Load..."));
914  S.Id(SaveID).AddButton(_("&Save..."));
915  S.AddTitle( {} );
916  S.Id(SaveDefaultsID).AddButton(_("Set De&fault"));
917  }
918  S.EndMultiColumn();
919  }
920  S.EndStatic();
921  }
922  S.EndHorizontalLay();
923  }
924  S.EndVerticalLay();
925 
927 }
ComboEditor * mComboEditor
Definition: Tags.h:184
static wxArrayString names()
Definition: Tags.cpp:703
Definition: Tags.cpp:756
wxWindow * AddWindow(wxWindow *pWindow, int Flags=wxALIGN_CENTRE|wxALL)
Definition: ShuttleGui.cpp:288
void EndMultiColumn()
Definition: Tags.cpp:754
#define safenew
Definition: Audacity.h:230
void EndHorizontalLay()
void AddUnits(const wxString &Prompt)
Left aligned text string.
Definition: ShuttleGui.cpp:260
void EndVerticalLay()
wxWindow * GetParent()
Definition: ShuttleGui.h:294
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
void StartMultiColumn(int nCols, int PositionFlags=wxALIGN_LEFT)
ShuttleGui & Id(int id)
void AddTitle(const wxString &Prompt)
Centred text string.
Definition: ShuttleGui.cpp:274
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
Grid * mGrid
Definition: Tags.h:183
Definition: Tags.cpp:753
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:763
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:418
wxGridCellStringRenderer * mStringRenderer
Definition: Tags.h:185
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
Supplies an accessible grid based on wxGrid.
Definition: Grid.h:193
Definition: Tags.cpp:751
wxButton * AddButton(const wxString &Text, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:341
void StartVerticalLay(int iProp=1)
void TagsEditor::SetEditors ( )
private

Definition at line 1409 of file Tags.cpp.

References label, LABEL_GENRE, and mGrid.

Referenced by TransferDataToWindow().

1410 {
1411  int cnt = mGrid->GetNumberRows();
1412 
1413  for (int i = 0; i < cnt; i++) {
1414  wxString label = mGrid->GetCellValue(i, 0);
1415  if (label.CmpNoCase(wxGetTranslation(LABEL_GENRE)) == 0) {
1416  // This use of GetDefaultEditorForType does not require DecRef.
1417  mGrid->SetCellEditor(i, 1, mGrid->GetDefaultEditorForType(wxT("Combo")));
1418  }
1419  else {
1420  mGrid->SetCellEditor(i, 1, NULL); //mGrid->GetDefaultEditor());
1421  }
1422  }
1423 }
wxString label
Definition: Tags.cpp:733
Grid * mGrid
Definition: Tags.h:183
#define LABEL_GENRE
Definition: Tags.cpp:700
bool TagsEditor::TransferDataFromWindow ( )
override

Definition at line 929 of file Tags.cpp.

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().

930 {
931  int i, cnt = mGrid->GetNumberRows();
932 
933  if (mGrid->IsCellEditControlShown()) {
934  mGrid->SaveEditControlValue();
935  mGrid->HideCellEditControl();
936  }
937 
938  mLocal.Clear();
939  for (i = 0; i < cnt; i++) {
940  // Get tag name from the grid
941 
942  wxString n = mGrid->GetCellValue(i, 0);
943  wxString v = mGrid->GetCellValue(i, 1);
944 
945  if (n.IsEmpty()) {
946  continue;
947  }
948 
949  // Map special tag names back to internal keys
950  if (n.CmpNoCase(wxGetTranslation(LABEL_ARTIST)) == 0) {
951  n = TAG_ARTIST;
952  }
953  else if (n.CmpNoCase(wxGetTranslation(LABEL_TITLE)) == 0) {
954  n = TAG_TITLE;
955  }
956  else if (n.CmpNoCase(wxGetTranslation(LABEL_ALBUM)) == 0) {
957  n = TAG_ALBUM;
958  }
959  else if (n.CmpNoCase(wxGetTranslation(LABEL_TRACK)) == 0) {
960  n = TAG_TRACK;
961  }
962  else if (n.CmpNoCase(wxGetTranslation(LABEL_YEAR)) == 0) {
963  n = TAG_YEAR;
964  }
965  else if (n.CmpNoCase(wxGetTranslation(LABEL_GENRE)) == 0) {
966  n = TAG_GENRE;
967  }
968  else if (n.CmpNoCase(wxGetTranslation(LABEL_COMMENTS)) == 0) {
969  n = TAG_COMMENTS;
970  }
971 
972  mLocal.SetTag(n, v);
973  }
974 
975  return true;
976 }
void SetTag(const wxString &name, const wxString &value)
Definition: Tags.cpp:449
#define TAG_TRACK
Definition: Tags.h:63
#define TAG_TITLE
Definition: Tags.h:60
#define LABEL_TRACK
Definition: Tags.cpp:698
#define TAG_ARTIST
Definition: Tags.h:61
#define LABEL_TITLE
Definition: Tags.cpp:696
#define LABEL_ALBUM
Definition: Tags.cpp:697
void Clear()
Definition: Tags.cpp:300
Tags mLocal
Definition: Tags.h:181
#define LABEL_YEAR
Definition: Tags.cpp:699
#define LABEL_COMMENTS
Definition: Tags.cpp:701
Grid * mGrid
Definition: Tags.h:183
#define LABEL_GENRE
Definition: Tags.cpp:700
#define TAG_COMMENTS
Definition: Tags.h:66
#define TAG_GENRE
Definition: Tags.h:65
#define LABEL_ARTIST
Definition: Tags.cpp:695
#define TAG_ALBUM
Definition: Tags.h:62
#define TAG_YEAR
Definition: Tags.h:64
bool TagsEditor::TransferDataToWindow ( )
override

Definition at line 978 of file Tags.cpp.

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

Referenced by OnClear(), and OnLoad().

979 {
980  size_t i;
981  TagMap popTagMap;
982 
983  // Disable redrawing until we're done
984  mGrid->BeginBatch();
985 
986  // Delete all rows
987  if (mGrid->GetNumberRows()) {
988  mGrid->DeleteRows(0, mGrid->GetNumberRows());
989  }
990 
991  // Populate the static rows
992  for (i = 0; i < STATICCNT; i++) {
993  mGrid->AppendRows();
994 
995  mGrid->SetReadOnly(i, 0);
996  // The special tag name that's displayed and translated may not match
997  // the key string used for internal lookup.
998  mGrid->SetCellValue(i, 0, wxGetTranslation( labelmap[i].label ) );
999  mGrid->SetCellValue(i, 1, mLocal.GetTag(labelmap[i].name));
1000 
1001  if (!mEditTitle &&
1002  mGrid->GetCellValue(i, 0).CmpNoCase(wxGetTranslation(LABEL_TITLE)) == 0) {
1003  mGrid->SetReadOnly(i, 1);
1004  }
1005 
1006  if (!mEditTrack &&
1007  mGrid->GetCellValue(i, 0).CmpNoCase(wxGetTranslation(LABEL_TRACK)) == 0) {
1008  mGrid->SetReadOnly(i, 1);
1009  }
1010 
1011  popTagMap[ labelmap[i].name ] = mGrid->GetCellValue(i, 1);
1012  }
1013 
1014  // Populate the rest
1015  for (const auto &pair : mLocal.GetRange()) {
1016  const auto &n = pair.first;
1017  const auto &v = pair.second;
1018  if (popTagMap.find(n) == popTagMap.end()) {
1019  mGrid->AppendRows();
1020  mGrid->SetCellValue(i, 0, n);
1021  mGrid->SetCellValue(i, 1, v);
1022  i++;
1023  }
1024  }
1025 
1026  // Add an extra one to help with initial sizing and to show it can be done
1027  mGrid->AppendRows(1);
1028 
1029  // We're done, so allow the grid to redraw
1030  mGrid->EndBatch();
1031 
1032  // Set the editors
1033  SetEditors();
1034  Layout();
1035  Fit();
1036 
1037  return true;
1038 }
static const struct @76 labelmap[]
wxString label
Definition: Tags.cpp:733
void SetEditors()
Definition: Tags.cpp:1409
std::unordered_map< wxString, wxString > TagMap
Definition: Tags.h:58
#define LABEL_TRACK
Definition: Tags.cpp:698
#define LABEL_TITLE
Definition: Tags.cpp:696
bool mEditTitle
Definition: Tags.h:178
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:424
Tags mLocal
Definition: Tags.h:181
#define STATICCNT
Definition: Tags.cpp:747
Grid * mGrid
Definition: Tags.h:183
bool mEditTrack
Definition: Tags.h:179
Iterators GetRange() const
Definition: Tags.cpp:444

Member Data Documentation

ComboEditor* TagsEditor::mComboEditor
private

Definition at line 184 of file Tags.h.

Referenced by PopulateOrExchange().

bool TagsEditor::mEditTitle
private

Definition at line 178 of file Tags.h.

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

bool TagsEditor::mEditTrack
private

Definition at line 179 of file Tags.h.

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

Grid* TagsEditor::mGrid
private
Tags TagsEditor::mLocal
private
wxGridCellStringRenderer* TagsEditor::mStringRenderer
private

Definition at line 185 of file Tags.h.

Referenced by PopulateOrExchange().

Tags* TagsEditor::mTags
private

Definition at line 177 of file Tags.h.

Referenced by OnOk().


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