#include "check_box.h"
#include "nag_dialog.h"
#include "dcpomatic_button.h"
+#include "audio_mapping_view.h"
+#include <dcp/raw_convert.h>
#include <iostream>
using std::string;
using std::map;
using boost::bind;
using boost::optional;
-using boost::shared_ptr;
+using std::shared_ptr;
using boost::function;
+#if BOOST_VERSION >= 106100
+using namespace boost::placeholders;
+#endif
static
bool
_config_connection = Config::instance()->Changed.connect (bind (&Page::config_changed_wrapper, this));
}
+
+wxWindow*
+Page::CreateWindow (wxWindow* parent)
+{
+ return create_window (parent);
+}
+
+
wxWindow*
Page::create_window (wxWindow* parent)
{
}
-StockPage::StockPage (Kind kind, wxSize panel_size, int border)
- : wxStockPreferencesPage (kind)
- , Page (panel_size, border)
-{
-
-}
-
-wxWindow*
-StockPage::CreateWindow (wxWindow* parent)
-{
- return create_window (parent);
-}
-
-StandardPage::StandardPage (wxSize panel_size, int border)
+GeneralPage::GeneralPage (wxSize panel_size, int border)
: Page (panel_size, border)
{
}
-wxWindow*
-StandardPage::CreateWindow (wxWindow* parent)
-{
- return create_window (parent);
-}
-GeneralPage::GeneralPage (wxSize panel_size, int border)
- : StockPage (Kind_General, panel_size, border)
+wxString
+GeneralPage::GetName () const
{
-
+ return _("General");
}
+
void
GeneralPage::add_language_controls (wxGridBagSizer* table, int& r)
{
_language->Bind (wxEVT_CHOICE, bind (&GeneralPage::language_changed, this));
}
-void
-GeneralPage::add_play_sound_controls (wxGridBagSizer* table, int& r)
-{
- _sound = new CheckBox (_panel, _("Play sound via"));
- table->Add (_sound, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _sound_output = new wxChoice (_panel, wxID_ANY);
- s->Add (_sound_output, 0);
- _sound_output_details = new wxStaticText (_panel, wxID_ANY, wxT(""));
- s->Add (_sound_output_details, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, DCPOMATIC_SIZER_X_GAP);
- table->Add (s, wxGBPosition(r, 1));
- ++r;
-
- wxFont font = _sound_output_details->GetFont();
- font.SetStyle (wxFONTSTYLE_ITALIC);
- font.SetPointSize (font.GetPointSize() - 1);
- _sound_output_details->SetFont (font);
-
- RtAudio audio (DCPOMATIC_RTAUDIO_API);
- for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
- RtAudio::DeviceInfo dev = audio.getDeviceInfo (i);
- if (dev.probed && dev.outputChannels > 0) {
- _sound_output->Append (std_to_wx (dev.name));
- }
- }
-
- _sound->Bind (wxEVT_CHECKBOX, bind (&GeneralPage::sound_changed, this));
- _sound_output->Bind (wxEVT_CHOICE, bind (&GeneralPage::sound_output_changed, this));
-}
-
void
GeneralPage::add_update_controls (wxGridBagSizer* table, int& r)
{
checked_set (_check_for_updates, config->check_for_updates ());
checked_set (_check_for_test_updates, config->check_for_test_updates ());
- checked_set (_sound, config->sound ());
-
- optional<string> const current_so = get_sound_output ();
- optional<string> configured_so;
-
- if (config->sound_output()) {
- configured_so = config->sound_output().get();
- } else {
- /* No configured output means we should use the default */
- RtAudio audio (DCPOMATIC_RTAUDIO_API);
- try {
- configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
- } catch (RtAudioError& e) {
- /* Probably no audio devices at all */
- }
- }
-
- if (configured_so && current_so != configured_so) {
- /* Update _sound_output with the configured value */
- unsigned int i = 0;
- while (i < _sound_output->GetCount()) {
- if (_sound_output->GetString(i) == std_to_wx(*configured_so)) {
- _sound_output->SetSelection (i);
- break;
- }
- ++i;
- }
- }
-
- RtAudio audio (DCPOMATIC_RTAUDIO_API);
-
- map<int, wxString> apis;
- apis[RtAudio::MACOSX_CORE] = _("CoreAudio");
- apis[RtAudio::WINDOWS_ASIO] = _("ASIO");
- apis[RtAudio::WINDOWS_DS] = _("Direct Sound");
- apis[RtAudio::WINDOWS_WASAPI] = _("WASAPI");
- apis[RtAudio::UNIX_JACK] = _("JACK");
- apis[RtAudio::LINUX_ALSA] = _("ALSA");
- apis[RtAudio::LINUX_PULSE] = _("Pulseaudio");
- apis[RtAudio::LINUX_OSS] = _("OSS");
- apis[RtAudio::RTAUDIO_DUMMY] = _("Dummy");
-
- int channels = 0;
- if (configured_so) {
- for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
- RtAudio::DeviceInfo info = audio.getDeviceInfo(i);
- if (info.name == *configured_so && info.outputChannels > 0) {
- channels = info.outputChannels;
- }
- }
- }
-
- _sound_output_details->SetLabel (
- wxString::Format(_("%d channels on %s"), channels, apis[audio.getCurrentApi()])
- );
-
setup_sensitivity ();
}
{
_language->Enable (_set_language->GetValue ());
_check_for_test_updates->Enable (_check_for_updates->GetValue ());
- _sound_output->Enable (_sound->GetValue ());
-}
-
-/** @return Currently-selected preview sound output in the dialogue */
-optional<string>
-GeneralPage::get_sound_output ()
-{
- int const sel = _sound_output->GetSelection ();
- if (sel == wxNOT_FOUND) {
- return optional<string> ();
- }
-
- return wx_to_std (_sound_output->GetString (sel));
}
void
Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
}
-void
-GeneralPage::sound_changed ()
-{
- Config::instance()->set_sound (_sound->GetValue ());
-}
-
-void
-GeneralPage::sound_output_changed ()
-{
- RtAudio audio (DCPOMATIC_RTAUDIO_API);
- optional<string> const so = get_sound_output();
- if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) {
- Config::instance()->unset_sound_output ();
- } else {
- Config::instance()->set_sound_output (*so);
- }
-}
-
CertificateChainEditor::CertificateChainEditor (
wxWindow* parent,
wxString title,
, _get (get)
, _nag_alter (nag_alter)
{
- wxFont subheading_font (*wxNORMAL_FONT);
- subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
-
_sizer = new wxBoxSizer (wxVERTICAL);
- {
- wxStaticText* m = new StaticText (this, title);
- m->SetFont (subheading_font);
- _sizer->Add (m, 0, wxALL, border);
- }
-
wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
- _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
+ _sizer->Add (certificates_sizer, 0, wxALL, border);
_certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
{
wxSizer* s = new wxBoxSizer (wxVERTICAL);
_add_certificate = new Button (this, _("Add..."));
- s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
+ s->Add (_add_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
_remove_certificate = new Button (this, _("Remove"));
- s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
- _export_certificate = new Button (this, _("Export"));
- s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
+ s->Add (_remove_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
+ _export_certificate = new Button (this, _("Export certificate..."));
+ s->Add (_export_certificate, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
+ _export_chain = new Button (this, _("Export chain..."));
+ s->Add (_export_chain, 1, wxTOP | wxBOTTOM | wxEXPAND, DCPOMATIC_BUTTON_STACK_GAP);
certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
}
_button_sizer = new wxBoxSizer (wxHORIZONTAL);
_remake_certificates = new Button (this, _("Re-make certificates and key..."));
_button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
- _export_chain = new Button (this, _("Export chain..."));
- _button_sizer->Add (_export_chain, 1, wxRIGHT, border);
table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
++r;
_set (chain);
update_sensitivity ();
+ update_certificate_list ();
}
void
wxFileDialog* d = new wxFileDialog (
this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
+ auto all = _get()->root_to_leaf();
+
+ wxString default_name;
+ if (i == 0) {
+ default_name = "root.pem";
+ } else if (i == static_cast<int>(all.size() - 1)) {
+ default_name = "leaf.pem";
+ } else {
+ default_name = "intermediate.pem";
+ }
+
+ auto d = new wxFileDialog(
+ this, _("Select Certificate File"), wxEmptyString, default_name, wxT ("PEM files (*.pem)|*.pem"),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
- dcp::CertificateChain::List all = _get()->root_to_leaf ();
- dcp::CertificateChain::List::iterator j = all.begin ();
+ auto j = all.begin ();
for (int k = 0; k < i; ++k) {
++j;
}
boost::filesystem::path path (wx_to_std(d->GetPath()));
FILE* f = fopen_boost (path, "w");
if (!f) {
- throw OpenFileError (path, errno, false);
+ throw OpenFileError (path, errno, OpenFileError::WRITE);
}
string const s = j->certificate (true);
void
CertificateChainEditor::export_chain ()
{
- wxFileDialog* d = new wxFileDialog (
- this, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT("PEM files (*.pem)|*.pem"),
+ auto d = new wxFileDialog (
+ this, _("Select Chain File"), wxEmptyString, _("certificate_chain.pem"), wxT("PEM files (*.pem)|*.pem"),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
boost::filesystem::path path (wx_to_std(d->GetPath()));
FILE* f = fopen_boost (path, "w");
if (!f) {
- throw OpenFileError (path, errno, false);
+ throw OpenFileError (path, errno, OpenFileError::WRITE);
}
string const s = _get()->chain();
_certificates->DeleteAllItems ();
size_t n = 0;
dcp::CertificateChain::List certs = _get()->root_to_leaf ();
- BOOST_FOREACH (dcp::Certificate const & i, certs) {
+ for (auto const& i: certs) {
wxListItem item;
item.SetId (n);
_certificates->InsertItem (item);
return;
}
- wxFileDialog* d = new wxFileDialog (
- this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
+ auto d = new wxFileDialog (
+ this, _("Select Key File"), wxEmptyString, _("private_key.pem"), wxT ("PEM files (*.pem)|*.pem"),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
boost::filesystem::path path (wx_to_std(d->GetPath()));
FILE* f = fopen_boost (path, "w");
if (!f) {
- throw OpenFileError (path, errno, false);
+ throw OpenFileError (path, errno, OpenFileError::WRITE);
}
string const s = _get()->key().get ();
sizer->Add (m, 0, wxALL, _border);
}
+ wxSizer* buttons = new wxBoxSizer (wxVERTICAL);
+
wxButton* export_decryption_certificate = new Button (_panel, _("Export KDM decryption certificate..."));
- sizer->Add (export_decryption_certificate, 0, wxLEFT, _border);
+ buttons->Add (export_decryption_certificate, 0, wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
wxButton* export_settings = new Button (_panel, _("Export all KDM decryption settings..."));
- sizer->Add (export_settings, 0, wxLEFT, _border);
+ buttons->Add (export_settings, 0, wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
wxButton* import_settings = new Button (_panel, _("Import all KDM decryption settings..."));
- sizer->Add (import_settings, 0, wxLEFT, _border);
+ buttons->Add (import_settings, 0, wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
wxButton* decryption_advanced = new Button (_panel, _("Advanced..."));
- sizer->Add (decryption_advanced, 0, wxALL, _border);
+ buttons->Add (decryption_advanced, 0);
+
+ sizer->Add (buttons, 0, wxLEFT, _border);
export_decryption_certificate->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_certificate, this));
export_settings->Bind (wxEVT_BUTTON, bind (&KeysPage::export_decryption_chain_and_key, this));
}
wxButton* signing_advanced = new Button (_panel, _("Advanced..."));
- sizer->Add (signing_advanced, 0, wxLEFT, _border);
+ sizer->Add (signing_advanced, 0, wxLEFT | wxBOTTOM, _border);
signing_advanced->Bind (wxEVT_BUTTON, bind (&KeysPage::signing_advanced, this));
}
boost::filesystem::path path (wx_to_std(d->GetPath()));
FILE* f = fopen_boost (path, "w");
if (!f) {
- throw OpenFileError (path, errno, false);
+ throw OpenFileError (path, errno, OpenFileError::WRITE);
}
string const chain = Config::instance()->decryption_chain()->chain();
FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "r");
if (!f) {
- throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
+ throw OpenFileError (wx_to_std (d->GetPath ()), errno, OpenFileError::WRITE);
}
string current;
boost::filesystem::path path (wx_to_std(d->GetPath()));
FILE* f = fopen_boost (path, "w");
if (!f) {
- throw OpenFileError (path, errno, false);
+ throw OpenFileError (path, errno, OpenFileError::WRITE);
}
string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
d->Destroy ();
}
+
+wxString
+SoundPage::GetName () const
+{
+ return _("Sound");
+}
+
+void
+SoundPage::setup ()
+{
+ wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+ _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
+
+ int r = 0;
+
+ _sound = new CheckBox (_panel, _("Play sound via"));
+ table->Add (_sound, wxGBPosition (r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _sound_output = new wxChoice (_panel, wxID_ANY);
+ s->Add (_sound_output, 0);
+ _sound_output_details = new wxStaticText (_panel, wxID_ANY, wxT(""));
+ s->Add (_sound_output_details, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, DCPOMATIC_SIZER_X_GAP);
+ table->Add (s, wxGBPosition(r, 1));
+ ++r;
+
+ add_label_to_sizer (table, _panel, _("Mapping"), true, wxGBPosition(r, 0));
+ _map = new AudioMappingView (_panel, _("DCP"), _("DCP"), _("Output"), _("output"));
+ _map->SetSize (-1, 600);
+ table->Add (_map, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+ ++r;
+
+ _reset_to_default = new Button (_panel, _("Reset to default"));
+ table->Add (_reset_to_default, wxGBPosition(r, 1));
+ ++r;
+
+ wxFont font = _sound_output_details->GetFont();
+ font.SetStyle (wxFONTSTYLE_ITALIC);
+ font.SetPointSize (font.GetPointSize() - 1);
+ _sound_output_details->SetFont (font);
+
+ RtAudio audio (DCPOMATIC_RTAUDIO_API);
+ for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
+ try {
+ RtAudio::DeviceInfo dev = audio.getDeviceInfo (i);
+ if (dev.probed && dev.outputChannels > 0) {
+ _sound_output->Append (std_to_wx (dev.name));
+ }
+ } catch (RtAudioError&) {
+ /* Something went wrong so let's just ignore that device */
+ }
+ }
+
+ _sound->Bind (wxEVT_CHECKBOX, bind(&SoundPage::sound_changed, this));
+ _sound_output->Bind (wxEVT_CHOICE, bind(&SoundPage::sound_output_changed, this));
+ _map->Changed.connect (bind(&SoundPage::map_changed, this, _1));
+ _reset_to_default->Bind (wxEVT_BUTTON, bind(&SoundPage::reset_to_default, this));
+}
+
+void
+SoundPage::reset_to_default ()
+{
+ Config::instance()->set_audio_mapping_to_default ();
+}
+
+void
+SoundPage::map_changed (AudioMapping m)
+{
+ Config::instance()->set_audio_mapping (m);
+}
+
+void
+SoundPage::sound_changed ()
+{
+ Config::instance()->set_sound (_sound->GetValue ());
+}
+
+void
+SoundPage::sound_output_changed ()
+{
+ RtAudio audio (DCPOMATIC_RTAUDIO_API);
+ optional<string> const so = get_sound_output();
+ string default_device;
+ try {
+ default_device = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
+ } catch (RtAudioError&) {
+ /* Never mind */
+ }
+ if (!so || *so == default_device) {
+ Config::instance()->unset_sound_output ();
+ } else {
+ Config::instance()->set_sound_output (*so);
+ }
+}
+
+void
+SoundPage::config_changed ()
+{
+ Config* config = Config::instance ();
+
+ checked_set (_sound, config->sound ());
+
+ optional<string> const current_so = get_sound_output ();
+ optional<string> configured_so;
+
+ if (config->sound_output()) {
+ configured_so = config->sound_output().get();
+ } else {
+ /* No configured output means we should use the default */
+ RtAudio audio (DCPOMATIC_RTAUDIO_API);
+ try {
+ configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
+ } catch (RtAudioError&) {
+ /* Probably no audio devices at all */
+ }
+ }
+
+ if (configured_so && current_so != configured_so) {
+ /* Update _sound_output with the configured value */
+ unsigned int i = 0;
+ while (i < _sound_output->GetCount()) {
+ if (_sound_output->GetString(i) == std_to_wx(*configured_so)) {
+ _sound_output->SetSelection (i);
+ break;
+ }
+ ++i;
+ }
+ }
+
+ RtAudio audio (DCPOMATIC_RTAUDIO_API);
+
+ map<int, wxString> apis;
+ apis[RtAudio::MACOSX_CORE] = _("CoreAudio");
+ apis[RtAudio::WINDOWS_ASIO] = _("ASIO");
+ apis[RtAudio::WINDOWS_DS] = _("Direct Sound");
+ apis[RtAudio::WINDOWS_WASAPI] = _("WASAPI");
+ apis[RtAudio::UNIX_JACK] = _("JACK");
+ apis[RtAudio::LINUX_ALSA] = _("ALSA");
+ apis[RtAudio::LINUX_PULSE] = _("PulseAudio");
+ apis[RtAudio::LINUX_OSS] = _("OSS");
+ apis[RtAudio::RTAUDIO_DUMMY] = _("Dummy");
+
+ int channels = 0;
+ if (configured_so) {
+ for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
+ try {
+ RtAudio::DeviceInfo info = audio.getDeviceInfo(i);
+ if (info.name == *configured_so && info.outputChannels > 0) {
+ channels = info.outputChannels;
+ }
+ } catch (RtAudioError&) {
+ /* Never mind */
+ }
+ }
+ }
+
+ _sound_output_details->SetLabel (
+ wxString::Format(_("%d channels on %s"), channels, apis[audio.getCurrentApi()])
+ );
+
+ _map->set (Config::instance()->audio_mapping(channels));
+
+ vector<NamedChannel> input;
+ for (int i = 0; i < MAX_DCP_AUDIO_CHANNELS; ++i) {
+ input.push_back (NamedChannel(short_audio_channel_name(i), i));
+ }
+ _map->set_input_channels (input);
+
+ vector<NamedChannel> output;
+ for (int i = 0; i < channels; ++i) {
+ output.push_back (NamedChannel(dcp::raw_convert<string>(i), i));
+ }
+ _map->set_output_channels (output);
+
+ setup_sensitivity ();
+}
+
+void
+SoundPage::setup_sensitivity ()
+{
+ _sound_output->Enable (_sound->GetValue());
+}
+
+/** @return Currently-selected preview sound output in the dialogue */
+optional<string>
+SoundPage::get_sound_output ()
+{
+ int const sel = _sound_output->GetSelection ();
+ if (sel == wxNOT_FOUND) {
+ return optional<string> ();
+ }
+
+ return wx_to_std (_sound_output->GetString (sel));
+}
+
+
+LocationsPage::LocationsPage (wxSize panel_size, int border)
+ : Page (panel_size, border)
+{
+
+}
+
+wxString
+LocationsPage::GetName () const
+{
+ return _("Locations");
+}
+
+#ifdef DCPOMATIC_OSX
+wxBitmap
+LocationsPage::GetLargeIcon () const
+{
+ return wxBitmap ("locations", wxBITMAP_TYPE_PNG_RESOURCE);
+}
+#endif
+
+void
+LocationsPage::setup ()
+{
+ int r = 0;
+
+ wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+ _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
+
+ add_label_to_sizer (table, _panel, _("Content directory"), true, wxGBPosition (r, 0));
+ _content_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
+ table->Add (_content_directory, wxGBPosition (r, 1));
+ ++r;
+
+ add_label_to_sizer (table, _panel, _("Playlist directory"), true, wxGBPosition (r, 0));
+ _playlist_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
+ table->Add (_playlist_directory, wxGBPosition (r, 1));
+ ++r;
+
+ add_label_to_sizer (table, _panel, _("KDM directory"), true, wxGBPosition (r, 0));
+ _kdm_directory = new wxDirPickerCtrl (_panel, wxID_ANY, wxEmptyString, wxDirSelectorPromptStr, wxDefaultPosition, wxSize (300, -1));
+ table->Add (_kdm_directory, wxGBPosition (r, 1));
+ ++r;
+
+ _content_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::content_directory_changed, this));
+ _playlist_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::playlist_directory_changed, this));
+ _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, bind(&LocationsPage::kdm_directory_changed, this));
+}
+
+void
+LocationsPage::config_changed ()
+{
+ Config* config = Config::instance ();
+
+ if (config->player_content_directory()) {
+ checked_set (_content_directory, *config->player_content_directory());
+ }
+ if (config->player_playlist_directory()) {
+ checked_set (_playlist_directory, *config->player_playlist_directory());
+ }
+ if (config->player_kdm_directory()) {
+ checked_set (_kdm_directory, *config->player_kdm_directory());
+ }
+}
+
+void
+LocationsPage::content_directory_changed ()
+{
+ Config::instance()->set_player_content_directory(wx_to_std(_content_directory->GetPath()));
+}
+
+void
+LocationsPage::playlist_directory_changed ()
+{
+ Config::instance()->set_player_playlist_directory(wx_to_std(_playlist_directory->GetPath()));
+}
+
+void
+LocationsPage::kdm_directory_changed ()
+{
+ Config::instance()->set_player_kdm_directory(wx_to_std(_kdm_directory->GetPath()));
+}