add initial code (and stubs) for save-as related functionality
authorPaul Davis <paul@linuxaudiosystems.com>
Sun, 11 Jan 2015 17:15:14 +0000 (12:15 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Sun, 11 Jan 2015 17:15:14 +0000 (12:15 -0500)
libs/ardour/ardour/session.h
libs/ardour/session_state.cc

index 895bbd6f1758053eae5700c518f15d5763583c23..83af5c2da6bf26d28d280be97546af68b17b71aa 100644 (file)
@@ -392,7 +392,21 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
        framecnt_t worst_input_latency ()  const { return _worst_input_latency; }
        framecnt_t worst_track_latency ()  const { return _worst_track_latency; }
        framecnt_t worst_playback_latency () const { return _worst_output_latency + _worst_track_latency; }
+       
+       int consolidate_all_media ();
+
+       struct SaveAs {
+               std::string new_parent_folder;
+               std::string new_name;
+               bool        switch_to;
+               bool        copy_media;
+               bool        copy_external;
+               
+               /* emitted as we make progress */
+               PBD::Signal3<bool,float,int64_t,int64_t> Progress;
+       };
 
+       int save_as (SaveAs&);
        int save_state (std::string snapshot_name, bool pending = false, bool switch_to_snapshot = false);
        int restore_state (std::string snapshot_name);
        int save_template (std::string template_name);
@@ -401,7 +415,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
        void remove_state (std::string snapshot_name);
        void rename_state (std::string old_name, std::string new_name);
        void remove_pending_capture_state ();
-       int rename (const std::string&);
+       int rename (const std::string&, bool after_copy = false);
        bool get_nsm_state () const { return _under_nsm_control; }
        void set_nsm_state (bool state) { _under_nsm_control = state; }
        bool save_default_options ();
index a44eeaf95add61220ab071f7274cf1b6eb0bb01f..3b26e376fb98a85ff51a0143dc8c53bdac327f68 100644 (file)
@@ -54,6 +54,7 @@
 
 #include <glibmm.h>
 #include <glibmm/threads.h>
+#include <glibmm/fileutils.h>
 
 #include <boost/algorithm/string.hpp>
 
@@ -3598,7 +3599,7 @@ Session::solo_cut_control() const
 }
 
 int
-Session::rename (const std::string& new_name)
+Session::rename (const std::string& new_name, bool after_copy)
 {
        string legal_name = legalize_for_path (new_name);
        string newpath;
@@ -3742,11 +3743,12 @@ Session::rename (const std::string& new_name)
                }
        }
 
-       /* remove old name from recent sessions */
-
-       remove_recent_sessions (_path);
+       if (!after_copy) {
+               /* remove old name from recent sessions */
+               remove_recent_sessions (_path);
+               _path = newpath;
+       }
 
-       _path = newpath;
        _current_snapshot_name = new_name;
        _name = new_name;
 
@@ -3922,3 +3924,136 @@ Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,
 
        return ret;
 }
+
+static
+bool accept_all_files (string const &, void *)
+{
+       return true;
+}
+
+int
+Session::save_as (SaveAs& saveas)
+{
+       vector<string> files;
+       string current_folder = Glib::path_get_dirname (_path);
+       string new_folder = legalize_for_path (saveas.new_name);
+       string to_dir = Glib::build_filename (saveas.new_parent_folder, saveas.new_name);
+       int64_t total_bytes = 0;
+       int64_t copied = 0;
+       int64_t cnt = 0;
+       int64_t all = 0;
+
+       /* get total size */
+
+       for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
+               
+               /* need to clear this because
+                * find_files_matching_filter() is cumulative
+                */
+               
+               files.clear ();
+               
+               find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
+               
+               all += files.size();
+               
+               for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
+                       GStatBuf gsb;
+                       
+                       if ((*i).find (X_("interchange")) == string::npos || saveas.copy_media) {
+                               g_stat ((*i).c_str(), &gsb);
+                               total_bytes += gsb.st_size;
+                       }
+               }
+       }
+
+       try {
+               for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
+                       
+                       /* need to clear this because
+                        * find_files_matching_filter() is cumulative
+                        */
+
+                       files.clear ();
+                       
+                       find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
+                       
+                       const size_t prefix_len = (*sd).path.size();
+                       
+                       for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
+                               std::string from = *i;
+                               std::string to = Glib::build_filename (to_dir, (*i).substr(prefix_len));
+
+                               g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755);
+                               
+                               if ((*i).find (X_("interchange")) == string::npos || saveas.copy_media) {
+                                       
+                                       GStatBuf gsb;
+                                       g_stat ((*i).c_str(), &gsb);
+                                       
+                                       if (!copy_file (from, to)) {
+                                               throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
+                                       }
+                                       
+                                       copied += gsb.st_size;
+                                       double fraction = (double) copied / total_bytes;
+                                       
+                                       /* tell someone "X percent, file M of
+                                        * N"; M is one-based
+                                        */
+
+                                       cnt++;
+                                       
+                                       if (!saveas.Progress (fraction, cnt, all)) {
+                                               throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
+                                       }
+                               }
+                       }
+                       
+                       /* now modify our _path setting so that we refer to the copy we've just
+                        * created. The filename of the session file hasn't
+                        * been changed yet.
+                        */
+                       
+                       _path = new_folder;
+                       
+                       /* _path now refers to the copy we just created, but that copy
+                        * contains references to the wrong name and so forth.
+                        * Use rename() to actually change the name 
+                        */
+                       
+                       if (rename (saveas.new_name, true)) {
+                               throw Glib::FileError (Glib::FileError::NAME_TOO_LONG, "rename failed");
+                       }
+                       
+                       if (saveas.copy_media && saveas.copy_external) {
+                               if (consolidate_all_media()) {
+                                       throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
+                               }
+                       }
+               }
+
+       } catch (...) {
+               
+               /* recursively remove all the directories */
+               
+               /* XXX HOW TO DO THIS */
+               
+               /* return error */
+               
+               return -1;
+       }
+       
+       return 0;
+}
+
+
+/** Check all sources used by the current snapshot
+ *  and make a copy of any external media within
+ *  the session.
+ */
+int
+Session::consolidate_all_media ()
+{
+       return 0;
+}