Handle export presets from config dirs properly. Removed some debug output.
[ardour.git] / libs / ardour / export_profile_manager.cc
index 88432bcedc5b7ba95a7de60de3ebb1b3157fd414..600ce9e3ea9654bc636d37a2e30959ebf7c7b232 100644 (file)
 #include <pbd/xml++.h>
 #include <pbd/convert.h>
 
-#include <ardour/audioengine.h>
 #include <ardour/export_failed.h>
+#include <ardour/export_file_io.h>
 #include <ardour/export_format_specification.h>
 #include <ardour/export_timespan.h>
 #include <ardour/export_channel_configuration.h>
 #include <ardour/export_filename.h>
+#include <ardour/export_preset.h>
 #include <ardour/export_handler.h>
+#include <ardour/filename_extensions.h>
 #include <ardour/session.h>
 
 #include "i18n.h"
@@ -45,168 +47,25 @@ using namespace PBD;
 namespace ARDOUR
 {
 
-ExportProfileManager::Preset::Preset (string filename, Session & s) :
-  _id (0), session (s), global (filename), local (0)
-{
-       XMLNode * root;
-       if ((root = global.root())) {
-               XMLProperty * prop;
-               if ((prop = root->property ("id"))) {
-                       set_id ((uint32_t) atoi (prop->value()));
-               }
-               if ((prop = root->property ("name"))) {
-                       set_name (prop->value());
-               }
-               
-               XMLNode * instant_xml = get_instant_xml ();
-               if (instant_xml) {
-                       XMLNode * instant_copy = new XMLNode (*instant_xml);
-                       set_local_state (*instant_copy);
-               }
-       }
-}
-
-ExportProfileManager::Preset::~Preset ()
-{
-       if (local) {
-               delete local;
-       }
-}
-
-void
-ExportProfileManager::Preset::set_name (string name)
-{
-       _name = name;
-
-       XMLNode * node; 
-       if ((node = global.root())) {
-               node->add_property ("name", name);
-       }
-       if (local) {
-               local->add_property ("name", name);
-       }
-}
-
-void
-ExportProfileManager::Preset::set_id (uint32_t id)
-{
-       _id = id;
-
-       XMLNode * node;
-       if ((node = global.root())) {
-               node->add_property ("id", id);
-       }
-       if (local) {
-               local->add_property ("id", id);
-       }
-}
-
-void
-ExportProfileManager::Preset::set_global_state (XMLNode & state)
-{
-       delete global.root ();
-       global.set_root (&state);
-       
-       set_id (_id);
-       set_name (_name);
-}
-
-void
-ExportProfileManager::Preset::set_local_state (XMLNode & state)
-{
-       delete local;
-       local = &state;
-       
-       set_id (_id);
-       set_name (_name);
-}
-
-void
-ExportProfileManager::Preset::save () const
-{
-       save_instant_xml ();
-       if (global.root()) {
-               global.write ();
-       }
-}
-
-void
-ExportProfileManager::Preset::remove_local () const
-{
-       remove_instant_xml ();
-}
-
-XMLNode *
-ExportProfileManager::Preset::get_instant_xml () const
-{
-       XMLNode * instant_xml;
-       
-       if ((instant_xml = session.instant_xml ("ExportPresets"))) {
-               XMLNodeList children = instant_xml->children ("ExportPreset");
-               for (XMLNodeList::iterator it = children.begin(); it != children.end(); ++it) {
-                       XMLProperty * prop;
-                       if ((prop = (*it)->property ("id")) && _id == (uint32_t) atoi (prop->value())) {
-                               return *it;
-                       }
-               }
-       }
-       
-       return 0;
-}
-
-void
-ExportProfileManager::Preset::save_instant_xml () const
-{
-       if (!local) { return; }
-
-       /* First remove old, then add new */
-       
-       remove_instant_xml ();
-       
-       XMLNode * instant_xml;
-       if ((instant_xml = session.instant_xml ("ExportPresets"))) {
-               instant_xml->add_child_copy (*local);
-       } else {
-               instant_xml = new XMLNode ("ExportPresets");
-               instant_xml->add_child_copy (*local);
-               session.add_instant_xml (*instant_xml, false);
-       }
-}
-
-void
-ExportProfileManager::Preset::remove_instant_xml () const
-{
-       XMLNode * instant_xml;
-       if ((instant_xml = session.instant_xml ("ExportPresets"))) {
-               instant_xml->remove_nodes_and_delete ("id", to_string (_id, std::dec));
-       }
-}
-
 ExportProfileManager::ExportProfileManager (Session & s) :
   handler (s.get_export_handler()),
   session (s),
 
   session_range (new Location ()),
   ranges (new LocationList ()),
+  single_range_mode (false),
 
   format_list (new FormatList ())
 {
 
        /* Initialize path variables */
 
-       sys::path path;
-
        export_config_dir = user_config_directory();
        export_config_dir /= "export";
        search_path += export_config_dir;
        
-       path = ardour_search_path().to_string();
-       path /= "export";
-       search_path += path;
-       
-       path = system_config_search_path().to_string();
-       path /= "export";
-       search_path += path;
+       search_path += ardour_search_path().add_subdirectory_to_paths("export");
+       search_path += system_config_search_path().add_subdirectory_to_paths("export");;
        
        /* create export config directory if necessary */
 
@@ -216,10 +75,20 @@ ExportProfileManager::ExportProfileManager (Session & s) :
        
        load_presets ();
        load_formats ();
+       
+       /* Initialize all lists with an empty config */
+       
+       XMLNodeList dummy;
+       init_timespans (dummy);
+       init_channel_configs (dummy);
+       init_formats (dummy);
+       init_filenames (dummy);
 }
 
 ExportProfileManager::~ExportProfileManager ()
 {
+       if (single_range_mode) { return; }
+       
        XMLNode * instant_xml (new XMLNode ("ExportProfile"));
        serialize_profile (*instant_xml);
        session.add_instant_xml (*instant_xml, false);
@@ -257,43 +126,46 @@ ExportProfileManager::prepare_for_export ()
        }
 }
 
-void
+bool
 ExportProfileManager::load_preset (PresetPtr preset)
 {
+       bool ok = true;
+
        current_preset = preset;
-       if (!preset) { return; }
+       if (!preset) { return false; }
 
        XMLNode const * state;
        if ((state = preset->get_local_state())) {
                set_local_state (*state);
-       }
+       } else { ok = false; }
        
        if ((state = preset->get_global_state())) {
-               set_global_state (*state);
-       }
+               if (!set_global_state (*state)) {
+                       ok = false;
+               }
+       } else { ok = false; }
+       
+       return ok;
 }
 
 void
 ExportProfileManager::load_presets ()
 {
-       preset_id_counter = 0;
-       
-       vector<sys::path> found = find_file ("*.preset");
+       vector<sys::path> found = find_file (string_compose (X_("*%1"),export_preset_suffix));
 
        for (vector<sys::path>::iterator it = found.begin(); it != found.end(); ++it) {
-               preset_id_counter = std::max (preset_id_counter, load_preset_from_disk (*it));
+               load_preset_from_disk (*it);
        }
 }
 
 ExportProfileManager::PresetPtr
 ExportProfileManager::save_preset (string const & name)
 {
+       string filename = export_config_dir.to_string() + "/" + name + export_preset_suffix;
+
        if (!current_preset) {
-               ++preset_id_counter;
-               string filename = export_config_dir.to_string() + "/" + to_string (preset_id_counter, std::dec) + ".preset";
-               current_preset.reset (new Preset (filename, session));
+               current_preset.reset (new ExportPreset (filename, session));
                preset_list.push_back (current_preset);
-               current_preset->set_id (preset_id_counter);
        }
        
        XMLNode * global_preset = new XMLNode ("ExportPreset");
@@ -306,7 +178,7 @@ ExportProfileManager::save_preset (string const & name)
        current_preset->set_global_state (*global_preset);
        current_preset->set_local_state (*local_preset);
        
-       current_preset->save();
+       current_preset->save (filename);
        
        return current_preset;
 }
@@ -333,39 +205,37 @@ ExportProfileManager::remove_preset ()
        current_preset.reset();
 }
 
-uint32_t
+void
 ExportProfileManager::load_preset_from_disk (PBD::sys::path const & path)
 {
-       PresetPtr preset (new Preset (path.to_string(), session));
-       preset_list.push_back (preset);
+       PresetPtr preset (new ExportPreset (path.to_string(), session));
        
-       /* Handle id to filename mapping */
+       /* Handle id to filename mapping and don't add duplicates to list */
        
        FilePair pair (preset->id(), path);
-       preset_file_map.insert (pair);
-       
-       return preset->id();
+       if (preset_file_map.insert (pair).second) {
+               preset_list.push_back (preset);
+       }
 }
 
-void
+bool
 ExportProfileManager::set_state (XMLNode const & root)
 {
-       set_global_state (root);
-       set_local_state (root);
+       return set_global_state (root) && set_local_state (root);
 }
 
-void
+bool
 ExportProfileManager::set_global_state (XMLNode const & root)
 {
-       init_formats (root.children ("ExportFormat"));
-       init_filenames (root.children ("ExportFilename"));
+       return init_filenames (root.children ("ExportFilename")) &&
+              init_formats (root.children ("ExportFormat"));
 }
 
-void
+bool
 ExportProfileManager::set_local_state (XMLNode const & root)
 {
-       init_timespans (root.children ("ExportTimespan"));;
-       init_channel_configs (root.children ("ExportChannelConfiguration"));
+       return init_timespans (root.children ("ExportTimespan")) &&
+              init_channel_configs (root.children ("ExportChannelConfiguration"));
 }
 
 void
@@ -383,7 +253,7 @@ ExportProfileManager::serialize_global_profile (XMLNode & root)
        }
 
        for (FilenameStateList::iterator it = filenames.begin(); it != filenames.end(); ++it) {
-               root.add_child_nocopy (serialize_filename (*it));
+               root.add_child_nocopy ((*it)->filename->get_state());
        }
 }
 
@@ -395,7 +265,7 @@ ExportProfileManager::serialize_local_profile (XMLNode & root)
        }
        
        for (ChannelConfigStateList::iterator it = channel_configs.begin(); it != channel_configs.end(); ++it) {
-               root.add_child_nocopy (serialize_channel_config (*it));
+               root.add_child_nocopy ((*it)->config->get_state());
        }
 }
 
@@ -427,23 +297,41 @@ ExportProfileManager::set_selection_range (nframes_t start, nframes_t end)
        }
 }
 
-void
+std::string
+ExportProfileManager::set_single_range (nframes_t start, nframes_t end, Glib::ustring name)
+{
+       single_range_mode = true;
+       
+       single_range.reset (new Location());
+       single_range->set_name (name);
+       single_range->set (start, end);
+       
+       update_ranges ();
+       
+       return single_range->id().to_s();
+}
+
+bool
 ExportProfileManager::init_timespans (XMLNodeList nodes)
 {
        timespans.clear ();
-
-       if (nodes.empty()) {
-               update_ranges ();
+       update_ranges ();
        
-               TimespanStatePtr timespan (new TimespanState (session_range, selection_range, ranges));
+       bool ok = true;
+       for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
+               TimespanStatePtr span = deserialize_timespan (**it);
+               if (span) {
+                       timespans.push_back (span);
+               } else { ok = false; }
+       }
        
+       if (timespans.empty()) {
+               TimespanStatePtr timespan (new TimespanState (session_range, selection_range, ranges));
                timespans.push_back (timespan);
-               return;
-       }
-
-       for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
-               timespans.push_back (deserialize_timespan (**it));
+               return false;
        }
+       
+       return ok;
 }
 
 ExportProfileManager::TimespanStatePtr
@@ -452,8 +340,6 @@ ExportProfileManager::deserialize_timespan (XMLNode & root)
        TimespanStatePtr state (new TimespanState (session_range, selection_range, ranges));
        XMLProperty const * prop;
        
-       update_ranges ();
-       
        XMLNodeList spans = root.children ("Range");
        for (XMLNodeList::iterator node_it = spans.begin(); node_it != spans.end(); ++node_it) {
                
@@ -503,6 +389,11 @@ ExportProfileManager::serialize_timespan (TimespanStatePtr state)
 void
 ExportProfileManager::update_ranges () {
        ranges->clear();
+       
+       if (single_range_mode) {
+               ranges->push_back (single_range.get());
+               return;
+       }
 
        /* Session */
 
@@ -526,7 +417,7 @@ ExportProfileManager::update_ranges () {
        }
 }
 
-void
+bool
 ExportProfileManager::init_channel_configs (XMLNodeList nodes)
 {
        channel_configs.clear();
@@ -534,70 +425,16 @@ ExportProfileManager::init_channel_configs (XMLNodeList nodes)
        if (nodes.empty()) {    
                ChannelConfigStatePtr config (new ChannelConfigState (handler->add_channel_config()));
                channel_configs.push_back (config);
-               return;
+               return false;
        }
        
        for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
-               channel_configs.push_back (deserialize_channel_config (**it));
-       }
-}
-
-ExportProfileManager::ChannelConfigStatePtr
-ExportProfileManager::deserialize_channel_config (XMLNode & root)
-{
-
-       ChannelConfigStatePtr state (new ChannelConfigState (handler->add_channel_config()));
-       XMLProperty const * prop;
-       
-       if ((prop = root.property ("split"))) {
-               state->config->set_split(!prop->value().compare ("true"));
-       }
-
-       XMLNodeList channels = root.children ("Channel");
-       for (XMLNodeList::iterator it = channels.begin(); it != channels.end(); ++it) {
-               boost::shared_ptr<ExportChannel> channel (new ExportChannel ());
-       
-               XMLNodeList ports = (*it)->children ("Port");
-               for (XMLNodeList::iterator p_it = ports.begin(); p_it != ports.end(); ++p_it) {
-                       if ((prop = (*p_it)->property ("name"))) {
-                               channel->add_port (dynamic_cast<AudioPort *> (session.engine().get_port_by_name (prop->value())));
-                       }
-               }
-       
-               state->config->register_channel (channel);
-       }
-
-       return state;
-}
-
-XMLNode &
-ExportProfileManager::serialize_channel_config (ChannelConfigStatePtr state)
-{
-       XMLNode * root = new XMLNode ("ExportChannelConfiguration");
-       XMLNode * channel;
-       XMLNode * port_node;
-       
-       root->add_property ("split", state->config->get_split() ? "true" : "false");
-       root->add_property ("channels", to_string (state->config->get_n_chans(), std::dec));
-       
-       uint32_t i = 1;
-       ExportChannelConfiguration::ChannelList const & chan_list = state->config->get_channels();
-       for (ExportChannelConfiguration::ChannelList::const_iterator c_it = chan_list.begin(); c_it != chan_list.end(); ++c_it) {
-               channel = root->add_child ("Channel");
-               if (!channel) { continue; }
-               
-               channel->add_property ("number", to_string (i, std::dec));
-               
-               for (ExportChannel::const_iterator p_it = (*c_it)->begin(); p_it != (*c_it)->end(); ++p_it) {
-                       if ((port_node = channel->add_child ("Port"))) {
-                               port_node->add_property ("name", (*p_it)->name());
-                       }
-               }
-               
-               ++i;
+               ChannelConfigStatePtr config (new ChannelConfigState (handler->add_channel_config()));
+               config->config->set_state (**it);
+               channel_configs.push_back (config);
        }
        
-       return *root;
+       return true;
 }
 
 ExportProfileManager::FormatStatePtr
@@ -630,7 +467,7 @@ ExportProfileManager::save_format_to_disk (FormatPtr format)
        /* Get filename for file */
 
        Glib::ustring new_name = format->name();
-       new_name += ".format";
+       new_name += export_format_suffix;
        
        sys::path new_path (export_config_dir);
        new_path /= new_name;
@@ -638,19 +475,31 @@ ExportProfileManager::save_format_to_disk (FormatPtr format)
        /* Check if format is on disk already */
        FileMap::iterator it;
        if ((it = format_file_map.find (format->id())) != format_file_map.end()) {
-               /* Update data */
-               {
-                       XMLTree tree (it->second.to_string());
+               
+               /* Check if config is not in user config dir */
+               if (it->second.branch_path().to_string().compare (export_config_dir.to_string())) {
+               
+                       /* Write new file */
+               
+                       XMLTree tree (new_path.to_string());
                        tree.set_root (&format->get_state());
                        tree.write();
-               }
                
-               /* Rename if necessary */
+               } else {
                
-               if (new_name.compare (it->second.leaf())) {
-                       sys::rename (it->second, new_path);
+                       /* Update file and rename if necessary */
+               
+                       XMLTree tree (it->second.to_string());
+                       tree.set_root (&format->get_state());
+                       tree.write();
+                       
+                       if (new_name.compare (it->second.leaf())) {
+                               sys::rename (it->second, new_path);
+                       }
                }
                
+               it->second = new_path;
+               
        } else {
                /* Write new file */
                
@@ -703,38 +552,36 @@ ExportProfileManager::get_new_format (FormatPtr original)
        return format;
 }
 
-void
+bool
 ExportProfileManager::init_formats (XMLNodeList nodes)
 {
        formats.clear();
 
-       if (nodes.empty()) {
-               FormatStatePtr format (new FormatState (format_list, FormatPtr ()));
-               formats.push_back (format);
-               return;
-       }
-       
+       bool ok = true;
        for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
-               FormatStatePtr format;
-               if ((format = deserialize_format (**it))) {
+               FormatStatePtr format = deserialize_format (**it);
+               if (format) {
                        formats.push_back (format);
-               }
+               } else { ok = false; }
        }
        
        if (formats.empty ()) {
                FormatStatePtr format (new FormatState (format_list, FormatPtr ()));
                formats.push_back (format);
+               return false;
        }
+       
+       return ok;
 }
 
 ExportProfileManager::FormatStatePtr
 ExportProfileManager::deserialize_format (XMLNode & root)
 {
        XMLProperty * prop;
-       uint32_t id = 0;
+       UUID id;
        
        if ((prop = root.property ("id"))) {
-               id = atoi (prop->value());
+               id = prop->value();
        }
        
        for (FormatList::iterator it = format_list->begin(); it != format_list->end(); ++it) {
@@ -751,7 +598,7 @@ ExportProfileManager::serialize_format (FormatStatePtr state)
 {
        XMLNode * root = new XMLNode ("ExportFormat");
        
-       string id = state->format ? to_string (state->format->id(), std::dec) : "0";
+       string id = state->format ? state->format->id().to_s() : "";
        root->add_property ("id", id);
        
        return *root;
@@ -760,7 +607,7 @@ ExportProfileManager::serialize_format (FormatStatePtr state)
 void
 ExportProfileManager::load_formats ()
 {
-       vector<sys::path> found = find_file ("*.format");
+       vector<sys::path> found = find_file (string_compose ("*%1", export_format_suffix));
 
        for (vector<sys::path>::iterator it = found.begin(); it != found.end(); ++it) {
                load_format_from_disk (*it);
@@ -772,12 +619,13 @@ ExportProfileManager::load_format_from_disk (PBD::sys::path const & path)
 {
        XMLTree const tree (path.to_string());
        FormatPtr format = handler->add_format (*tree.root());
-       format_list->push_back (format);
        
-       /* Handle id to filename mapping */
+       /* Handle id to filename mapping and don't add duplicates to list */
        
        FilePair pair (format->id(), path);
-       format_file_map.insert (pair);
+       if (format_file_map.insert (pair).second) {
+               format_list->push_back (format);
+       }
        
        FormatListChanged ();
 }
@@ -801,34 +649,24 @@ ExportProfileManager::remove_filename_state (FilenameStatePtr state)
        }
 }
 
-void
+bool
 ExportProfileManager::init_filenames (XMLNodeList nodes)
 {
        filenames.clear ();
 
-       if (nodes.empty()) {
+       for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
+               FilenamePtr filename = handler->add_filename();
+               filename->set_state (**it);
+               filenames.push_back (FilenameStatePtr (new FilenameState (filename)));
+       }
+       
+       if (filenames.empty()) {
                FilenameStatePtr filename (new FilenameState (handler->add_filename()));
                filenames.push_back (filename);
-               return;
+               return false;
        }
        
-       for (XMLNodeList::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
-               filenames.push_back (deserialize_filename (**it));
-       }
-}
-
-ExportProfileManager::FilenameStatePtr
-ExportProfileManager::deserialize_filename (XMLNode & root)
-{
-       FilenamePtr filename = handler->add_filename();
-       filename->set_state (root);
-       return FilenameStatePtr (new FilenameState (filename));
-}
-
-XMLNode &
-ExportProfileManager::serialize_filename (FilenameStatePtr state)
-{
-       return state->filename->get_state();
+       return true;
 }
 
 boost::shared_ptr<ExportProfileManager::Warnings>
@@ -884,6 +722,8 @@ ExportProfileManager::check_config (boost::shared_ptr<Warnings> warnings,
        /* Check format and maximum channel count */
        if (!format || !format->type()) {
                warnings->errors.push_back (_("No format selected!"));
+       } else if (!ExportFileFactory::check (format, channel_config->get_n_chans())) {
+               warnings->errors.push_back (_("One or more of the selected formats is not compatible with this system!"));
        } else if (format->channel_limit() < channel_config->get_n_chans()) {
                warnings->errors.push_back
                  (string_compose (_("%1 supports only %2 channels, but you have %3 channels in your channel configuration"),