Store subtitle language(s) in Film, and allow setup of those
authorCarl Hetherington <cth@carlh.net>
Wed, 18 Nov 2020 00:06:49 +0000 (01:06 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 20 Nov 2020 21:57:59 +0000 (22:57 +0100)
languages from the Interop/SMPTE metadata dialogues.

16 files changed:
src/lib/film.cc
src/lib/film.h
src/lib/isdcf_metadata.cc
src/lib/isdcf_metadata.h
src/lib/reel_writer.cc
src/lib/subtitle_encoder.cc
src/wx/interop_metadata_dialog.cc
src/wx/interop_metadata_dialog.h
src/wx/isdcf_metadata_dialog.cc
src/wx/isdcf_metadata_dialog.h
src/wx/language_tag_dialog.cc
src/wx/language_tag_dialog.h
src/wx/language_tag_widget.cc
src/wx/language_tag_widget.h
src/wx/smpte_metadata_dialog.cc
src/wx/smpte_metadata_dialog.h

index 3d822c5..9943711 100644 (file)
@@ -488,6 +488,9 @@ Film::metadata (bool with_content_paths) const
        root->add_child("LuminanceUnit")->add_child_text(dcp::Luminance::unit_to_string(_luminance.unit()));
        root->add_child("UserExplicitContainer")->add_child_text(_user_explicit_container ? "1" : "0");
        root->add_child("UserExplicitResolution")->add_child_text(_user_explicit_resolution ? "1" : "0");
+       BOOST_FOREACH (dcp::LanguageTag i, _subtitle_languages) {
+               root->add_child("SubtitleLanguage")->add_child_text(i.to_string());
+       }
        _playlist->as_xml (root->add_child ("Playlist"), with_content_paths);
 
        return doc;
@@ -671,6 +674,10 @@ Film::read_metadata (optional<boost::filesystem::path> path)
        _user_explicit_container = f.optional_bool_child("UserExplicitContainer").get_value_or(true);
        _user_explicit_resolution = f.optional_bool_child("UserExplicitResolution").get_value_or(true);
 
+       BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("SubtitleLanguage")) {
+               _subtitle_languages.push_back (dcp::LanguageTag(i->content()));
+       }
+
        list<string> notes;
        _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes);
 
@@ -863,39 +870,27 @@ Film::isdcf_name (bool if_created_now) const
                   for now I'm just appending -CCAP if we have any closed captions.
                */
 
-               optional<string> subtitle_language;
                bool burnt_in = true;
                bool ccap = false;
                BOOST_FOREACH (shared_ptr<Content> i, content()) {
                        BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
-                               if (j->type() == TEXT_OPEN_SUBTITLE && j->use()) {
-                                       subtitle_language = j->language ();
-                                       if (!j->burn()) {
-                                               burnt_in = false;
-                                       }
+                               if (j->type() == TEXT_OPEN_SUBTITLE && j->use() && !j->burn()) {
+                                       burnt_in = false;
                                } else if (j->type() == TEXT_CLOSED_CAPTION && j->use()) {
                                        ccap = true;
                                }
                        }
                }
 
-               if (dm.subtitle_language) {
-                       /* Subtitle language is overridden in ISDCF metadata, primarily to handle
-                          content with pre-burnt subtitles.
-                       */
-                       d += "-" + *dm.subtitle_language;
-                       if (ccap) {
-                               d += "-CCAP";
-                       }
-               } else if (subtitle_language) {
-                       /* Language is worked out from the content */
-                       if (burnt_in && *subtitle_language != "XX") {
-                               transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::tolower);
+               if (!_subtitle_languages.empty()) {
+                       string lang = _subtitle_languages.front().language().get_value_or("en").subtag();
+                       if (burnt_in) {
+                               transform (lang.begin(), lang.end(), lang.begin(), ::tolower);
                        } else {
-                               transform (subtitle_language->begin(), subtitle_language->end(), subtitle_language->begin(), ::toupper);
+                               transform (lang.begin(), lang.end(), lang.begin(), ::toupper);
                        }
 
-                       d += "-" + *subtitle_language;
+                       d += "-" + lang;
                        if (ccap) {
                                d += "-CCAP";
                        }
@@ -1684,29 +1679,6 @@ Film::should_be_enough_disk_space (double& required, double& available, bool& ca
        return (available - required) > 1;
 }
 
-string
-Film::subtitle_language () const
-{
-       set<string> languages;
-
-       BOOST_FOREACH (shared_ptr<Content> i, content()) {
-               BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
-                       languages.insert (j->language ());
-               }
-       }
-
-       string all;
-       BOOST_FOREACH (string s, languages) {
-               if (!all.empty ()) {
-                       all += "/" + s;
-               } else {
-                       all += s;
-               }
-       }
-
-       return all;
-}
-
 /** @return The names of the channels that audio contents' outputs are passed into;
  *  this is either the DCP or a AudioProcessor.
  */
@@ -2011,6 +1983,31 @@ Film::set_luminance (dcp::Luminance l)
 }
 
 
+void
+Film::set_subtitle_language (dcp::LanguageTag language)
+{
+       vector<dcp::LanguageTag> lang;
+       lang.push_back (language);
+       set_subtitle_languages (lang);
+}
+
+
+void
+Film::unset_subtitle_language ()
+{
+       ChangeSignaller<Film> ch (this, SUBTITLE_LANGUAGES);
+       _subtitle_languages.clear();
+}
+
+
+void
+Film::set_subtitle_languages (vector<dcp::LanguageTag> languages)
+{
+       ChangeSignaller<Film> ch (this, SUBTITLE_LANGUAGES);
+       _subtitle_languages = languages;
+}
+
+
 void
 Film::set_facility (string f)
 {
index 4854d2a..4c71c9e 100644 (file)
@@ -175,8 +175,6 @@ public:
                return _state_version;
        }
 
-       std::string subtitle_language () const;
-
        std::vector<NamedChannel> audio_output_names () const;
 
        void repeat_content (ContentList, int);
@@ -240,7 +238,8 @@ public:
                CHAIN,
                DISTRIBUTOR,
                FACILITY,
-               LUMINANCE
+               LUMINANCE,
+               SUBTITLE_LANGUAGES
        };
 
 
@@ -378,6 +377,10 @@ public:
                return _luminance;
        }
 
+       std::vector<dcp::LanguageTag> subtitle_languages () const {
+               return _subtitle_languages;
+       }
+
        /* SET */
 
        void set_directory (boost::filesystem::path);
@@ -419,6 +422,9 @@ public:
        void set_facility (std::string f);
        void set_distributor (std::string d);
        void set_luminance (dcp::Luminance l);
+       void set_subtitle_language (dcp::LanguageTag language);
+       void unset_subtitle_language ();
+       void set_subtitle_languages (std::vector<dcp::LanguageTag> languages);
 
        void add_ffoc_lfoc (Markers& markers) const;
 
@@ -524,6 +530,7 @@ private:
        std::string _distributor;
        std::string _facility;
        dcp::Luminance _luminance;
+       std::vector<dcp::LanguageTag> _subtitle_languages;
 
        int _state_version;
 
index f4b2566..e117dc2 100644 (file)
@@ -36,7 +36,6 @@ using dcp::raw_convert;
 ISDCFMetadata::ISDCFMetadata (cxml::ConstNodePtr node)
        : content_version (node->number_child<int> ("ContentVersion"))
        , audio_language (node->string_child ("AudioLanguage"))
-       , subtitle_language (node->optional_string_child("SubtitleLanguage"))
        , territory (node->string_child ("Territory"))
        , rating (node->string_child ("Rating"))
        , studio (node->string_child ("Studio"))
@@ -56,9 +55,6 @@ void
 ISDCFMetadata::as_xml (xmlpp::Node* root) const
 {
        root->add_child("ContentVersion")->add_child_text (raw_convert<string> (content_version));
-       if (subtitle_language) {
-               root->add_child("SubtitleLanguage")->add_child_text (*subtitle_language);
-       }
        root->add_child("AudioLanguage")->add_child_text (audio_language);
        root->add_child("Territory")->add_child_text (territory);
        root->add_child("Rating")->add_child_text (rating);
@@ -76,7 +72,6 @@ bool
 operator== (ISDCFMetadata const & a, ISDCFMetadata const & b)
 {
        return a.content_version == b.content_version &&
-              a.subtitle_language == b.subtitle_language &&
                a.audio_language == b.audio_language &&
                a.territory == b.territory &&
                a.rating == b.rating &&
index f54565f..0c70fb6 100644 (file)
@@ -46,8 +46,6 @@ public:
 
        int content_version;
        std::string audio_language;
-       /** if set, this overrides any languages specified in individual Content objects */
-       boost::optional<std::string> subtitle_language;
        std::string territory;
        std::string rating;
        std::string studio;
index 0ea4d15..a927770 100644 (file)
@@ -685,12 +685,12 @@ ReelWriter::write (PlayerText subs, TextType type, optional<DCPTextTrack> track,
        }
 
        if (!asset) {
-               string lang = _film->subtitle_language ();
+               vector<dcp::LanguageTag> lang = _film->subtitle_languages ();
                if (_film->interop ()) {
                        shared_ptr<dcp::InteropSubtitleAsset> s (new dcp::InteropSubtitleAsset ());
                        s->set_movie_title (_film->name ());
                        if (type == TEXT_OPEN_SUBTITLE) {
-                               s->set_language (lang.empty() ? "Unknown" : lang);
+                               s->set_language (lang.empty() ? "Unknown" : lang.front().to_string());
                        } else {
                                s->set_language (track->language);
                        }
@@ -701,7 +701,7 @@ ReelWriter::write (PlayerText subs, TextType type, optional<DCPTextTrack> track,
                        s->set_content_title_text (_film->name ());
                        s->set_metadata (mxf_metadata());
                        if (type == TEXT_OPEN_SUBTITLE && !lang.empty()) {
-                               s->set_language (lang);
+                               s->set_language (lang.front().to_string());
                        } else {
                                s->set_language (track->language);
                        }
index 19241bd..5e76f5e 100644 (file)
@@ -130,18 +130,18 @@ SubtitleEncoder::text (PlayerText subs, TextType type, optional<DCPTextTrack> tr
 
        if (!_assets[_reel_index].first) {
                shared_ptr<dcp::SubtitleAsset> asset;
-               string lang = _film->subtitle_language ();
+               vector<dcp::LanguageTag> lang = _film->subtitle_languages ();
                if (_film->interop ()) {
                        shared_ptr<dcp::InteropSubtitleAsset> s (new dcp::InteropSubtitleAsset());
                        s->set_movie_title (_film->name());
-                       s->set_language (lang.empty() ? "Unknown" : lang);
+                       s->set_language (lang.empty() ? "Unknown" : lang.front().to_string());
                        s->set_reel_number (raw_convert<string>(_reel_index + 1));
                        _assets[_reel_index].first = s;
                } else {
                        shared_ptr<dcp::SMPTESubtitleAsset> s (new dcp::SMPTESubtitleAsset());
                        s->set_content_title_text (_film->name());
                        if (!lang.empty()) {
-                               s->set_language (lang);
+                               s->set_language (lang.front().to_string());
                        } else {
                                s->set_language (track->language);
                        }
index 186e9bb..5555bf5 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2019 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -20,6 +20,7 @@
 
 #include "interop_metadata_dialog.h"
 #include "editable_list.h"
+#include "language_tag_widget.h"
 #include "rating_dialog.h"
 #include "lib/film.h"
 #include <dcp/types.h>
@@ -54,6 +55,16 @@ InteropMetadataDialog::InteropMetadataDialog (wxWindow* parent, weak_ptr<Film> f
        wxFlexGridSizer* sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        sizer->AddGrowableCol (1, 1);
 
+       shared_ptr<Film> f = _film.lock();
+       DCPOMATIC_ASSERT (f);
+
+       _enable_subtitle_language = new wxCheckBox (this, wxID_ANY, _("Subtitle language"));
+       sizer->Add (_enable_subtitle_language, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
+       vector<dcp::LanguageTag> langs = f->subtitle_languages ();
+       _enable_subtitle_language->SetValue (!langs.empty());
+       _subtitle_language = new LanguageTagWidget (this, wxT(""), langs.empty() ? dcp::LanguageTag("en-US") : langs.front());
+       sizer->Add (_subtitle_language->sizer(), 1, wxEXPAND);
+
        {
                int flags = wxALIGN_TOP | wxLEFT | wxRIGHT | wxTOP;
 #ifdef __WXOSX__
@@ -81,8 +92,6 @@ InteropMetadataDialog::InteropMetadataDialog (wxWindow* parent, weak_ptr<Film> f
        _content_version = new wxTextCtrl (this, wxID_ANY);
        sizer->Add (_content_version, 1, wxEXPAND);
 
-       shared_ptr<Film> f = _film.lock();
-       DCPOMATIC_ASSERT (f);
        vector<string> cv = f->content_versions();
        _content_version->SetValue (std_to_wx(cv.empty() ? "" : cv[0]));
 
@@ -96,10 +105,41 @@ InteropMetadataDialog::InteropMetadataDialog (wxWindow* parent, weak_ptr<Film> f
        overall_sizer->Layout ();
        overall_sizer->SetSizeHints (this);
 
+       _enable_subtitle_language->Bind (wxEVT_CHECKBOX, boost::bind(&InteropMetadataDialog::setup_sensitivity, this));
+       _subtitle_language->Changed.connect (boost::bind(&InteropMetadataDialog::subtitle_language_changed, this, _1));
+
        _content_version->Bind (wxEVT_TEXT, boost::bind(&InteropMetadataDialog::content_version_changed, this));
        _content_version->SetFocus ();
+
+       setup_sensitivity ();
 }
 
+
+void
+InteropMetadataDialog::setup_sensitivity ()
+{
+       bool const enabled = _enable_subtitle_language->GetValue();
+       _subtitle_language->enable (enabled);
+
+       shared_ptr<Film> film = _film.lock ();
+       DCPOMATIC_ASSERT (film);
+       if (enabled) {
+               film->set_subtitle_language (_subtitle_language->get());
+       } else {
+               film->unset_subtitle_language ();
+       }
+}
+
+
+void
+InteropMetadataDialog::subtitle_language_changed (dcp::LanguageTag language)
+{
+       shared_ptr<Film> film = _film.lock ();
+       DCPOMATIC_ASSERT (film);
+       film->set_subtitle_language (language);
+}
+
+
 vector<dcp::Rating>
 InteropMetadataDialog::ratings () const
 {
index 43d028e..189e28e 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2019 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -19,6 +19,7 @@
 */
 
 #include "editable_list.h"
+#include <dcp/language_tag.h>
 #include <dcp/types.h>
 #include <wx/wx.h>
 #include <boost/shared_ptr.hpp>
 #include <vector>
 
 class Film;
+class LanguageTagWidget;
 class RatingDialog;
 
+
 class InteropMetadataDialog : public wxDialog
 {
 public:
@@ -37,8 +40,12 @@ private:
        std::vector<dcp::Rating> ratings () const;
        void set_ratings (std::vector<dcp::Rating> r);
        void content_version_changed ();
+       void setup_sensitivity ();
+       void subtitle_language_changed (dcp::LanguageTag tag);
 
        boost::weak_ptr<Film> _film;
+       wxCheckBox* _enable_subtitle_language;
+       LanguageTagWidget* _subtitle_language;
        EditableList<dcp::Rating, RatingDialog>* _ratings;
        wxTextCtrl* _content_version;
 };
index 32f994d..652b85d 100644 (file)
@@ -41,16 +41,6 @@ ISDCFMetadataDialog::ISDCFMetadataDialog (wxWindow* parent, ISDCFMetadata dm, bo
        add (_("Audio Language (e.g. EN)"), true);
        _audio_language = add (new wxTextCtrl (this, wxID_ANY));
 
-       _enable_subtitle_language = add (new wxCheckBox(this, wxID_ANY, _("Subtitle language (e.g. FR)")));
-       _subtitle_language = add (new wxTextCtrl(this, wxID_ANY));
-
-       wxStaticText* subtitle_note = add (_("(use this to override languages specified\nin the 'timed text' tab)"), false);
-       wxFont font = subtitle_note->GetFont();
-       font.SetStyle (wxFONTSTYLE_ITALIC);
-       font.SetPointSize (font.GetPointSize() - 1);
-       subtitle_note->SetFont (font);
-       add_spacer ();
-
        add (_("Territory (e.g. UK)"), true);
        _territory = add (new wxTextCtrl (this, wxID_ANY));
 
@@ -89,8 +79,6 @@ ISDCFMetadataDialog::ISDCFMetadataDialog (wxWindow* parent, ISDCFMetadata dm, bo
 
        _content_version->SetValue (dm.content_version);
        _audio_language->SetValue (std_to_wx (dm.audio_language));
-       _enable_subtitle_language->SetValue (static_cast<bool>(dm.subtitle_language));
-       _subtitle_language->SetValue (std_to_wx(dm.subtitle_language.get_value_or("")));
        _territory->SetValue (std_to_wx (dm.territory));
        _rating->SetValue (std_to_wx (dm.rating));
        _studio->SetValue (std_to_wx (dm.studio));
@@ -102,20 +90,11 @@ ISDCFMetadataDialog::ISDCFMetadataDialog (wxWindow* parent, ISDCFMetadata dm, bo
        _two_d_version_of_three_d->SetValue (dm.two_d_version_of_three_d);
        _mastered_luminance->SetValue (std_to_wx (dm.mastered_luminance));
 
-       _enable_subtitle_language->Bind (wxEVT_CHECKBOX, boost::bind(&ISDCFMetadataDialog::setup_sensitivity, this));
-
-       setup_sensitivity ();
-
        layout ();
 
        _content_version->SetFocus ();
 }
 
-void
-ISDCFMetadataDialog::setup_sensitivity ()
-{
-       _subtitle_language->Enable (_enable_subtitle_language->GetValue());
-}
 
 ISDCFMetadata
 ISDCFMetadataDialog::isdcf_metadata () const
@@ -124,9 +103,6 @@ ISDCFMetadataDialog::isdcf_metadata () const
 
        dm.content_version = _content_version->GetValue ();
        dm.audio_language = wx_to_std (_audio_language->GetValue ());
-       if (_enable_subtitle_language->GetValue()) {
-               dm.subtitle_language = wx_to_std (_subtitle_language->GetValue());
-       }
        dm.territory = wx_to_std (_territory->GetValue ());
        dm.rating = wx_to_std (_rating->GetValue ());
        dm.studio = wx_to_std (_studio->GetValue ());
index 335c29a..b1ecb5a 100644 (file)
@@ -34,12 +34,8 @@ public:
        ISDCFMetadata isdcf_metadata () const;
 
 private:
-       void setup_sensitivity ();
-
        wxSpinCtrl* _content_version;
        wxTextCtrl* _audio_language;
-       wxCheckBox* _enable_subtitle_language;
-       wxTextCtrl* _subtitle_language;
        wxTextCtrl* _territory;
        wxTextCtrl* _rating;
        wxTextCtrl* _studio;
index 1c3ab2f..94e266f 100644 (file)
@@ -224,18 +224,7 @@ LanguageTagDialog::LanguageTagDialog (wxWindow* parent, dcp::LanguageTag tag)
 
        SetSizerAndFit (overall_sizer);
 
-       bool have_language = false;
-       vector<pair<dcp::LanguageTag::SubtagType, dcp::LanguageTag::SubtagData> > subtags = tag.subtags();
-       for (vector<pair<dcp::LanguageTag::SubtagType, dcp::LanguageTag::SubtagData> >::const_iterator i = subtags.begin(); i != subtags.end(); ++i) {
-               add_to_current_tag (i->first, i->second);
-               if (i->first == dcp::LanguageTag::LANGUAGE) {
-                       have_language = true;
-               }
-       }
-
-       if (!have_language) {
-               add_to_current_tag (dcp::LanguageTag::LANGUAGE, dcp::LanguageTag::SubtagData("en", "English"));
-       }
+       set (tag);
 
        _add_script->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::SCRIPT, boost::optional<dcp::LanguageTag::SubtagData>()));
        _add_region->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::REGION, boost::optional<dcp::LanguageTag::SubtagData>()));
@@ -303,6 +292,27 @@ dcp::LanguageTag LanguageTagDialog::get () const
 }
 
 
+void
+LanguageTagDialog::set (dcp::LanguageTag tag)
+{
+       _current_tag_subtags.clear ();
+       _current_tag_list->DeleteAllItems ();
+
+       bool have_language = false;
+       vector<pair<dcp::LanguageTag::SubtagType, dcp::LanguageTag::SubtagData> > subtags = tag.subtags();
+       for (vector<pair<dcp::LanguageTag::SubtagType, dcp::LanguageTag::SubtagData> >::const_iterator i = subtags.begin(); i != subtags.end(); ++i) {
+               add_to_current_tag (i->first, i->second);
+               if (i->first == dcp::LanguageTag::LANGUAGE) {
+                       have_language = true;
+               }
+       }
+
+       if (!have_language) {
+               add_to_current_tag (dcp::LanguageTag::LANGUAGE, dcp::LanguageTag::SubtagData("en", "English"));
+       }
+}
+
+
 string LanguageTagDialog::subtag_type_name (dcp::LanguageTag::SubtagType type)
 {
        switch (type) {
index cd6f2c8..705359d 100644 (file)
 */
 
 
+#ifndef DCPOMATIC_LANGUAGE_TAG_DIALOG_H
+#define DCPOMATIC_LANGUAGE_TAG_DIALOG_H
+
+
 #include "lib/warnings.h"
 #include <dcp/language_tag.h>
 DCPOMATIC_DISABLE_WARNINGS
@@ -46,10 +50,10 @@ public:
                std::string last_search;
        };
 
-       LanguageTagDialog (wxWindow* parent, dcp::LanguageTag tag);
+       LanguageTagDialog (wxWindow* parent, dcp::LanguageTag tag = dcp::LanguageTag("en"));
 
        dcp::LanguageTag get () const;
-
+       void set (dcp::LanguageTag tag);
 
 private:
 
@@ -84,3 +88,5 @@ private:
        LanguageSubtagPanel* _panel;
 };
 
+
+#endif
index f2f59f6..38c2c59 100644 (file)
@@ -58,3 +58,11 @@ LanguageTagWidget::set (dcp::LanguageTag tag)
        _tag = tag;
        checked_set (_language, std_to_wx(tag.to_string()));
 }
+
+
+void
+LanguageTagWidget::enable (bool e)
+{
+       _language->Enable (e);
+       _edit->Enable (e);
+}
index 3cfca01..336f7dc 100644 (file)
@@ -40,7 +40,11 @@ public:
                return _sizer;
        }
 
+       dcp::LanguageTag get () const {
+               return _tag;
+       }
        void set (dcp::LanguageTag tag);
+       void enable (bool e);
 
        boost::signals2::signal<void (dcp::LanguageTag)> Changed;
 
index 3011cb2..156f82a 100644 (file)
@@ -39,6 +39,13 @@ using namespace boost::placeholders;
 #endif
 
 
+static string
+additional_subtitle_language_column (dcp::LanguageTag r, int)
+{
+       return r.to_string();
+}
+
+
 static string
 ratings_column (dcp::Rating r, int c)
 {
@@ -83,6 +90,38 @@ SMPTEMetadataDialog::SMPTEMetadataDialog (wxWindow* parent, weak_ptr<Film> weak_
                );
        sizer->Add (_audio_language->sizer(), 0, wxEXPAND);
 
+       _enable_main_subtitle_language = new wxCheckBox (this, wxID_ANY, _("Main subtitle language"));
+       sizer->Add (_enable_main_subtitle_language, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
+       vector<dcp::LanguageTag> subtitle_languages = film()->subtitle_languages();
+       _main_subtitle_language = new LanguageTagWidget(
+               this,
+               _("The main language that is displayed in the film's subtitles"),
+               subtitle_languages.empty() ? dcp::LanguageTag("en-US") : subtitle_languages.front()
+               );
+       sizer->Add (_main_subtitle_language->sizer(), 0, wxEXPAND);
+
+       {
+               int flags = wxALIGN_TOP | wxLEFT | wxRIGHT | wxTOP;
+#ifdef __WXOSX__
+               flags |= wxALIGN_RIGHT;
+#endif
+               wxStaticText* m = create_label (this, _("Additional subtitle languages"), true);
+               sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP);
+       }
+
+       vector<EditableListColumn> columns;
+       columns.push_back (EditableListColumn("Language", 250, true));
+       _additional_subtitle_languages = new EditableList<dcp::LanguageTag, LanguageTagDialog> (
+               this,
+               columns,
+               boost::bind(&SMPTEMetadataDialog::additional_subtitle_languages, this),
+               boost::bind(&SMPTEMetadataDialog::set_additional_subtitle_languages, this, _1),
+               boost::bind(&additional_subtitle_language_column, _1, _2),
+               true,
+               false
+               );
+       sizer->Add (_additional_subtitle_languages, 1, wxEXPAND);
+
        Button* edit_release_territory = 0;
        add_label_to_sizer (sizer, this, _("Release territory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
        {
@@ -135,7 +174,7 @@ SMPTEMetadataDialog::SMPTEMetadataDialog (wxWindow* parent, weak_ptr<Film> weak_
                sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP);
        }
 
-       vector<EditableListColumn> columns;
+       columns.clear ();
        columns.push_back (EditableListColumn("Agency", 200, true));
        columns.push_back (EditableListColumn("Label", 50, true));
        _ratings = new EditableList<dcp::Rating, RatingDialog> (
@@ -190,6 +229,8 @@ SMPTEMetadataDialog::SMPTEMetadataDialog (wxWindow* parent, weak_ptr<Film> weak_
 
        _name_language->Changed.connect (boost::bind(&SMPTEMetadataDialog::name_language_changed, this, _1));
        _audio_language->Changed.connect (boost::bind(&SMPTEMetadataDialog::audio_language_changed, this, _1));
+       _enable_main_subtitle_language->Bind (wxEVT_CHECKBOX, boost::bind(&SMPTEMetadataDialog::enable_main_subtitle_changed, this));
+       _main_subtitle_language->Changed.connect (boost::bind(&SMPTEMetadataDialog::main_subtitle_language_changed, this, _1));
        edit_release_territory->Bind (wxEVT_BUTTON, boost::bind(&SMPTEMetadataDialog::edit_release_territory, this));
        _version_number->Bind (wxEVT_SPINCTRL, boost::bind(&SMPTEMetadataDialog::version_number_changed, this));
        _status->Bind (wxEVT_CHOICE, boost::bind(&SMPTEMetadataDialog::status_changed, this));
@@ -212,6 +253,9 @@ SMPTEMetadataDialog::SMPTEMetadataDialog (wxWindow* parent, weak_ptr<Film> weak_
        film_changed (CHANGE_TYPE_DONE, Film::FACILITY);
        film_changed (CHANGE_TYPE_DONE, Film::CONTENT_VERSIONS);
        film_changed (CHANGE_TYPE_DONE, Film::LUMINANCE);
+       film_changed (CHANGE_TYPE_DONE, Film::SUBTITLE_LANGUAGES);
+
+       setup_sensitivity ();
 }
 
 
@@ -256,6 +300,14 @@ SMPTEMetadataDialog::film_changed (ChangeType type, Film::Property property)
                        checked_set (_luminance_unit, 1);
                        break;
                }
+       } else if (property == Film::SUBTITLE_LANGUAGES) {
+               vector<dcp::LanguageTag> languages = film()->subtitle_languages();
+               checked_set (_enable_main_subtitle_language, !languages.empty());
+               if (!languages.empty()) {
+                       _main_subtitle_language->set (languages.front());
+               } else {
+                       _main_subtitle_language->set (dcp::LanguageTag("en-US"));
+               }
        }
 }
 
@@ -386,3 +438,65 @@ SMPTEMetadataDialog::luminance_changed ()
 
        film()->set_luminance (dcp::Luminance(_luminance_value->GetValue(), unit));
 }
+
+
+void
+SMPTEMetadataDialog::enable_main_subtitle_changed ()
+{
+       setup_sensitivity ();
+       bool enabled = _enable_main_subtitle_language->GetValue ();
+       if (enabled) {
+               film()->set_subtitle_language (_main_subtitle_language->get());
+       } else {
+               set_additional_subtitle_languages (vector<dcp::LanguageTag>());
+               _additional_subtitle_languages->refresh ();
+               film()->unset_subtitle_language ();
+       }
+}
+
+
+void
+SMPTEMetadataDialog::setup_sensitivity ()
+{
+       bool const enabled = _enable_main_subtitle_language->GetValue ();
+       _main_subtitle_language->enable (enabled);
+       _additional_subtitle_languages->Enable (enabled);
+}
+
+
+void
+SMPTEMetadataDialog::main_subtitle_language_changed (dcp::LanguageTag tag)
+{
+       vector<dcp::LanguageTag> existing = film()->subtitle_languages();
+       if (existing.empty()) {
+               existing.push_back (tag);
+       } else {
+               existing[0] = tag;
+       }
+
+       film()->set_subtitle_languages (existing);
+}
+
+
+vector<dcp::LanguageTag>
+SMPTEMetadataDialog::additional_subtitle_languages ()
+{
+       vector<dcp::LanguageTag> all = film()->subtitle_languages();
+       if (all.empty()) {
+               return all;
+       }
+
+       return vector<dcp::LanguageTag>(all.begin() + 1, all.end());
+}
+
+
+void
+SMPTEMetadataDialog::set_additional_subtitle_languages (vector<dcp::LanguageTag> languages)
+{
+       vector<dcp::LanguageTag> all = film()->subtitle_languages();
+       DCPOMATIC_ASSERT (!all.empty());
+       all.resize (1);
+       copy (languages.begin(), languages.end(), back_inserter(all));
+       film()->set_subtitle_languages (all);
+}
+
index e47ffe2..36039c5 100644 (file)
@@ -19,7 +19,9 @@
 */
 
 #include "editable_list.h"
+#include "language_tag_dialog.h"
 #include "lib/film.h"
+#include <dcp/language_tag.h>
 #include <dcp/types.h>
 #include <wx/wx.h>
 #include <boost/shared_ptr.hpp>
@@ -45,6 +47,10 @@ private:
        void set_content_versions (std::vector<std::string> v);
        void name_language_changed (dcp::LanguageTag tag);
        void audio_language_changed (dcp::LanguageTag tag);
+       void enable_main_subtitle_changed ();
+       void main_subtitle_language_changed (dcp::LanguageTag tag);
+       std::vector<dcp::LanguageTag> additional_subtitle_languages ();
+       void set_additional_subtitle_languages (std::vector<dcp::LanguageTag> languages);
        void edit_release_territory ();
        void version_number_changed ();
        void status_changed ();
@@ -53,11 +59,15 @@ private:
        void facility_changed ();
        void luminance_changed ();
        void film_changed (ChangeType type, Film::Property property);
+       void setup_sensitivity ();
        boost::shared_ptr<Film> film () const;
 
        boost::weak_ptr<Film> _film;
        LanguageTagWidget* _name_language;
        LanguageTagWidget* _audio_language;
+       wxCheckBox* _enable_main_subtitle_language;
+       LanguageTagWidget* _main_subtitle_language;
+       EditableList<dcp::LanguageTag, LanguageTagDialog>* _additional_subtitle_languages;
        wxStaticText* _release_territory;
        wxSpinCtrl* _version_number;
        wxChoice* _status;