diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-10-24 09:29:28 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-10-24 09:29:28 +0100 |
| commit | f0d7baf0ce956fe5461caa91868c41d881b5f0dc (patch) | |
| tree | 946d9fe2be68a6049ea4835d7edf825c491dd02c /src | |
| parent | 0e2c7f060529d93035e89b06d4aa687830a5e0ad (diff) | |
| parent | f28102477a712b8dde0f157d33b087d642c84555 (diff) | |
Merge 1.0.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/content.cc | 24 | ||||
| -rw-r--r-- | src/lib/content.h | 5 | ||||
| -rw-r--r-- | src/lib/content_factory.cc | 17 | ||||
| -rw-r--r-- | src/lib/content_factory.h | 1 | ||||
| -rw-r--r-- | src/lib/film.cc | 6 | ||||
| -rw-r--r-- | src/lib/film.h | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 4 | ||||
| -rw-r--r-- | src/lib/playlist.cc | 12 | ||||
| -rw-r--r-- | src/lib/playlist.h | 2 | ||||
| -rw-r--r-- | src/tools/dcpomatic.cc | 9 | ||||
| -rw-r--r-- | src/wx/content_menu.cc | 107 | ||||
| -rw-r--r-- | src/wx/content_menu.h | 9 | ||||
| -rw-r--r-- | src/wx/film_editor.cc | 36 | ||||
| -rw-r--r-- | src/wx/film_viewer.cc | 4 | ||||
| -rw-r--r-- | src/wx/wscript | 1 | ||||
| -rw-r--r-- | src/wx/wx_util.h | 3 |
16 files changed, 199 insertions, 43 deletions
diff --git a/src/lib/content.cc b/src/lib/content.cc index dbb841200..e3ad42560 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -31,10 +31,11 @@ using std::set; using boost::shared_ptr; using boost::lexical_cast; -int const ContentProperty::POSITION = 400; -int const ContentProperty::LENGTH = 401; -int const ContentProperty::TRIM_START = 402; -int const ContentProperty::TRIM_END = 403; +int const ContentProperty::PATH = 400; +int const ContentProperty::POSITION = 401; +int const ContentProperty::LENGTH = 402; +int const ContentProperty::TRIM_START = 403; +int const ContentProperty::TRIM_END = 404; Content::Content (shared_ptr<const Film> f, Time p) : _film (f) @@ -191,3 +192,18 @@ Content::identifier () const return s.str (); } + +bool +Content::path_valid () const +{ + return boost::filesystem::exists (_path); +} + +void +Content::set_path (boost::filesystem::path path) +{ + _path = path; + signal_changed (ContentProperty::PATH); +} + + diff --git a/src/lib/content.h b/src/lib/content.h index 9c7ad2fc2..c066c61e0 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -38,6 +38,7 @@ class Film; class ContentProperty { public: + static int const PATH; static int const POSITION; static int const LENGTH; static int const TRIM_START; @@ -61,12 +62,16 @@ public: virtual std::string identifier () const; boost::shared_ptr<Content> clone () const; + + void set_path (boost::filesystem::path); boost::filesystem::path path () const { boost::mutex::scoped_lock lm (_mutex); return _path; } + bool path_valid () const; + /** @return MD5 digest of the content's file(s) */ std::string digest () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/content_factory.cc b/src/lib/content_factory.cc index 6ed01f174..d42491f7f 100644 --- a/src/lib/content_factory.cc +++ b/src/lib/content_factory.cc @@ -22,6 +22,7 @@ #include "still_image_content.h" #include "moving_image_content.h" #include "sndfile_content.h" +#include "util.h" using std::string; using boost::shared_ptr; @@ -45,3 +46,19 @@ content_factory (shared_ptr<const Film> film, shared_ptr<cxml::Node> node) return content; } + +shared_ptr<Content> +content_factory (shared_ptr<const Film> film, boost::filesystem::path path) +{ + shared_ptr<Content> content; + + if (valid_image_file (path)) { + content.reset (new StillImageContent (film, path)); + } else if (SndfileContent::valid_file (path)) { + content.reset (new SndfileContent (film, path)); + } else { + content.reset (new FFmpegContent (film, path)); + } + + return content; +} diff --git a/src/lib/content_factory.h b/src/lib/content_factory.h index 27cd36024..93fd98d83 100644 --- a/src/lib/content_factory.h +++ b/src/lib/content_factory.h @@ -20,3 +20,4 @@ class Film; extern boost::shared_ptr<Content> content_factory (boost::shared_ptr<const Film>, boost::shared_ptr<cxml::Node>); +extern boost::shared_ptr<Content> content_factory (boost::shared_ptr<const Film>, boost::filesystem::path); diff --git a/src/lib/film.cc b/src/lib/film.cc index f869289d5..650163efe 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -844,6 +844,12 @@ Film::best_video_frame_rate () const return _playlist->best_dcp_frame_rate (); } +bool +Film::content_paths_valid () const +{ + return _playlist->content_paths_valid (); +} + void Film::playlist_content_changed (boost::weak_ptr<Content> c, int p) { diff --git a/src/lib/film.h b/src/lib/film.h index 8cfc49088..6bd04572b 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -111,10 +111,10 @@ public: /* Proxies for some Playlist methods */ ContentList content () const; - Time length () const; bool has_subtitles () const; OutputVideoFrame best_video_frame_rate () const; + bool content_paths_valid () const; libdcp::KDM make_kdm ( diff --git a/src/lib/player.cc b/src/lib/player.cc index 73c873c59..02d390365 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -537,6 +537,10 @@ Player::content_changed (weak_ptr<Content> w, int property, bool frequent) ) { Changed (frequent); + + } else if (property == ContentProperty::PATH) { + + Changed (frequent); } } diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 1712dc8ff..621b99dd7 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -390,3 +390,15 @@ Playlist::move_later (shared_ptr<Content> c) Changed (); } + +bool +Playlist::content_paths_valid () const +{ + for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) { + if (!(*i)->path_valid ()) { + return false; + } + } + + return true; +} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 05928ee57..a1ae9b151 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -80,6 +80,8 @@ public: void repeat (ContentList, int); + bool content_paths_valid () const; + mutable boost::signals2::signal<void ()> Changed; /** Third parameter is true if signals are currently being emitted frequently */ mutable boost::signals2::signal<void (boost::weak_ptr<Content>, int, bool)> ContentChanged; diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 8d1ebf5d3..4972654b2 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -501,21 +501,12 @@ private: } }; -#if wxMINOR_VERSION == 9 static const wxCmdLineEntryDesc command_line_description[] = { { wxCMD_LINE_OPTION, "l", "log", "set log level (silent, verbose or timing)", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_SWITCH, "n", "new", "create new film", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_PARAM, 0, 0, "film to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 } }; -#else -static const wxCmdLineEntryDesc command_line_description[] = { - { wxCMD_LINE_OPTION, wxT("l"), wxT("log"), wxT("set log level (silent, verbose or timing)"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_SWITCH, wxT("n"), wxT("new"), wxT("create new film"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_PARAM, 0, 0, wxT("film to load or create"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_NONE, wxT(""), wxT(""), wxT(""), wxCmdLineParamType (0), 0 } -}; -#endif class App : public wxApp { diff --git a/src/wx/content_menu.cc b/src/wx/content_menu.cc index 60a95a9f2..6183e3444 100644 --- a/src/wx/content_menu.cc +++ b/src/wx/content_menu.cc @@ -18,16 +18,25 @@ */ #include <wx/wx.h> +#include <wx/dirdlg.h> #include "lib/playlist.h" #include "lib/film.h" +#include "lib/moving_image_content.h" +#include "lib/content_factory.h" +#include "lib/examine_content_job.h" +#include "lib/job_manager.h" #include "content_menu.h" #include "repeat_dialog.h" +#include "wx_util.h" using std::cout; using boost::shared_ptr; +using boost::weak_ptr; +using boost::dynamic_pointer_cast; enum { ID_repeat = 1, + ID_find_missing, ID_remove }; @@ -36,12 +45,14 @@ ContentMenu::ContentMenu (shared_ptr<Film> f, wxWindow* p) , _film (f) , _parent (p) { - _menu->Append (ID_repeat, _("Repeat...")); + _repeat = _menu->Append (ID_repeat, _("Repeat...")); + _find_missing = _menu->Append (ID_find_missing, _("Find missing...")); _menu->AppendSeparator (); - _menu->Append (ID_remove, _("Remove")); + _remove = _menu->Append (ID_remove, _("Remove")); - _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, &ContentMenu::repeat, this, ID_repeat); - _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, &ContentMenu::remove, this, ID_remove); + _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&ContentMenu::repeat, this), ID_repeat); + _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&ContentMenu::find_missing, this), ID_find_missing); + _parent->Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&ContentMenu::remove, this), ID_remove); } ContentMenu::~ContentMenu () @@ -53,32 +64,38 @@ void ContentMenu::popup (ContentList c, wxPoint p) { _content = c; + _repeat->Enable (!_content.empty ()); + _find_missing->Enable (_content.size() == 1 && !_content.front()->path_valid ()); + _remove->Enable (!_content.empty ()); _parent->PopupMenu (_menu, p); } void -ContentMenu::repeat (wxCommandEvent &) +ContentMenu::repeat () { if (_content.empty ()) { return; } - RepeatDialog d (_parent); - d.ShowModal (); + RepeatDialog* d = new RepeatDialog (_parent); + if (d->ShowModal() != wxID_OK) { + d->Destroy (); + return; + } shared_ptr<const Film> film = _film.lock (); if (!film) { return; } - film->playlist()->repeat (_content, d.number ()); - d.Destroy (); + film->playlist()->repeat (_content, d->number ()); + d->Destroy (); _content.clear (); } void -ContentMenu::remove (wxCommandEvent &) +ContentMenu::remove () { if (_content.empty ()) { return; @@ -94,3 +111,73 @@ ContentMenu::remove (wxCommandEvent &) _content.clear (); } +void +ContentMenu::find_missing () +{ + if (_content.size() != 1) { + return; + } + + shared_ptr<const Film> film = _film.lock (); + if (!film) { + return; + } + + shared_ptr<Content> content; + + /* XXX: a bit nasty */ + if (dynamic_pointer_cast<MovingImageContent> (_content.front ())) { + wxDirDialog* d = new wxDirDialog (0, _("Choose a folder"), wxT (""), wxDD_DIR_MUST_EXIST); + int const r = d->ShowModal (); + if (r == wxID_OK) { + content.reset (new MovingImageContent (film, boost::filesystem::path (wx_to_std (d->GetPath ())))); + } + d->Destroy (); + } else { + wxFileDialog* d = new wxFileDialog (0, _("Choose a file"), wxT (""), wxT (""), wxT ("*.*"), wxFD_MULTIPLE); + int const r = d->ShowModal (); + if (r == wxID_OK) { + content = content_factory (film, wx_to_std (d->GetPath ())); + } + d->Destroy (); + } + + if (!content) { + return; + } + + shared_ptr<Job> j (new ExamineContentJob (film, content)); + + j->Finished.connect ( + bind ( + &ContentMenu::maybe_found_missing, + this, + boost::weak_ptr<Job> (j), + boost::weak_ptr<Content> (_content.front ()), + boost::weak_ptr<Content> (content) + ) + ); + + JobManager::instance()->add (j); +} + +void +ContentMenu::maybe_found_missing (weak_ptr<Job> j, weak_ptr<Content> oc, weak_ptr<Content> nc) +{ + shared_ptr<Job> job = j.lock (); + if (!job || !job->finished_ok ()) { + return; + } + + shared_ptr<Content> old_content = oc.lock (); + shared_ptr<Content> new_content = nc.lock (); + assert (old_content); + assert (new_content); + + if (new_content->digest() != old_content->digest()) { + error_dialog (0, _("The content file(s) you specified are not the same as those that are missing. Either try again with the correct content file or remove the missing content.")); + return; + } + + old_content->set_path (new_content->path ()); +} diff --git a/src/wx/content_menu.h b/src/wx/content_menu.h index 127fbea1a..2a6725320 100644 --- a/src/wx/content_menu.h +++ b/src/wx/content_menu.h @@ -36,13 +36,18 @@ public: void popup (ContentList, wxPoint); private: - void repeat (wxCommandEvent &); - void remove (wxCommandEvent &); + void repeat (); + void find_missing (); + void remove (); + void maybe_found_missing (boost::weak_ptr<Job>, boost::weak_ptr<Content>, boost::weak_ptr<Content>); wxMenu* _menu; boost::weak_ptr<Film> _film; wxWindow* _parent; ContentList _content; + wxMenuItem* _repeat; + wxMenuItem* _find_missing; + wxMenuItem* _remove; }; #endif diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index f2514da51..1472c8b89 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -44,6 +44,8 @@ #include "lib/sound_processor.h" #include "lib/scaler.h" #include "lib/playlist.h" +#include "lib/content.h" +#include "lib/content_factory.h" #include "timecode.h" #include "wx_util.h" #include "film_editor.h" @@ -490,6 +492,8 @@ FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property) if (property == FFmpegContentProperty::AUDIO_STREAM) { setup_dcp_name (); + } else if (property == ContentProperty::PATH) { + setup_content (); } } @@ -705,10 +709,22 @@ FilmEditor::setup_content () ContentList content = _film->content (); for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { int const t = _content->GetItemCount (); - _content->InsertItem (t, std_to_wx ((*i)->summary ())); + bool const valid = (*i)->path_valid (); + + string s = (*i)->summary (); + if (!valid) { + s = _("MISSING: ") + s; + } + + _content->InsertItem (t, std_to_wx (s)); + if ((*i)->summary() == selected_summary) { _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); } + + if (!valid) { + _content->SetItemTextColour (t, *wxRED); + } } if (selected_summary.empty () && !content.empty ()) { @@ -734,19 +750,7 @@ FilmEditor::content_add_file_clicked () /* XXX: check for lots of files here and do something */ for (unsigned int i = 0; i < paths.GetCount(); ++i) { - boost::filesystem::path p (wx_to_std (paths[i])); - - shared_ptr<Content> c; - - if (valid_image_file (p)) { - c.reset (new StillImageContent (_film, p)); - } else if (SndfileContent::valid_file (p)) { - c.reset (new SndfileContent (_film, p)); - } else { - c.reset (new FFmpegContent (_film, p)); - } - - _film->examine_and_add_content (c); + _film->examine_and_add_content (content_factory (_film, wx_to_std (paths[i]))); } } @@ -916,7 +920,9 @@ void FilmEditor::content_right_click (wxListEvent& ev) { ContentList cl; - cl.push_back (selected_content ()); + if (selected_content ()) { + cl.push_back (selected_content ()); + } _menu.popup (cl, ev.GetPoint ()); } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index a1a47a943..03e8419a0 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -334,6 +334,10 @@ FilmViewer::fetch_next_frame () _play_button->SetValue (false); check_play_state (); error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data())); + } catch (OpenFileError& e) { + /* There was a problem opening a content file; we'll let this slide as it + probably means a missing content file, which we're already taking care of. + */ } _panel->Refresh (); diff --git a/src/wx/wscript b/src/wx/wscript index 8f35e2fac..09e783161 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -69,7 +69,6 @@ def build(bld): obj = bld(features = 'cxx cxxshlib') obj.name = 'libdcpomatic-wx' -# obj.includes = [ '..' ] obj.export_includes = ['..'] obj.uselib = 'WXWIDGETS' if bld.env.TARGET_LINUX: diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index aefa75fca..48683492c 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -85,9 +85,10 @@ extern void checked_set (wxRadioButton* widget, bool value); extern void checked_set (wxStaticText* widget, std::string value); /* GTK 2.24.17 has a buggy GtkFileChooserButton and it was put in Ubuntu 13.04. + This also seems to apply to 2.24.20 in Ubuntu 13.10 Use our own dir picker as this is the least bad option I can think of. */ -#if defined(__WXMSW__) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION == 24 && GTK_MICRO_VERSION == 17) +#if defined(__WXMSW__) || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION == 24 && (GTK_MICRO_VERSION == 17 || GTK_MICRO_VERSION == 20)) #define DCPOMATIC_USE_OWN_DIR_PICKER #endif |
