Handle export presets from config dirs properly. Removed some debug output.
[ardour.git] / libs / ardour / export_profile_manager.cc
index 7fb1b928d3587b19bbe81ffe37bce502575d12b5..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"
@@ -52,25 +53,19 @@ ExportProfileManager::ExportProfileManager (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 */
 
@@ -80,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);
@@ -121,26 +126,32 @@ 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 ()
 {
-       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) {
                load_preset_from_disk (*it);
@@ -150,8 +161,9 @@ ExportProfileManager::load_presets ()
 ExportProfileManager::PresetPtr
 ExportProfileManager::save_preset (string const & name)
 {
+       string filename = export_config_dir.to_string() + "/" + name + export_preset_suffix;
+
        if (!current_preset) {
-               string filename = export_config_dir.to_string() + "/" + name + ".preset";
                current_preset.reset (new ExportPreset (filename, session));
                preset_list.push_back (current_preset);
        }
@@ -166,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;
 }
@@ -197,33 +209,33 @@ void
 ExportProfileManager::load_preset_from_disk (PBD::sys::path const & path)
 {
        PresetPtr preset (new ExportPreset (path.to_string(), session));
-       preset_list.push_back (preset);
        
-       /* 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);
+       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
@@ -241,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());
        }
 }
 
@@ -253,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());
        }
 }
 
@@ -285,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
@@ -310,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) {
                
@@ -361,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 */
 
@@ -384,7 +417,7 @@ ExportProfileManager::update_ranges () {
        }
 }
 
-void
+bool
 ExportProfileManager::init_channel_configs (XMLNodeList nodes)
 {
        channel_configs.clear();
@@ -392,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
@@ -488,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;
@@ -496,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 {
+               
+                       /* Update file and rename if necessary */
                
-               if (new_name.compare (it->second.leaf())) {
-                       sys::rename (it->second, new_path);
+                       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 */
                
@@ -561,28 +552,26 @@ 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
@@ -618,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);
@@ -630,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 ();
 }
@@ -659,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>
@@ -742,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"),