globally remove all trailing whitespace from ardour code base.
[ardour.git] / libs / surfaces / mackie / device_profile.cc
index 860da3ca2a249c0979f70a479942d0341ce56dc3..c4cd9bf1a8f953885e2dd2b234718ffe4dcdfa7b 100644 (file)
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <cerrno>
 #include <cstdlib>
 #include <cstring>
 #include <glibmm/miscutils.h>
 
 #include "pbd/xml++.h"
 #include "pbd/error.h"
-#include "pbd/pathscanner.h"
+#include "pbd/file_utils.h"
+#include "pbd/stl_delete.h"
+#include "pbd/replace_all.h"
 
 #include "ardour/filesystem_paths.h"
 
 
 #include "i18n.h"
 
-using namespace Mackie;
 using namespace PBD;
 using namespace ARDOUR;
+using namespace ArdourSurface;
+using namespace Mackie;
+
 using std::string;
 using std::vector;
 
@@ -53,38 +58,30 @@ static const char * const devprofile_env_variable_name = "ARDOUR_MCP_PATH";
 static const char* const devprofile_dir_name = "mcp";
 static const char* const devprofile_suffix = ".profile";
 
-static sys::path
-system_devprofile_search_path ()
+static Searchpath
+devprofile_search_path ()
 {
        bool devprofile_path_defined = false;
-        sys::path spath_env (Glib::getenv (devprofile_env_variable_name, devprofile_path_defined));
+        std::string spath_env (Glib::getenv (devprofile_env_variable_name, devprofile_path_defined));
 
        if (devprofile_path_defined) {
                return spath_env;
        }
 
-       SearchPath spath (system_data_search_path());
+       Searchpath spath (ardour_data_search_path());
        spath.add_subdirectory_to_paths(devprofile_dir_name);
 
-       // just return the first directory in the search path that exists
-       SearchPath::const_iterator i = std::find_if(spath.begin(), spath.end(), sys::exists);
-
-       if (i == spath.end()) return sys::path();
-
-       return *i;
+       return spath;
 }
 
-static sys::path
+static std::string
 user_devprofile_directory ()
 {
-       sys::path p(user_config_directory());
-       p /= devprofile_dir_name;
-
-       return p;
+       return Glib::build_filename (user_config_directory(), devprofile_dir_name);
 }
 
 static bool
-devprofile_filter (const string &str, void */*arg*/)
+devprofile_filter (const string &str, void/*arg*/)
 {
        return (str.length() > strlen(devprofile_suffix) &&
                str.find (devprofile_suffix) == (str.length() - strlen (devprofile_suffix)));
@@ -93,53 +90,38 @@ devprofile_filter (const string &str, void */*arg*/)
 void
 DeviceProfile::reload_device_profiles ()
 {
-       DeviceProfile dp;
        vector<string> s;
-       vector<string *> *devprofiles;
-       PathScanner scanner;
-       SearchPath spath (system_devprofile_search_path());
-       spath += user_devprofile_directory ();
+       vector<string> devprofiles;
+       Searchpath spath (devprofile_search_path());
 
-       devprofiles = scanner (spath.to_string(), devprofile_filter, 0, false, true);
+       find_files_matching_filter (devprofiles, spath, devprofile_filter, 0, false, true);
        device_profiles.clear ();
 
-       if (!devprofiles) {
+       if (devprofiles.empty()) {
                error << "No MCP device info files found using " << spath.to_string() << endmsg;
-               std::cerr << "No MCP device info files found using " << spath.to_string() << std::endl;
                return;
        }
 
-       if (devprofiles->empty()) {
-               error << "No MCP device info files found using " << spath.to_string() << endmsg;
-               std::cerr << "No MCP device info files found using " << spath.to_string() << std::endl;
-               return;
-       }
-
-       for (vector<string*>::iterator i = devprofiles->begin(); i != devprofiles->end(); ++i) {
-               string fullpath = *(*i);
+       for (vector<string>::iterator i = devprofiles.begin(); i != devprofiles.end(); ++i) {
+               string fullpath = *i;
+               DeviceProfile dp; // has to be initial every loop or info from last added.
 
                XMLTree tree;
 
-               std::cerr << "Loading " << fullpath << std::endl;
-               
                if (!tree.read (fullpath.c_str())) {
-                       std::cerr << "XML read failed\n";
                        continue;
                }
 
                XMLNode* root = tree.root ();
                if (!root) {
-                       std::cerr << "no root\n";
                        continue;
                }
 
                if (dp.set_state (*root, 3000) == 0) { /* version is ignored for now */
-                       std::cerr << "saved profile " << dp.name() << std::endl;
+                       dp.set_path (fullpath);
                        device_profiles[dp.name()] = dp;
                }
        }
-
-       delete devprofiles;
 }
 
 int
@@ -149,18 +131,15 @@ DeviceProfile::set_state (const XMLNode& node, int /* version */)
        const XMLNode* child;
 
        if (node.name() != "MackieDeviceProfile") {
-               std::cerr << "wrong root\n";
                return -1;
        }
 
        /* name is mandatory */
+
        if ((child = node.child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
-               std::cerr << "no name\n";
                return -1;
        } else {
                _name = prop->value();
-               std::cerr << "got name " << _name << std::endl;
        }
 
        if ((child = node.child ("Buttons")) != 0) {
@@ -171,8 +150,6 @@ DeviceProfile::set_state (const XMLNode& node, int /* version */)
 
                        if ((*i)->name() == "Button") {
 
-                               std::cerr << "foudn a button\n";
-
                                if ((prop = (*i)->property ("name")) == 0) {
                                        error << string_compose ("Button without name in device profile \"%1\" - ignored", _name) << endmsg;
                                        continue;
@@ -180,7 +157,7 @@ DeviceProfile::set_state (const XMLNode& node, int /* version */)
 
                                int id = Button::name_to_id (prop->value());
                                if (id < 0) {
-                                       error << string_compose ("Unknow button ID \"%1\"", prop->value()) << endmsg;
+                                       error << string_compose ("Unknown button ID \"%1\"", prop->value()) << endmsg;
                                        continue;
                                }
 
@@ -192,10 +169,7 @@ DeviceProfile::set_state (const XMLNode& node, int /* version */)
                                        b = _button_map.insert (_button_map.end(), std::pair<Button::ID,ButtonActions> (bid, ButtonActions()));
                                }
 
-                               std::cerr << "checking bindings for button " << bid << std::endl;
-
                                if ((prop = (*i)->property ("plain")) != 0) {
-                                       std::cerr << "Loaded binding between " << bid << " and " << prop->value() << std::endl;
                                        b->second.plain = prop->value ();
                                }
                                if ((prop = (*i)->property ("control")) != 0) {
@@ -215,8 +189,6 @@ DeviceProfile::set_state (const XMLNode& node, int /* version */)
                                }
                        }
                }
-       } else {
-               std::cerr << " no buttons\n";
        }
 
        return 0;
@@ -226,8 +198,10 @@ XMLNode&
 DeviceProfile::get_state () const
 {
        XMLNode* node = new XMLNode ("MackieDeviceProfile");
+       XMLNode* child = new XMLNode ("Name");
 
-       node->add_property ("name", _name);
+       child->add_property ("value", _name);
+       node->add_child_nocopy (*child);
 
        if (_button_map.empty()) {
                return *node;
@@ -239,7 +213,7 @@ DeviceProfile::get_state () const
        for (ButtonActionMap::const_iterator b = _button_map.begin(); b != _button_map.end(); ++b) {
                XMLNode* n = new XMLNode ("Button");
 
-               n->add_property ("name", b->first);
+               n->add_property ("name", Button::id_to_name (b->first));
 
                if (!b->second.plain.empty()) {
                        n->add_property ("plain", b->second.plain);
@@ -291,14 +265,17 @@ DeviceProfile::get_button_action (Button::ID id, int modifier_state) const
 }
 
 void
-DeviceProfile::set_button_action (Button::ID id, int modifier_state, const string& action)
+DeviceProfile::set_button_action (Button::ID id, int modifier_state, const string& act)
 {
        ButtonActionMap::iterator i = _button_map.find (id);
 
        if (i == _button_map.end()) {
-               return;
+               i = _button_map.insert (std::make_pair (id, ButtonActions())).first;
        }
 
+       string action (act);
+       replace_all (action, "<Actions>/", "");
+
        if (modifier_state == MackieControlProtocol::MODIFIER_CONTROL) {
                i->second.control = action;
        } else if (modifier_state == MackieControlProtocol::MODIFIER_SHIFT) {
@@ -314,6 +291,8 @@ DeviceProfile::set_button_action (Button::ID id, int modifier_state, const strin
        if (modifier_state == 0) {
                i->second.plain = action;
        }
+
+       save ();
 }
 
 const string&
@@ -321,3 +300,51 @@ DeviceProfile::name() const
 {
        return _name;
 }
+
+void
+DeviceProfile::set_path (const string& p)
+{
+       _path = p;
+}
+
+/* XXX copied from libs/ardour/utils.cc */
+
+static string
+legalize_for_path (const string& str)
+{
+       string::size_type pos;
+       string illegal_chars = "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
+       string legal;
+
+       legal = str;
+       pos = 0;
+
+       while ((pos = legal.find_first_of (illegal_chars, pos)) != string::npos) {
+               legal.replace (pos, 1, "_");
+               pos += 1;
+       }
+
+       return string (legal);
+}
+
+
+void
+DeviceProfile::save ()
+{
+       std::string fullpath = user_devprofile_directory();
+
+       if (g_mkdir_with_parents (fullpath.c_str(), 0755) < 0) {
+               error << string_compose(_("Session: cannot create user MCP profile folder \"%1\" (%2)"), fullpath, strerror (errno)) << endmsg;
+               return;
+       }
+
+       fullpath = Glib::build_filename (fullpath, legalize_for_path (_name) + ".profile");
+       
+       XMLTree tree;
+       tree.set_root (&get_state());
+
+       if (!tree.write (fullpath)) {
+               error << string_compose ("MCP profile not saved to %1", fullpath) << endmsg;
+       }
+}
+