Missing note type when filtering out missing asset errors.
[libdcp.git] / langtest.cc
1 #include <dcp/language_tag.h>
2 #include <wx/listctrl.h>
3 #include <wx/srchctrl.h>
4 #include <wx/wx.h>
5 #include <boost/algorithm/string.hpp>
6 #include <boost/bind.hpp>
7 #include <boost/enable_shared_from_this.hpp>
8 #include <boost/foreach.hpp>
9 #include <boost/shared_ptr.hpp>
10 #include <boost/signals2.hpp>
11 #include <iostream>
12 #include <iterator>
13
14
15 using std::string;
16 using std::vector;
17 using boost::enable_shared_from_this;
18 using boost::optional;
19 using boost::shared_ptr;
20 using boost::weak_ptr;
21
22
23 class SubtagListCtrl : public wxListCtrl
24 {
25 public:
26         SubtagListCtrl (wxWindow* parent)
27                 : wxListCtrl (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER | wxLC_VIRTUAL)
28         {
29                 AppendColumn ("", wxLIST_FORMAT_LEFT, 80);
30                 AppendColumn ("", wxLIST_FORMAT_LEFT, 400);
31         }
32
33         void set_type_and_search (dcp::LanguageTag::SubtagType type, string search, optional<dcp::LanguageTag::Subtag> subtag = optional<dcp::LanguageTag::Subtag>())
34         {
35                 _all_subtags = dcp::LanguageTag::get_all(type);
36                 set_search (search);
37                 if (subtag) {
38                         vector<dcp::LanguageTag::Subtag>::iterator i = find(_matching_subtags.begin(), _matching_subtags.end(), *subtag);
39                         if (i != _matching_subtags.end()) {
40                                 SetItemState (std::distance(_matching_subtags.begin(), i), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
41                         }
42                 }
43         }
44
45         void set_search (string search)
46         {
47                 if (search == "") {
48                         _matching_subtags = _all_subtags;
49                 } else {
50                         _matching_subtags.clear ();
51
52                         boost::algorithm::to_lower(search);
53                         BOOST_FOREACH (dcp::LanguageTag::Subtag const& i, _all_subtags) {
54                                 if (
55                                         (boost::algorithm::to_lower_copy(i.subtag).find(search) != string::npos) ||
56                                         (boost::algorithm::to_lower_copy(i.description).find(search) != string::npos)) {
57                                         _matching_subtags.push_back (i);
58                                 }
59                         }
60                 }
61
62                 SetItemCount (_matching_subtags.size());
63                 if (GetItemCount() > 0) {
64                         RefreshItems (0, GetItemCount() - 1);
65                 }
66         }
67
68         optional<dcp::LanguageTag::Subtag> selected_subtag () const
69         {
70                 long int selected = GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
71                 if (selected == -1) {
72                         return optional<dcp::LanguageTag::Subtag>();
73                 }
74
75                 //DCPOMATIC_ASSERT (selected < _matching_subtags.size());
76                 return _matching_subtags[selected];
77         }
78
79 private:
80         wxString OnGetItemText (long item, long column) const
81         {
82                 if (column == 0) {
83                         return _matching_subtags[item].subtag;
84                 } else {
85                         return _matching_subtags[item].description;
86                 }
87         }
88
89         std::vector<dcp::LanguageTag::Subtag> _all_subtags;
90         std::vector<dcp::LanguageTag::Subtag> _matching_subtags;
91 };
92
93
94 class LanguageSubtagPanel : public wxPanel
95 {
96 public:
97         LanguageSubtagPanel (wxWindow* parent)
98                 : wxPanel (parent, wxID_ANY)
99         {
100 #ifdef __WXGTK3__
101                 int const height = 30;
102 #else
103                 int const height = -1;
104 #endif
105
106                 _search = new wxSearchCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, height));
107                 _list = new SubtagListCtrl (this);
108
109                 wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
110                 sizer->Add (_search, 0, wxALL, 8);
111                 sizer->Add (_list, 1, wxALL, 8);
112                 SetSizerAndFit (sizer);
113
114                 _search->Bind (wxEVT_TEXT, boost::bind(&LanguageSubtagPanel::search_changed, this));
115                 _list->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&LanguageSubtagPanel::selection_changed, this));
116                 _list->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&LanguageSubtagPanel::selection_changed, this));
117         }
118
119         void set_type_and_search (dcp::LanguageTag::SubtagType type, string search, optional<dcp::LanguageTag::Subtag> subtag = optional<dcp::LanguageTag::Subtag>())
120         {
121                 _list->set_type_and_search (type, search, subtag);
122                 _search->SetValue (wxString(search));
123         }
124
125         boost::signals2::signal<void (optional<dcp::LanguageTag::Subtag>)> SelectionChanged;
126         boost::signals2::signal<void (string)> SearchChanged;
127
128 private:
129         void search_changed ()
130         {
131                 _list->set_search (_search->GetValue().ToStdString());
132                 SearchChanged (_search->GetValue().ToStdString());
133         }
134
135         void selection_changed ()
136         {
137                 SelectionChanged (_list->selected_subtag());
138         }
139
140         wxSearchCtrl* _search;
141         SubtagListCtrl* _list;
142 };
143
144
145
146
147 class LanguageTagDialog : public wxDialog
148 {
149 public:
150         class Subtag
151         {
152         public:
153                 Subtag (dcp::LanguageTag::SubtagType type_, dcp::LanguageTag::Subtag subtag_)
154                         : type (type_)
155                         , subtag (subtag_)
156                 {}
157
158                 dcp::LanguageTag::SubtagType type;
159                 dcp::LanguageTag::Subtag subtag;
160                 std::string last_search;
161         };
162
163         LanguageTagDialog (wxWindow* parent)
164                 : wxDialog (parent, wxID_ANY, "Language Tag")
165         {
166                 _current_tag_list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER);
167                 _current_tag_list->AppendColumn ("", wxLIST_FORMAT_LEFT, 200);
168                 _current_tag_list->AppendColumn ("", wxLIST_FORMAT_LEFT, 400);
169
170                 wxBoxSizer* button_sizer = new wxBoxSizer (wxVERTICAL);
171                 _add_script = new wxButton(this, wxID_ANY, "Add script");
172                 button_sizer->Add (_add_script, 1, wxTOP | wxBOTTOM | wxEXPAND, 2);
173                 _add_region = new wxButton(this, wxID_ANY, "Add region");
174                 button_sizer->Add (_add_region, 1, wxTOP | wxBOTTOM | wxEXPAND, 2);
175                 _add_variant = new wxButton(this, wxID_ANY, "Add variant");
176                 button_sizer->Add (_add_variant, 1, wxTOP | wxBOTTOM | wxEXPAND, 2);
177                 _add_external = new wxButton(this, wxID_ANY, "Add external");
178                 button_sizer->Add (_add_external, 1, wxTOP | wxBOTTOM | wxEXPAND, 2);
179
180                 _choose_subtag_panel = new LanguageSubtagPanel (this);
181                 _choose_subtag_panel->set_type_and_search (dcp::LanguageTag::LANGUAGE, "de");
182
183                 wxBoxSizer* overall_sizer = new wxBoxSizer (wxHORIZONTAL);
184                 overall_sizer->Add (_current_tag_list, 1, wxALL, 8);
185                 overall_sizer->Add (button_sizer, 0, wxALL, 8);
186                 overall_sizer->Add (_choose_subtag_panel, 1, wxALL, 8);
187
188                 SetSizerAndFit (overall_sizer);
189
190                 add_to_current_tag (dcp::LanguageTag::LANGUAGE, dcp::LanguageTag::Subtag("en", "English"));
191
192                 _add_script->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::SCRIPT, dcp::LanguageTag::Subtag()));
193                 _add_region->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::REGION, dcp::LanguageTag::Subtag()));
194                 _add_variant->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::VARIANT, dcp::LanguageTag::Subtag()));
195                 _add_external->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::EXTLANG, dcp::LanguageTag::Subtag()));
196                 _choose_subtag_panel->SelectionChanged.connect(bind(&LanguageTagDialog::chosen_subtag_changed, this, _1));
197                 _choose_subtag_panel->SearchChanged.connect(bind(&LanguageTagDialog::search_changed, this, _1));
198                 _current_tag_list->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&LanguageTagDialog::current_tag_selection_changed, this));
199                 _current_tag_list->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&LanguageTagDialog::current_tag_selection_changed, this));
200         }
201
202         dcp::LanguageTag get () const
203         {
204                 dcp::LanguageTag tag;
205
206                 vector<string> variants;
207                 vector<string> extlangs;
208
209                 BOOST_FOREACH (Subtag i, _current_tag_subtags) {
210                         switch (i.type) {
211                         case dcp::LanguageTag::LANGUAGE:
212                                 tag.set_language (i.subtag.subtag);
213                                 break;
214                         case dcp::LanguageTag::SCRIPT:
215                                 tag.set_script (i.subtag.subtag);
216                                 break;
217                         case dcp::LanguageTag::REGION:
218                                 tag.set_region (i.subtag.subtag);
219                                 break;
220                         case dcp::LanguageTag::VARIANT:
221                                 variants.push_back (i.subtag.subtag);
222                                 break;
223                         case dcp::LanguageTag::EXTLANG:
224                                 extlangs.push_back (i.subtag.subtag);
225                                 break;
226                         }
227                 }
228
229                 tag.set_variants (variants);
230                 tag.set_extlangs (extlangs);
231                 return tag;
232         }
233
234
235 private:
236
237         string subtag_type_name (dcp::LanguageTag::SubtagType type)
238         {
239                 switch (type) {
240                 case dcp::LanguageTag::LANGUAGE:
241                         return "Language";
242                 case dcp::LanguageTag::SCRIPT:
243                         return "Script";
244                 case dcp::LanguageTag::REGION:
245                         return "Region";
246                 case dcp::LanguageTag::VARIANT:
247                         return "Variant";
248                 case dcp::LanguageTag::EXTLANG:
249                         return "External";
250                 }
251
252                 return "";
253         }
254
255         void search_changed (string search)
256         {
257                 long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
258                 if (selected >= 0) {
259                         _current_tag_subtags[selected].last_search = search;
260                 }
261         }
262
263         void add_to_current_tag (dcp::LanguageTag::SubtagType type, dcp::LanguageTag::Subtag subtag)
264         {
265                 _current_tag_subtags.push_back (Subtag(type, subtag));
266                 wxListItem it;
267                 it.SetId (_current_tag_list->GetItemCount());
268                 it.SetColumn (0);
269                 it.SetText (subtag_type_name(type));
270                 _current_tag_list->InsertItem (it);
271                 it.SetColumn (1);
272                 it.SetText ("Select...");
273                 _current_tag_list->SetItem (it);
274                 _current_tag_list->SetItemState (_current_tag_list->GetItemCount() - 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
275                 _choose_subtag_panel->set_type_and_search (type, "");
276                 setup_sensitivity ();
277         }
278
279         void current_tag_selection_changed ()
280         {
281                 long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
282                 if (selected >= 0) {
283                         _choose_subtag_panel->Enable (true);
284                         _choose_subtag_panel->set_type_and_search (_current_tag_subtags[selected].type, _current_tag_subtags[selected].last_search, _current_tag_subtags[selected].subtag);
285                 } else {
286                         _choose_subtag_panel->Enable (false);
287                 }
288         }
289
290         void chosen_subtag_changed (optional<dcp::LanguageTag::Subtag> selection)
291         {
292                 if (!selection) {
293                         return;
294                 }
295
296                 long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
297                 if (selected >= 0) {
298                         _current_tag_subtags[selected].subtag = *selection;
299                         _current_tag_list->SetItem (selected, 0, subtag_type_name(_current_tag_subtags[selected].type));
300                         _current_tag_list->SetItem (selected, 1, selection->description);
301                 }
302         }
303
304         void setup_sensitivity ()
305         {
306                 _add_script->Enable ();
307                 _add_region->Enable ();
308                 _add_variant->Enable ();
309                 _add_external->Enable ();
310                 BOOST_FOREACH (Subtag const& i, _current_tag_subtags) {
311                         switch (i.type) {
312                         case dcp::LanguageTag::SCRIPT:
313                                 _add_script->Enable (false);
314                                 break;
315                         case dcp::LanguageTag::REGION:
316                                 _add_region->Enable (false);
317                                 break;
318                         case dcp::LanguageTag::VARIANT:
319                                 _add_variant->Enable (false);
320                                 break;
321                         case dcp::LanguageTag::EXTLANG:
322                                 _add_external->Enable (false);
323                                 break;
324                         }
325                 }
326         }
327
328         vector<Subtag> _current_tag_subtags;
329         wxListCtrl* _current_tag_list;
330         LanguageSubtagPanel* _choose_subtag_panel;
331         wxButton* _add_script;
332         wxButton* _add_region;
333         wxButton* _add_variant;
334         wxButton* _add_external;
335 };
336
337
338 class MyApp : public wxApp
339 {
340 public:
341         virtual bool OnInit()
342         {
343                 LanguageTagDialog* dialog = new LanguageTagDialog (0);
344                 dialog->ShowModal ();
345                 return true;
346         }
347 };
348
349 wxIMPLEMENT_APP(MyApp);
350