1 #include <dcp/language_tag.h>
2 #include <wx/listctrl.h>
3 #include <wx/srchctrl.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>
17 using boost::enable_shared_from_this;
18 using boost::optional;
19 using boost::shared_ptr;
20 using boost::weak_ptr;
23 class SubtagListCtrl : public wxListCtrl
26 SubtagListCtrl (wxWindow* parent)
27 : wxListCtrl (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER | wxLC_VIRTUAL)
29 AppendColumn ("", wxLIST_FORMAT_LEFT, 80);
30 AppendColumn ("", wxLIST_FORMAT_LEFT, 400);
33 void set_type_and_search (dcp::LanguageTag::SubtagType type, string search, optional<dcp::LanguageTag::Subtag> subtag = optional<dcp::LanguageTag::Subtag>())
35 _all_subtags = dcp::LanguageTag::get_all(type);
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);
45 void set_search (string search)
48 _matching_subtags = _all_subtags;
50 _matching_subtags.clear ();
52 boost::algorithm::to_lower(search);
53 BOOST_FOREACH (dcp::LanguageTag::Subtag const& i, _all_subtags) {
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);
62 SetItemCount (_matching_subtags.size());
63 if (GetItemCount() > 0) {
64 RefreshItems (0, GetItemCount() - 1);
68 optional<dcp::LanguageTag::Subtag> selected_subtag () const
70 long int selected = GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
72 return optional<dcp::LanguageTag::Subtag>();
75 //DCPOMATIC_ASSERT (selected < _matching_subtags.size());
76 return _matching_subtags[selected];
80 wxString OnGetItemText (long item, long column) const
83 return _matching_subtags[item].subtag;
85 return _matching_subtags[item].description;
89 std::vector<dcp::LanguageTag::Subtag> _all_subtags;
90 std::vector<dcp::LanguageTag::Subtag> _matching_subtags;
94 class LanguageSubtagPanel : public wxPanel
97 LanguageSubtagPanel (wxWindow* parent)
98 : wxPanel (parent, wxID_ANY)
101 int const height = 30;
103 int const height = -1;
106 _search = new wxSearchCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, height));
107 _list = new SubtagListCtrl (this);
109 wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
110 sizer->Add (_search, 0, wxALL, 8);
111 sizer->Add (_list, 1, wxALL, 8);
112 SetSizerAndFit (sizer);
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));
119 void set_type_and_search (dcp::LanguageTag::SubtagType type, string search, optional<dcp::LanguageTag::Subtag> subtag = optional<dcp::LanguageTag::Subtag>())
121 _list->set_type_and_search (type, search, subtag);
122 _search->SetValue (wxString(search));
125 boost::signals2::signal<void (optional<dcp::LanguageTag::Subtag>)> SelectionChanged;
126 boost::signals2::signal<void (string)> SearchChanged;
129 void search_changed ()
131 _list->set_search (_search->GetValue().ToStdString());
132 SearchChanged (_search->GetValue().ToStdString());
135 void selection_changed ()
137 SelectionChanged (_list->selected_subtag());
140 wxSearchCtrl* _search;
141 SubtagListCtrl* _list;
147 class LanguageTagDialog : public wxDialog
153 Subtag (dcp::LanguageTag::SubtagType type_, dcp::LanguageTag::Subtag subtag_)
158 dcp::LanguageTag::SubtagType type;
159 dcp::LanguageTag::Subtag subtag;
160 std::string last_search;
163 LanguageTagDialog (wxWindow* parent)
164 : wxDialog (parent, wxID_ANY, "Language Tag")
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);
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);
180 _choose_subtag_panel = new LanguageSubtagPanel (this);
181 _choose_subtag_panel->set_type_and_search (dcp::LanguageTag::LANGUAGE, "de");
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);
188 SetSizerAndFit (overall_sizer);
190 add_to_current_tag (dcp::LanguageTag::LANGUAGE, dcp::LanguageTag::Subtag("en", "English"));
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));
202 dcp::LanguageTag get () const
204 dcp::LanguageTag tag;
206 vector<string> variants;
207 vector<string> extlangs;
209 BOOST_FOREACH (Subtag i, _current_tag_subtags) {
211 case dcp::LanguageTag::LANGUAGE:
212 tag.set_language (i.subtag.subtag);
214 case dcp::LanguageTag::SCRIPT:
215 tag.set_script (i.subtag.subtag);
217 case dcp::LanguageTag::REGION:
218 tag.set_region (i.subtag.subtag);
220 case dcp::LanguageTag::VARIANT:
221 variants.push_back (i.subtag.subtag);
223 case dcp::LanguageTag::EXTLANG:
224 extlangs.push_back (i.subtag.subtag);
229 tag.set_variants (variants);
230 tag.set_extlangs (extlangs);
237 string subtag_type_name (dcp::LanguageTag::SubtagType type)
240 case dcp::LanguageTag::LANGUAGE:
242 case dcp::LanguageTag::SCRIPT:
244 case dcp::LanguageTag::REGION:
246 case dcp::LanguageTag::VARIANT:
248 case dcp::LanguageTag::EXTLANG:
255 void search_changed (string search)
257 long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
259 _current_tag_subtags[selected].last_search = search;
263 void add_to_current_tag (dcp::LanguageTag::SubtagType type, dcp::LanguageTag::Subtag subtag)
265 _current_tag_subtags.push_back (Subtag(type, subtag));
267 it.SetId (_current_tag_list->GetItemCount());
269 it.SetText (subtag_type_name(type));
270 _current_tag_list->InsertItem (it);
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 ();
279 void current_tag_selection_changed ()
281 long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
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);
286 _choose_subtag_panel->Enable (false);
290 void chosen_subtag_changed (optional<dcp::LanguageTag::Subtag> selection)
296 long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
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);
304 void setup_sensitivity ()
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) {
312 case dcp::LanguageTag::SCRIPT:
313 _add_script->Enable (false);
315 case dcp::LanguageTag::REGION:
316 _add_region->Enable (false);
318 case dcp::LanguageTag::VARIANT:
319 _add_variant->Enable (false);
321 case dcp::LanguageTag::EXTLANG:
322 _add_external->Enable (false);
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;
338 class MyApp : public wxApp
341 virtual bool OnInit()
343 LanguageTagDialog* dialog = new LanguageTagDialog (0);
344 dialog->ShowModal ();
349 wxIMPLEMENT_APP(MyApp);