}
void
-AtmosMXFContent::as_xml (xmlpp::Node* node) const
+AtmosMXFContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("AtmosMXF");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
}
DCPTime
void examine (boost::shared_ptr<Job> job);
std::string summary () const;
- void as_xml (xmlpp::Node* node) const;
+ void as_xml (xmlpp::Node* node, bool with_path) const;
DCPTime full_length () const;
static bool valid_mxf (boost::filesystem::path path);
_parent->signal_changed (AudioContentProperty::STREAMS);
}
+
+void
+AudioContent::use_template (shared_ptr<const AudioContent> c)
+{
+ _gain = c->_gain;
+ _delay = c->_delay;
+
+ size_t i = 0;
+ size_t j = 0;
+
+ while (i < _streams.size() && j < c->_streams.size()) {
+ _streams[i]->set_mapping (c->_streams[j]->mapping());
+ ++i;
+ ++j;
+ }
+}
void as_xml (xmlpp::Node *) const;
std::string technical_summary () const;
+ void use_template (boost::shared_ptr<const AudioContent> c);
AudioMapping mapping () const;
void set_mapping (AudioMapping);
#include "cinema.h"
#include "util.h"
#include "cross.h"
+#include "film.h"
#include <dcp/raw_convert.h>
#include <dcp/name_format.h>
#include <dcp/colour_matrix.h>
changed (OTHER);
}
+
+void
+Config::save_template (shared_ptr<const Film> film, string name) const
+{
+ film->write_template (template_path (name));
+}
+
+list<string>
+Config::template_names () const
+{
+ list<string> n;
+ for (boost::filesystem::directory_iterator i (path("templates")); i != boost::filesystem::directory_iterator(); ++i) {
+ n.push_back (i->path().filename().string());
+ }
+ return n;
+}
+
+bool
+Config::existing_template (string name) const
+{
+ return boost::filesystem::exists (template_path (name));
+}
+
+boost::filesystem::path
+Config::template_path (string name) const
+{
+ return path("templates") / tidy_for_filename (name);
+}
class DCPContentType;
class Ratio;
class Cinema;
+class Film;
/** @class Config
* @brief A singleton class holding configuration.
void write () const;
+ void save_template (boost::shared_ptr<const Film> film, std::string name) const;
+ bool existing_template (std::string name) const;
+ std::list<std::string> template_names () const;
+ boost::filesystem::path template_path (std::string name) const;
+
static Config* instance ();
static void drop ();
static void restore_defaults ();
/*
- Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
#include "content.h"
#include "util.h"
#include "content_factory.h"
+#include "video_content.h"
+#include "audio_content.h"
+#include "subtitle_content.h"
#include "exceptions.h"
#include "film.h"
#include "job.h"
}
void
-Content::as_xml (xmlpp::Node* node) const
+Content::as_xml (xmlpp::Node* node, bool with_paths) const
{
boost::mutex::scoped_lock lm (_mutex);
- for (vector<boost::filesystem::path>::const_iterator i = _paths.begin(); i != _paths.end(); ++i) {
- node->add_child("Path")->add_child_text (i->string ());
+ if (with_paths) {
+ for (vector<boost::filesystem::path>::const_iterator i = _paths.begin(); i != _paths.end(); ++i) {
+ node->add_child("Path")->add_child_text (i->string ());
+ }
}
node->add_child("Digest")->add_child_text (_digest);
node->add_child("Position")->add_child_text (raw_convert<string> (_position.get ()));
/* This is a bit naughty, but I can't think of a compelling reason not to do it ... */
xmlpp::Document doc;
xmlpp::Node* node = doc.create_root_node ("Content");
- as_xml (node);
+ as_xml (node, true);
/* notes is unused here (we assume) */
list<string> notes;
}
}
}
+
+void
+Content::use_template (shared_ptr<const Content> c)
+{
+ if (video && c->video) {
+ video->use_template (c->video);
+ }
+ if (audio && c->audio) {
+ audio->use_template (c->audio);
+ }
+ if (subtitle && c->subtitle) {
+ subtitle->use_template (c->subtitle);
+ }
+}
*/
virtual void examine (boost::shared_ptr<Job> job);
+ virtual void use_template (boost::shared_ptr<const Content> c);
+
/** @return Quick one-line summary of the content, as will be presented in the
* film editor.
*/
*/
virtual std::string technical_summary () const;
- virtual void as_xml (xmlpp::Node *) const;
+ virtual void as_xml (xmlpp::Node *, bool with_paths) const;
virtual DCPTime full_length () const = 0;
virtual std::string identifier () const;
/** @return points at which to split this content when
using boost::scoped_ptr;
using boost::optional;
using boost::function;
+using boost::dynamic_pointer_cast;
using dcp::raw_convert;
int const DCPContentProperty::CAN_BE_PLAYED = 600;
}
void
-DCPContent::as_xml (xmlpp::Node* node) const
+DCPContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("DCP");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (video) {
video->as_xml (node);
return can_reference (bind (&Content::subtitle, _1), _("There is other subtitle content overlapping this DCP; remove it."), why_not);
}
+
+void
+DCPContent::use_template (shared_ptr<const Content> c)
+{
+ shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (c);
+ DCPOMATIC_ASSERT (dc);
+
+ _reference_video = dc->_reference_video;
+ _reference_audio = dc->_reference_audio;
+ _reference_subtitle = dc->_reference_subtitle;
+}
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
std::string identifier () const;
+ void use_template (boost::shared_ptr<const Content> c);
void set_default_colour_conversion ();
std::list<DCPTime> reel_split_points () const;
}
void
-DCPSubtitleContent::as_xml (xmlpp::Node* node) const
+DCPSubtitleContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("DCPSubtitle");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (subtitle) {
subtitle->as_xml (node);
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
private:
}
void
-FFmpegContent::as_xml (xmlpp::Node* node) const
+FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("FFmpeg");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (video) {
video->as_xml (node);
return fa;
}
+
+void
+FFmpegContent::use_template (shared_ptr<const Content> c)
+{
+ Content::use_template (c);
+
+ shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (c);
+ _filters = fc->_filters;
+}
}
void examine (boost::shared_ptr<Job>);
+ void use_template (boost::shared_ptr<const Content> c);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
std::string identifier () const;
* @param dir Film directory.
*/
-Film::Film (boost::filesystem::path dir, bool log)
+Film::Film (optional<boost::filesystem::path> dir)
: _playlist (new Playlist)
, _use_isdcf_name (true)
, _dcp_content_type (Config::instance()->default_dcp_content_type ())
_playlist_order_changed_connection = _playlist->OrderChanged.connect (bind (&Film::playlist_order_changed, this));
_playlist_content_changed_connection = _playlist->ContentChanged.connect (bind (&Film::playlist_content_changed, this, _1, _2, _3));
- /* Make state.directory a complete path without ..s (where possible)
- (Code swiped from Adam Bowen on stackoverflow)
- XXX: couldn't/shouldn't this just be boost::filesystem::canonical?
- */
+ if (dir) {
+ /* Make state.directory a complete path without ..s (where possible)
+ (Code swiped from Adam Bowen on stackoverflow)
+ XXX: couldn't/shouldn't this just be boost::filesystem::canonical?
+ */
- boost::filesystem::path p (boost::filesystem::system_complete (dir));
- boost::filesystem::path result;
- for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) {
- if (*i == "..") {
- if (boost::filesystem::is_symlink (result) || result.filename() == "..") {
+ boost::filesystem::path p (boost::filesystem::system_complete (dir.get()));
+ boost::filesystem::path result;
+ for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) {
+ if (*i == "..") {
+ if (boost::filesystem::is_symlink (result) || result.filename() == "..") {
+ result /= *i;
+ } else {
+ result = result.parent_path ();
+ }
+ } else if (*i != ".") {
result /= *i;
- } else {
- result = result.parent_path ();
}
- } else if (*i != ".") {
- result /= *i;
}
+
+ set_directory (result.make_preferred ());
}
- set_directory (result.make_preferred ());
- if (log) {
+ if (_directory) {
_log.reset (new FileLog (file ("log")));
} else {
_log.reset (new NullLog);
}
shared_ptr<xmlpp::Document>
-Film::metadata () const
+Film::metadata (bool with_content_paths) const
{
shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
xmlpp::Element* root = doc->create_root_node ("Metadata");
root->add_child("ReelType")->add_child_text (raw_convert<string> (static_cast<int> (_reel_type)));
root->add_child("ReelLength")->add_child_text (raw_convert<string> (_reel_length));
root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
- _playlist->as_xml (root->add_child ("Playlist"));
+ _playlist->as_xml (root->add_child ("Playlist"), with_content_paths);
return doc;
}
void
Film::write_metadata () const
{
- boost::filesystem::create_directories (directory ());
+ DCPOMATIC_ASSERT (directory());
+ boost::filesystem::create_directories (directory().get());
shared_ptr<xmlpp::Document> doc = metadata ();
doc->write_to_file_formatted (file("metadata.xml").string ());
_dirty = false;
}
+/** Write a template from this film */
+void
+Film::write_template (boost::filesystem::path path) const
+{
+ boost::filesystem::create_directories (path.parent_path());
+ shared_ptr<xmlpp::Document> doc = metadata (false);
+ doc->write_to_file_formatted (path.string ());
+}
+
/** Read state from our metadata file.
* @return Notes about things that the user should know about, or empty.
*/
list<string>
-Film::read_metadata ()
+Film::read_metadata (optional<boost::filesystem::path> path)
{
- if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) {
- throw runtime_error (_("This film was created with an older version of DCP-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!"));
+ if (!path) {
+ if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) {
+ throw runtime_error (_("This film was created with an older version of DCP-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!"));
+ }
+
+ path = file ("metadata.xml");
}
cxml::Document f ("Metadata");
- f.read_file (file ("metadata.xml"));
+ f.read_file (path.get ());
_state_version = f.number_child<int> ("Version");
if (_state_version > current_state_version) {
_playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes);
/* Write backtraces to this film's directory, until another film is loaded */
- set_backtrace_file (file ("backtrace.txt"));
+ if (_directory) {
+ set_backtrace_file (file ("backtrace.txt"));
+ }
_dirty = false;
return notes;
boost::filesystem::path
Film::dir (boost::filesystem::path d) const
{
+ DCPOMATIC_ASSERT (_directory);
+
boost::filesystem::path p;
- p /= _directory;
+ p /= _directory.get();
p /= d;
boost::filesystem::create_directories (p);
boost::filesystem::path
Film::file (boost::filesystem::path f) const
{
+ DCPOMATIC_ASSERT (_directory);
+
boost::filesystem::path p;
- p /= _directory;
+ p /= _directory.get();
p /= f;
boost::filesystem::create_directories (p.parent_path ());
vector<CPLSummary>
Film::cpls () const
{
+ if (!directory ()) {
+ return vector<CPLSummary> ();
+ }
+
vector<CPLSummary> out;
- boost::filesystem::path const dir = directory ();
+ boost::filesystem::path const dir = directory().get();
for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) {
if (
boost::filesystem::is_directory (*i) &&
void
Film::examine_and_add_content (shared_ptr<Content> c)
{
- if (dynamic_pointer_cast<FFmpegContent> (c) && !_directory.empty ()) {
+ if (dynamic_pointer_cast<FFmpegContent> (c) && _directory) {
run_ffprobe (c->path(0), file ("ffprobe.log"), _log);
}
}
add_content (content);
+
if (Config::instance()->automatic_audio_analysis() && content->audio) {
shared_ptr<Playlist> playlist (new Playlist);
playlist->add (content);
c->set_position (_playlist->subtitle_end ());
}
+ if (_template_film) {
+ /* Take settings from the first piece of content of c's type in _template */
+ BOOST_FOREACH (shared_ptr<Content> i, _template_film->content()) {
+ if (typeid(i.get()) == typeid(c.get())) {
+ c->use_template (i);
+ }
+ }
+ }
+
_playlist->add (c);
}
return notes;
}
+
+void
+Film::use_template (string name)
+{
+ _template_film.reset (new Film (optional<boost::filesystem::path>()));
+ _template_film->read_metadata (Config::instance()->template_path (name));
+ _use_isdcf_name = _template_film->_use_isdcf_name;
+ _dcp_content_type = _template_film->_dcp_content_type;
+ _container = _template_film->_container;
+ _resolution = _template_film->_resolution;
+ _j2k_bandwidth = _template_film->_j2k_bandwidth;
+ _video_frame_rate = _template_film->_video_frame_rate;
+ _signed = _template_film->_signed;
+ _encrypted = _template_film->_encrypted;
+ _audio_channels = _template_film->_audio_channels;
+ _sequence = _template_film->_sequence;
+ _three_d = _template_film->_three_d;
+ _interop = _template_film->_interop;
+ _audio_processor = _template_film->_audio_processor;
+ _reel_type = _template_film->_reel_type;
+ _reel_length = _template_film->_reel_length;
+ _upload_after_make_dcp = _template_film->_upload_after_make_dcp;
+}
class Film : public boost::enable_shared_from_this<Film>, public Signaller, public boost::noncopyable
{
public:
- Film (boost::filesystem::path, bool log = true);
+ Film (boost::optional<boost::filesystem::path> dir);
~Film ();
boost::filesystem::path info_file (DCPTimePeriod p) const;
boost::filesystem::path file (boost::filesystem::path f) const;
boost::filesystem::path dir (boost::filesystem::path d) const;
- std::list<std::string> read_metadata ();
+ void use_template (std::string name);
+ std::list<std::string> read_metadata (boost::optional<boost::filesystem::path> path = boost::optional<boost::filesystem::path> ());
void write_metadata () const;
- boost::shared_ptr<xmlpp::Document> metadata () const;
+ void write_template (boost::filesystem::path path) const;
+ boost::shared_ptr<xmlpp::Document> metadata (bool with_content_paths = true) const;
std::string isdcf_name (bool if_created_now) const;
std::string dcp_name (bool if_created_now = false) const;
/* GET */
- boost::filesystem::path directory () const {
+ boost::optional<boost::filesystem::path> directory () const {
return _directory;
}
/** Complete path to directory containing the film metadata;
* must not be relative.
*/
- boost::filesystem::path _directory;
+ boost::optional<boost::filesystem::path> _directory;
/** Name for DCP-o-matic */
std::string _name;
/** true if our state has changed since we last saved it */
mutable bool _dirty;
+ /** film being used as a template, or 0 */
+ boost::shared_ptr<Film> _template_film;
boost::signals2::scoped_connection _playlist_changed_connection;
boost::signals2::scoped_connection _playlist_order_changed_connection;
}
void
-ImageContent::as_xml (xmlpp::Node* node) const
+ImageContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("Image");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (video) {
video->as_xml (node);
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
std::string identifier () const;
/** @param node <Playlist> node */
void
-Playlist::as_xml (xmlpp::Node* node)
+Playlist::as_xml (xmlpp::Node* node, bool with_content_paths)
{
BOOST_FOREACH (shared_ptr<Content> i, _content) {
- i->as_xml (node->add_child ("Content"));
+ i->as_xml (node->add_child ("Content"), with_content_paths);
}
}
Playlist ();
~Playlist ();
- void as_xml (xmlpp::Node *);
+ void as_xml (xmlpp::Node *, bool with_content_paths);
void set_from_xml (boost::shared_ptr<const Film>, cxml::ConstNodePtr, int, std::list<std::string> &);
void add (boost::shared_ptr<Content>);
_sound_asset->set_key (_film->key ());
}
+ DCPOMATIC_ASSERT (_film->directory());
+
/* Write the sound asset into the film directory so that we leave the creation
of the DCP directory until the last minute.
*/
_sound_asset_writer = _sound_asset->start_write (
- _film->directory() / audio_asset_filename (_sound_asset, _reel_index, _reel_count, _content_summary),
+ _film->directory().get() / audio_asset_filename (_sound_asset, _reel_index, _reel_count, _content_summary),
_film->interop() ? dcp::INTEROP : dcp::SMPTE
);
}
{
maybe_set (_fade_out, t, SubtitleContentProperty::FADE_OUT);
}
+
+void
+SubtitleContent::use_template (shared_ptr<const SubtitleContent> c)
+{
+ _use = c->_use;
+ _burn = c->_burn;
+ _x_offset = c->_x_offset;
+ _y_offset = c->_y_offset;
+ _x_scale = c->_x_scale;
+ _y_scale = c->_y_scale;
+ _fonts = c->_fonts;
+ _colour = c->_colour;
+ _outline = c->_outline;
+ _shadow = c->_shadow;
+ _effect_colour = c->_effect_colour;
+ _line_spacing = c->_line_spacing;
+ _fade_in = c->_fade_in;
+ _fade_out = c->_fade_out;
+}
void as_xml (xmlpp::Node *) const;
std::string identifier () const;
+ void use_template (boost::shared_ptr<const SubtitleContent> c);
void add_font (boost::shared_ptr<Font> font);
}
void
-TextSubtitleContent::as_xml (xmlpp::Node* node) const
+TextSubtitleContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("TextSubtitle");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
if (subtitle) {
subtitle->as_xml (node);
void examine (boost::shared_ptr<Job>);
std::string summary () const;
std::string technical_summary () const;
- void as_xml (xmlpp::Node *) const;
+ void as_xml (xmlpp::Node *, bool with_paths) const;
DCPTime full_length () const;
private:
{
maybe_set (_fade_out, t, VideoContentProperty::FADE_OUT);
}
+
+void
+VideoContent::use_template (shared_ptr<const VideoContent> c)
+{
+ _colour_conversion = c->_colour_conversion;
+ _frame_type = c->_frame_type;
+ _crop = c->_crop;
+ _scale = c->_scale;
+ _fade_in = c->_fade_in;
+ _fade_out = c->_fade_out;
+}
void as_xml (xmlpp::Node *) const;
std::string technical_summary () const;
std::string identifier () const;
+ void use_template (boost::shared_ptr<const VideoContent> c);
Frame length () const {
boost::mutex::scoped_lock lm (_mutex);
}
void
-VideoMXFContent::as_xml (xmlpp::Node* node) const
+VideoMXFContent::as_xml (xmlpp::Node* node, bool with_paths) const
{
node->add_child("Type")->add_child_text ("VideoMXF");
- Content::as_xml (node);
+ Content::as_xml (node, with_paths);
video->as_xml (node);
}
std::string summary () const;
std::string technical_summary () const;
std::string identifier () const;
- void as_xml (xmlpp::Node* node) const;
+ void as_xml (xmlpp::Node* node, bool with_paths) const;
DCPTime full_length () const;
void add_properties (std::list<UserProperty>& p) const;
void set_default_colour_conversion ();
#include "wx/content_panel.h"
#include "wx/report_problem_dialog.h"
#include "wx/video_waveform_dialog.h"
+#include "wx/save_template_dialog.h"
#include "lib/film.h"
#include "lib/config.h"
#include "lib/util.h"
ID_file_new = 1,
ID_file_open,
ID_file_save,
+ ID_file_save_as_template,
ID_file_history,
/* Allow spare IDs after _history for the recent files list */
ID_content_scale_to_fit_width = 100,
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_new, this), ID_file_new);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_open, this), ID_file_open);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_save, this), ID_file_save);
+ Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_save_as_template, this), ID_file_save_as_template);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_history, this, _1), ID_file_history, ID_file_history + HISTORY_SIZE);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_exit, this), wxID_EXIT);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES);
}
}
- void new_film (boost::filesystem::path path)
+ void new_film (boost::filesystem::path path, optional<string> template_name)
{
shared_ptr<Film> film (new Film (path));
+ if (template_name) {
+ film->use_template (template_name.get());
+ }
film->write_metadata ();
film->set_name (path.filename().generic_string());
set_film (film);
delete _video_waveform_dialog;
_video_waveform_dialog = 0;
set_menu_sensitivity ();
- Config::instance()->add_to_history (_film->directory ());
+ if (_film->directory()) {
+ Config::instance()->add_to_history (_film->directory().get());
+ }
}
shared_ptr<Film> film () const {
if (r == wxID_OK) {
- if (boost::filesystem::is_directory (d->get_path()) && !boost::filesystem::is_empty(d->get_path())) {
+ if (boost::filesystem::is_directory (d->path()) && !boost::filesystem::is_empty(d->path())) {
if (!confirm_dialog (
this,
std_to_wx (
String::compose (wx_to_std (_("The directory %1 already exists and is not empty. "
"Are you sure you want to use it?")),
- d->get_path().string().c_str())
+ d->path().string().c_str())
)
)) {
return;
}
- } else if (boost::filesystem::is_regular_file (d->get_path())) {
+ } else if (boost::filesystem::is_regular_file (d->path())) {
error_dialog (
this,
- String::compose (wx_to_std (_("%1 already exists as a file, so you cannot use it for a new film.")), d->get_path().c_str())
+ String::compose (wx_to_std (_("%1 already exists as a file, so you cannot use it for a new film.")), d->path().c_str())
);
return;
}
if (maybe_save_then_delete_film ()) {
- new_film (d->get_path ());
+ new_film (d->path(), d->template_name());
}
}
_film->write_metadata ();
}
+ void file_save_as_template ()
+ {
+ SaveTemplateDialog* d = new SaveTemplateDialog (this);
+ int const r = d->ShowModal ();
+ if (r == wxID_OK) {
+ bool ok = true;
+ if (Config::instance()->existing_template (d->name ())) {
+ ok = confirm_dialog (d, _("There is already a template with this name. Do you want to overwrite it?"));
+ }
+ if (ok) {
+ Config::instance()->save_template (_film, d->name ());
+ }
+ }
+ d->Destroy ();
+ }
+
void file_history (wxCommandEvent& event)
{
vector<boost::filesystem::path> history = Config::instance()->history ();
boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query);
Socket socket (5);
socket.connect (*endpoint_iterator);
- string s = _film->directory().string ();
+ DCPOMATIC_ASSERT (_film->directory ());
+ string s = _film->directory()->string ();
socket.write (s.length() + 1);
socket.write ((uint8_t *) s.c_str(), s.length() + 1);
/* OK\0 */
void jobs_show_dcp ()
{
+ DCPOMATIC_ASSERT (_film->directory ());
#ifdef DCPOMATIC_WINDOWS
wstringstream args;
args << "/select," << _film->dir (_film->dcp_name(false));
#ifdef DCPOMATIC_LINUX
int r = system ("which nautilus");
if (WEXITSTATUS (r) == 0) {
- r = system (string ("nautilus " + _film->directory().string()).c_str ());
+ r = system (string ("nautilus " + _film->directory()->string()).c_str ());
if (WEXITSTATUS (r)) {
error_dialog (this, _("Could not show DCP (could not run nautilus)"));
}
} else {
int r = system ("which konqueror");
if (WEXITSTATUS (r) == 0) {
- r = system (string ("konqueror " + _film->directory().string()).c_str ());
+ r = system (string ("konqueror " + _film->directory()->string()).c_str ());
if (WEXITSTATUS (r)) {
error_dialog (this, _("Could not show DCP (could not run konqueror)"));
}
add_item (_file_menu, _("&Open...\tCtrl-O"), ID_file_open, ALWAYS);
_file_menu->AppendSeparator ();
add_item (_file_menu, _("&Save\tCtrl-S"), ID_file_save, NEEDS_FILM);
+ _file_menu->AppendSeparator ();
+ add_item (_file_menu, _("Save as &template..."), ID_file_save_as_template, NEEDS_FILM);
_history_position = _file_menu->GetMenuItems().GetCount();
}
if (!_film_to_create.empty ()) {
- _frame->new_film (_film_to_create);
+ _frame->new_film (_film_to_create, optional<string> ());
if (!_content_to_add.empty ()) {
_frame->film()->examine_and_add_content (content_factory (_frame->film(), _content_to_add));
}
using boost::thread;
using boost::scoped_array;
-static std::string film_to_load;
+static boost::optional<boost::filesystem::path> film_to_load;
enum {
ID_file_add_film = 1,
this->Bind (wxEVT_IDLE, boost::bind (&App::idle, this));
shared_ptr<Film> film;
- if (!film_to_load.empty() && boost::filesystem::is_directory (film_to_load)) {
+ if (film_to_load && boost::filesystem::is_directory (film_to_load.get())) {
try {
- film.reset (new Film (film_to_load));
+ film.reset (new Film (film_to_load.get()));
film->read_metadata ();
film->make_dcp ();
} catch (exception& e) {
- error_dialog (0, std_to_wx (String::compose (wx_to_std (_("Could not load film %1 (%2)")), film_to_load, e.what())));
+ error_dialog (
+ 0, std_to_wx (String::compose (wx_to_std (_("Could not load film %1 (%2)")), film_to_load->string(), e.what()))
+ );
}
}
int
main (int argc, char* argv[])
{
- string film_dir;
+ boost::filesystem::path film_dir;
bool progress = true;
bool no_remote = false;
optional<int> threads;
film.reset (new Film (film_dir));
film->read_metadata ();
} catch (std::exception& e) {
- cerr << argv[0] << ": error reading film `" << film_dir << "' (" << e.what() << ")\n";
+ cerr << argv[0] << ": error reading film `" << film_dir.string() << "' (" << e.what() << ")\n";
exit (EXIT_FAILURE);
}
using std::exception;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
+using boost::optional;
static void
syntax (string n)
<< " -v, --version show DCP-o-matic version\n"
<< " -h, --help show this help\n"
<< " -n, --name <name> film name\n"
+ << " -t, --template <name> template name\n"
<< " -c, --dcp-content-type <type> FTR, SHR, TLR, TST, XSN, RTG, TSR, POL, PSA or ADV\n"
<< " --container-ratio <ratio> 119, 133, 137, 138, 166, 178, 185 or 239\n"
<< " --content-ratio <ratio> 119, 133, 137, 138, 166, 178, 185 or 239\n"
dcpomatic_setup ();
string name;
+ optional<string> template_name;
DCPContentType const * dcp_content_type = DCPContentType::from_isdcf_name ("TST");
Ratio const * container_ratio = 0;
Ratio const * content_ratio = 0;
{ "version", no_argument, 0, 'v'},
{ "help", no_argument, 0, 'h'},
{ "name", required_argument, 0, 'n'},
+ { "template", required_argument, 0, 'f'},
{ "dcp-content-type", required_argument, 0, 'c'},
{ "container-ratio", required_argument, 0, 'A'},
{ "content-ratio", required_argument, 0, 'B'},
{ 0, 0, 0, 0}
};
- int c = getopt_long (argc, argv, "vhn:c:A:B:C:s:o:DE", long_options, &option_index);
+ int c = getopt_long (argc, argv, "vhn:f:c:A:B:C:s:o:DE", long_options, &option_index);
if (c == -1) {
break;
}
case 'n':
name = optarg;
break;
+ case 't':
+ template_name = optarg;
+ break;
case 'c':
dcp_content_type = DCPContentType::from_isdcf_name (optarg);
if (dcp_content_type == 0) {
}
try {
- shared_ptr<Film> film (new Film (output, false));
+ shared_ptr<Film> film (new Film (output));
+ if (template_name) {
+ film->use_template (template_name.get());
+ }
film->set_name (name);
film->set_container (container_ratio);
using std::list;
using std::vector;
using boost::shared_ptr;
+using boost::optional;
static void
help ()
valid_to = valid_from.get() + duration_from_string (duration_string);
}
- string const film_dir = argv[optind];
+ boost::filesystem::path const film_dir = argv[optind];
dcpomatic_setup_path_encoding ();
dcpomatic_setup ();
cout << "Read film " << film->name () << "\n";
}
} catch (std::exception& e) {
- cerr << program_name << ": error reading film `" << film_dir << "' (" << e.what() << ")\n";
+ cerr << program_name << ": error reading film `" << film_dir.string() << "' (" << e.what() << ")\n";
exit (EXIT_FAILURE);
}
using std::string;
using std::pair;
using boost::shared_ptr;
+using boost::optional;
using dcp::Data;
static shared_ptr<Film> film;
int
main (int argc, char* argv[])
{
- string film_dir;
+ boost::filesystem::path film_dir;
string server_host;
while (true) {
}
}
- if (server_host.empty() || film_dir.empty()) {
+ if (server_host.empty() || film_dir.string().empty()) {
help (argv[0]);
exit (EXIT_FAILURE);
}
_film->ContentChanged.connect (bind (&FilmEditor::film_content_changed, this, _2));
}
- if (_film) {
- FileChanged (_film->directory ());
+ if (_film && _film->directory()) {
+ FileChanged (_film->directory().get());
} else {
FileChanged ("");
}
*/
-#include <boost/filesystem.hpp>
-#include <wx/stdpaths.h>
#include "lib/config.h"
#include "new_film_dialog.h"
#include "wx_util.h"
#ifdef DCPOMATIC_USE_OWN_PICKER
#include "dir_picker_ctrl.h"
#endif
+#include <wx/stdpaths.h>
+#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
using namespace std;
using namespace boost;
_folder->SetPath (std_to_wx (_directory.get().string()));
add (_folder);
+ _use_template = new wxCheckBox (this, wxID_ANY, _("From template"));
+ add (_use_template);
+ _template_name = new wxChoice (this, wxID_ANY);
+ add (_template_name);
+
_name->SetFocus ();
+ _template_name->Enable (false);
+
+ BOOST_FOREACH (string i, Config::instance()->template_names ()) {
+ _template_name->Append (std_to_wx (i));
+ }
+
+ _use_template->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, bind (&NewFilmDialog::use_template_clicked, this));
layout ();
}
+void
+NewFilmDialog::use_template_clicked ()
+{
+ _template_name->Enable (_use_template->GetValue ());
+}
+
NewFilmDialog::~NewFilmDialog ()
{
_directory = wx_to_std (_folder->GetPath ());
}
boost::filesystem::path
-NewFilmDialog::get_path () const
+NewFilmDialog::path () const
{
filesystem::path p;
p /= wx_to_std (_folder->GetPath ());
p /= wx_to_std (_name->GetValue ());
return p;
}
+
+optional<string>
+NewFilmDialog::template_name () const
+{
+ if (!_use_template->GetValue() || _template_name->GetSelection() == -1) {
+ return optional<string> ();
+ }
+
+ return wx_to_std (_template_name->GetString(_template_name->GetSelection()));
+}
NewFilmDialog (wxWindow *);
~NewFilmDialog ();
- boost::filesystem::path get_path () const;
+ boost::filesystem::path path () const;
+ boost::optional<std::string> template_name () const;
private:
+ void use_template_clicked ();
+
wxTextCtrl* _name;
#ifdef DCPOMATIC_USE_OWN_PICKER
DirPickerCtrl* _folder;
#else
wxDirPickerCtrl* _folder;
#endif
+ wxCheckBox* _use_template;
+ wxChoice* _template_name;
static boost::optional<boost::filesystem::path> _directory;
};
--- /dev/null
+/*
+ Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DCP-o-matic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "save_template_dialog.h"
+#include "wx_util.h"
+#include <boost/foreach.hpp>
+
+using std::string;
+
+SaveTemplateDialog::SaveTemplateDialog (wxWindow* parent)
+ : TableDialog (parent, _("Save template"), 2, 1, true)
+{
+ add (_("Template name"), true);
+ _name = add (new wxTextCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (300, -1)));
+ _name->SetFocus ();
+ layout ();
+}
+
+string
+SaveTemplateDialog::name () const
+{
+ return wx_to_std (_name->GetValue ());
+}
--- /dev/null
+/*
+ Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DCP-o-matic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "table_dialog.h"
+
+class SaveTemplateDialog : public TableDialog
+{
+public:
+ SaveTemplateDialog (wxWindow* parent);
+
+ std::string name () const;
+
+private:
+ wxTextCtrl* _name;
+};
repeat_dialog.cc
report_problem_dialog.cc
rgba_colour_picker.cc
+ save_template_dialog.cc
screen_dialog.cc
screens_panel.cc
self_dkdm_dialog.cc
BOOST_AUTO_TEST_CASE (ffmpeg_have_dcp_test)
{
boost::filesystem::path p = test_film_dir ("ffmpeg_dcp_test");
- shared_ptr<Film> film (new Film (p.string ()));
+ shared_ptr<Film> film (new Film (p));
film->read_metadata ();
BOOST_CHECK (!film->cpls().empty());
{
/* Find the subtitle file and check it */
for (
- boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory() / film->dcp_name (false));
+ boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory().get() / film->dcp_name (false));
i != boost::filesystem::directory_iterator ();
++i) {
/* Find the subtitle file and check it */
for (
- boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory() / film->dcp_name (false));
+ boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (film->directory().get() / film->dcp_name (false));
i != boost::filesystem::directory_iterator ();
++i) {
boost::filesystem::remove_all (p);
}
- shared_ptr<Film> film = shared_ptr<Film> (new Film (p.string()));
+ shared_ptr<Film> film = shared_ptr<Film> (new Film (p));
film->write_metadata ();
return film;
}