1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   Tags.h
6 
7   Dominic Mazzoni
8 
9   This class holds a few informational tags, such as Title, Author,
10   etc. that can be associated with a project or other audio file.
11   It is modeled after the ID3 format for MP3 files, and it can
12   both import ID3 tags from MP3 files, and export them as well.
13 
14   It can present the user with a dialog for editing this information.
15 
16   It only keeps track of the fields that are standard in ID3v1
17   (title, author, artist, track num, year, genre, and comments),
18   but it can export both ID3v1 or the newer ID3v2 format.  The primary
19   reason you would want to export ID3v2 tags instead of ID3v1,
20   since we're not supporting any v2 fields, is that ID3v2 tags are
21   inserted at the BEGINNING of an mp3 file, which is far more
22   useful for streaming.
23 
24   Use of this functionality requires that libid3tag be compiled in
25   with Audacity.
26 
27 **********************************************************************/
28 
29 #ifndef __AUDACITY_TAGS__
30 #define __AUDACITY_TAGS__
31 
32 
33 
34 #include "XMLTagHandler.h"
35 
36 #include "ClientData.h"
37 #include <utility>
38 
39 #include "widgets/wxPanelWrapper.h" // to inherit
40 
41 #include <memory>
42 #include <unordered_map>
43 #include "Identifier.h"
44 
45 class wxArrayString;
46 class wxComboBox;
47 class wxGridCellChoiceEditor;
48 class wxGridCellStringRenderer;
49 class wxGridEvent;
50 class wxTextCtrl;
51 
52 class AudacityProject;
53 class Grid;
54 class ShuttleGui;
55 class TagsEditorDialog;
56 class ComboEditor;
57 
58 using TagMap = std::unordered_map< wxString, wxString >;
59 
60 #define TAG_TITLE     wxT("TITLE")
61 #define TAG_ARTIST   wxT("ARTIST")
62 #define TAG_ALBUM    wxT("ALBUM")
63 #define TAG_TRACK    wxT("TRACKNUMBER")
64 #define TAG_YEAR     wxT("YEAR")
65 #define TAG_GENRE    wxT("GENRE")
66 #define TAG_COMMENTS wxT("COMMENTS")
67 #define TAG_SOFTWARE wxT("Software")
68 #define TAG_COPYRIGHT wxT("Copyright")
69 
70 class AUDACITY_DLL_API Tags final
71    : public XMLTagHandler
72    , public std::enable_shared_from_this< Tags >
73    , public ClientData::Base
74 {
75 
76  public:
77 
78    static Tags &Get( AudacityProject &project );
79    static const Tags &Get( const AudacityProject &project );
80    // Returns reference to *tags
81    static Tags &Set(
82       AudacityProject &project, const std::shared_ptr<Tags> &tags );
83 
84    Tags();  // constructor
85    Tags( const Tags& ) = default;
86    //Tags( Tags && ) = default;
87    virtual ~Tags();
88 
89    std::shared_ptr<Tags> Duplicate() const;
90 
91    void Merge( const Tags &other );
92 
93    Tags & operator= (const Tags & src );
94 
95    bool ShowEditDialog(
96       wxWindow *parent, const TranslatableString &title, bool force = false);
97 
98    bool HandleXMLTag(const std::string_view& tag, const AttributesList &attrs) override;
99    XMLTagHandler *HandleXMLChild(const std::string_view& tag) override;
100    void WriteXML(XMLWriter &xmlFile) const /* not override */;
101 
102    void AllowEditTitle(bool editTitle);
103    void AllowEditTrackNumber(bool editTrackNumber);
104 
105    void LoadDefaultGenres();
106    void LoadGenres();
107 
108    void LoadDefaults();
109 
110    int GetNumUserGenres();
111    wxString GetUserGenre(int value);
112 
113    wxString GetGenre(int value);
114    int GetGenre(const wxString & name);
115 
116    bool HasTag(const wxString & name) const;
117    wxString GetTag(const wxString & name) const;
118 
119    using Iterators = IteratorRange<TagMap::const_iterator>;
120    Iterators GetRange() const;
121 
122    void SetTag(const wxString & name, const wxString & value, const bool bSpecialTag=false);
123    void SetTag(const wxString & name, const int & value);
124 
125    bool IsEmpty();
126    void Clear();
127 
128    friend bool operator == (const Tags &lhs, const Tags &rhs);
129 
130  private:
131    TagMap mXref;
132    TagMap mMap;
133 
134    wxArrayString mGenres;
135 
136    bool mEditTitle;
137    bool mEditTrackNumber;
138 };
139 
140 inline bool operator != (const Tags &lhs, const Tags &rhs)
141 { return !(lhs == rhs); }
142 
143 class TagsEditorDialog final : public wxDialogWrapper
144 {
145  public:
146    // constructors and destructors
147    TagsEditorDialog(wxWindow * parent,
148               const TranslatableString &title,
149               Tags * tags,
150               bool editTitle,
151               bool editTrack);
152 
153    virtual ~TagsEditorDialog();
154 
155 #if !defined(__WXMSW__)
IsEscapeKey(const wxKeyEvent &)156    bool IsEscapeKey(const wxKeyEvent& /*event*/) override { return false; }
157 #endif
158 
159    void PopulateOrExchange(ShuttleGui & S);
160 
161    void OnDontShow( wxCommandEvent & Evt);
162    void OnHelp(wxCommandEvent & Evt);
163    bool TransferDataToWindow() override;
164    bool TransferDataFromWindow() override;
165 
166  private:
167    void PopulateGenres();
168    void SetEditors();
169 
170    void OnChange(wxGridEvent & event);
171 
172    void OnEdit(wxCommandEvent & event);
173    void OnReset(wxCommandEvent & event);
174 
175    void OnClear(wxCommandEvent & event);
176 
177    void OnLoad(wxCommandEvent & event);
178    void OnSave(wxCommandEvent & event);
179    void OnSaveDefaults(wxCommandEvent & event);
180 
181    void OnAdd(wxCommandEvent & event);
182    void OnRemove(wxCommandEvent & event);
183 
184    void OnOk(wxCommandEvent & event);
185    void DoCancel(bool escKey);
186    void OnCancel(wxCommandEvent & event);
187 
188    void OnKeyDown(wxKeyEvent &event);
189 
190    bool IsWindowRectValid(const wxRect *windowRect) const;
191 
192  private:
193    Tags *mTags;
194    bool mEditTitle;
195    bool mEditTrack;
196 
197    Tags mLocal;
198 
199    Grid *mGrid;
200    ComboEditor *mComboEditor;
201    wxGridCellStringRenderer *mStringRenderer;
202 
203    DECLARE_EVENT_TABLE()
204 };
205 
206 #endif
207