initial pass at session-renaming functionality
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 14 Jul 2011 17:41:06 +0000 (17:41 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 14 Jul 2011 17:41:06 +0000 (17:41 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@9876 d708f5d6-7413-0410-9779-e7cbd77b26cf

13 files changed:
gtk2_ardour/ardour.menus.in
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/ardour_ui_ed.cc
libs/ardour/ardour/session.h
libs/ardour/ardour/session_directory.h
libs/ardour/midi_source.cc
libs/ardour/midi_stretch.cc
libs/ardour/session_directory.cc
libs/ardour/session_state.cc
libs/ardour/smf_source.cc
libs/evoral/evoral/Sequence.hpp
libs/evoral/src/Sequence.cpp

index 417c3b552ab0b788c7e2a3977b3266f15a9b1bda..56c6c6052d25eb9c162c0272b5eea06bc55ec2ff 100644 (file)
@@ -16,6 +16,7 @@
       <separator/>
       <menuitem action='Save'/>
       <menuitem action='SaveAs'/>
+      <menuitem action='Rename'/>
       <menuitem action='Snapshot'/>
       <menuitem action='SaveTemplate'/>
       <menu name='Metadata' action='Metadata'>
index 01321c21f2b02e198cfb84f82dac7dbe18c42cc3..9e34ac0641e30a9234604225565d1dd7d8a4ce99 100644 (file)
@@ -2120,7 +2120,6 @@ ARDOUR_UI::snapshot_session (bool switch_to_it)
        prompter.set_name ("Prompter");
        prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
        prompter.set_title (_("Take Snapshot"));
-       prompter.set_title (_("Take Snapshot"));
        prompter.set_prompt (_("Name of new snapshot"));
 
        if (!switch_to_it) {
@@ -2185,6 +2184,73 @@ ARDOUR_UI::snapshot_session (bool switch_to_it)
        }
 }
 
+/** Ask the user for the name of a new shapshot and then take it.
+ */
+
+void
+ARDOUR_UI::rename_session ()
+{
+       if (!_session) {
+               return;
+       }
+
+       ArdourPrompter prompter (true);
+       string name;
+
+       prompter.set_name ("Prompter");
+       prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
+       prompter.set_title (_("Rename Session"));
+       prompter.set_prompt (_("New session name"));
+
+  again:
+       switch (prompter.run()) {
+       case RESPONSE_ACCEPT:
+       {
+               prompter.get_result (name);
+
+               bool do_rename = (name.length() != 0);
+
+               if (do_rename) {
+                       if (name.find ('/') != string::npos) {
+                               MessageDialog msg (_("To ensure compatibility with various systems\n"
+                                                    "session names may not contain a '/' character"));
+                               msg.run ();
+                               goto again;
+                       }
+                       if (name.find ('\\') != string::npos) {
+                               MessageDialog msg (_("To ensure compatibility with various systems\n"
+                                                    "session names may not contain a '\\' character"));
+                               msg.run ();
+                               goto again;
+                       }
+
+                       switch (_session->rename (name)) {
+                       case -1: {
+                               MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
+                               msg.set_position (WIN_POS_MOUSE);
+                               msg.run ();
+                               goto again;
+                               break;
+                       }
+                       case 0:
+                               break;
+                       default: {
+                               MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
+                               msg.set_position (WIN_POS_MOUSE);
+                               msg.run ();
+                               break;
+                       }
+                       }
+               }
+               
+               break;
+       }
+
+       default:
+               break;
+       }
+}
+
 void
 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
 {
index 047262ec0040025565b8657db3269784dd3f2240..b288961d71c3212914dd5050aa2a54604f2ba4a3 100644 (file)
@@ -578,6 +578,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
        guint32  last_key_press_time;
 
        void snapshot_session (bool switch_to_it);
+       void rename_session ();
 
        Mixer_UI   *mixer;
        int         create_mixer ();
index 712eb0aa3e551b5893dc9aebb19df74e4513f9a3..1379de83c8a930f1c09fc5188e6fe9536161b34f 100644 (file)
@@ -147,6 +147,10 @@ ARDOUR_UI::install_actions ()
        ActionManager::session_sensitive_actions.push_back (act);
        ActionManager::write_sensitive_actions.push_back (act);
 
+       act = ActionManager::register_action (main_actions, X_("Rename"), _("Rename..."), sigc::mem_fun(*this, &ARDOUR_UI::rename_session));
+       ActionManager::session_sensitive_actions.push_back (act);
+       ActionManager::write_sensitive_actions.push_back (act);
+
        act = ActionManager::register_action (main_actions, X_("SaveTemplate"), _("Save Template..."),  sigc::mem_fun(*this, &ARDOUR_UI::save_template));
        ActionManager::session_sensitive_actions.push_back (act);
 
index 6b9010642c81dbede6e9fdeafd3fa282783c1fa5..1daa82dc48eb1f2b1200720c9105dc42630b7c37 100644 (file)
@@ -372,6 +372,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        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&);
 
        static int rename_template (std::string old_name, std::string new_name);
        static int delete_template (std::string name);
index 49ef879ea1efd9c7ec6dbc173c5f77e50585d7f0..16d7115aee3d3c1695fc76551a83d71fa12de833 100644 (file)
@@ -35,6 +35,11 @@ public:
         */
        SessionDirectory (const PBD::sys::path& session_path);
 
+       /**
+        * Change the root path of this SessionDirectory object
+        */
+       SessionDirectory& operator= (const std::string& path);
+
        /**
         * @return the absolute path to the root directory of the session
         */
@@ -124,7 +129,7 @@ protected:
        const std::vector<PBD::sys::path> sub_directories () const;
 
        /// The path to the root of the session directory.
-       const PBD::sys::path m_root_path;
+       PBD::sys::path m_root_path;
 };
 
 } // namespace ARDOUR
index 4c7abd22d8004b352e1509353a32d94f1d214f82..56d31ddee7673dd5dd2d484810da45321aac9852 100644 (file)
@@ -265,6 +265,7 @@ framecnt_t
 MidiSource::midi_write (MidiRingBuffer<framepos_t>& source, framepos_t source_start, framecnt_t duration)
 {
        Glib::Mutex::Lock lm (_lock);
+       cerr << "MidiSource calling write unlocked\n";
        const framecnt_t ret = write_unlocked (source, source_start, duration);
        _last_write_end += duration;
        return ret;
@@ -310,7 +311,7 @@ void
 MidiSource::mark_streaming_write_completed ()
 {
        if (_model) {
-               _model->end_write(false);
+               _model->end_write (false);
        }
 
        _writing = false;
index 4d893d526e11d1435d353cf7b40141aab173b592..4dfab65fd44bdf802790302d5d14d7c951178125 100644 (file)
@@ -103,8 +103,8 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress* progress)
                new_model->append(ev, Evoral::next_event_id());
        }
 
-       new_model->end_write();
-       new_model->set_edited(true);
+       new_model->end_write ();
+       new_model->set_edited (true);
 
        new_src->copy_interpolation_from (src);
 
index 8996b74f61de46b31936d951ae337b98d60283c2..36a01fb77d532067727f030cc2a4a6bcfec54de9 100644 (file)
@@ -37,6 +37,13 @@ SessionDirectory::SessionDirectory (const path& session_path)
 
 }
 
+SessionDirectory& 
+SessionDirectory::operator= (const std::string& newpath)
+{
+       m_root_path = newpath;
+       return *this;
+}
+
 bool
 SessionDirectory::create ()
 {
index 8022c7670c20a18c6fbe4ab2d00952f01cbd1cd9..c8323047ebc05829baa361fa57aae6820bbbeb7f 100644 (file)
@@ -48,6 +48,8 @@
 #include <sys/mount.h>
 #endif
 
+#include <glib.h>
+
 #include <glibmm.h>
 #include <glibmm/thread.h>
 
@@ -817,7 +819,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
 
        } else {
 
-               if (rename (tmp_path.to_string().c_str(), xml_path.to_string().c_str()) != 0) {
+               if (::rename (tmp_path.to_string().c_str(), xml_path.to_string().c_str()) != 0) {
                        error << string_compose (_("could not rename temporary session file %1 to %2"),
                                        tmp_path.to_string(), xml_path.to_string()) << endmsg;
                        sys::remove (tmp_path);
@@ -2950,7 +2952,7 @@ Session::cleanup_sources (CleanupReport& rep)
                                                          peakpath, _path, strerror (errno))
                                      << endmsg;
                                /* try to back out */
-                               rename (newpath.c_str(), _path.c_str());
+                               ::rename (newpath.c_str(), _path.c_str());
                                goto out;
                        }
                }
@@ -3654,3 +3656,144 @@ Session::solo_cut_control() const
 
         return _solo_cut_control;
 }
+
+int
+Session::rename (const std::string& new_name)
+{
+       string legal_name = legalize_for_path (new_name);
+       string newpath;
+       string oldstr;
+       string newstr;
+       bool first = true;
+
+#define RENAME ::rename
+
+       /* Rename:
+
+        * session directory
+        * interchange subdirectory
+        * session file
+        * session history
+        
+        * Backup files are left unchanged and not renamed.
+        */
+
+       /* pass one: not 100% safe check that the new directory names don't
+        * already exist ...
+        */
+
+       for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+               vector<string> v;
+
+               oldstr = (*i).path;
+
+               /* this is a stupid hack because Glib::path_get_dirname() is
+                * lexical-only, and so passing it /a/b/c/ gives a different
+                * result than passing it /a/b/c ...
+                */
+
+               if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
+                       oldstr = oldstr.substr (0, oldstr.length() - 1);
+               }
+
+               string base = Glib::path_get_dirname (oldstr);
+               string p = Glib::path_get_basename (oldstr);
+
+               newstr = Glib::build_filename (base, legal_name);
+               
+               if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
+                       return -1;
+               }
+       }
+
+       /* Session dirs */
+       
+       for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+               vector<string> v;
+
+               oldstr = (*i).path;
+
+               /* this is a stupid hack because Glib::path_get_dirname() is
+                * lexical-only, and so passing it /a/b/c/ gives a different
+                * result than passing it /a/b/c ...
+                */
+
+               if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
+                       oldstr = oldstr.substr (0, oldstr.length() - 1);
+               }
+
+               string base = Glib::path_get_dirname (oldstr);
+               string p = Glib::path_get_basename (oldstr);
+
+               newstr = Glib::build_filename (base, legal_name);
+
+               cerr << "Rename " << oldstr << " => " << newstr << endl;                
+
+               if (RENAME (oldstr.c_str(), newstr.c_str()) != 0) {
+                       return 1;
+               }
+
+               if (first) {
+                       (*_session_dir) = newstr;
+                       newpath = newstr;
+                       first = 1;
+               }
+
+               /* directory below interchange */
+
+               v.push_back (newstr);
+               v.push_back (interchange_dir_name);
+               v.push_back (p);
+
+               oldstr = Glib::build_filename (v);
+
+               v.clear ();
+               v.push_back (newstr);
+               v.push_back (interchange_dir_name);
+               v.push_back (legal_name);
+
+               newstr = Glib::build_filename (v);
+               
+               cerr << "Rename " << oldstr << " => " << newstr << endl;
+               
+               if (RENAME (oldstr.c_str(), newstr.c_str()) != 0) {
+                       return 1;
+               }
+       }
+
+       /* state file */
+       
+       oldstr = Glib::build_filename (newpath, _current_snapshot_name) + statefile_suffix;
+       newstr= Glib::build_filename (newpath, legal_name) + statefile_suffix;
+       
+       cerr << "Rename " << oldstr << " => " << newstr << endl;                
+
+       if (RENAME (oldstr.c_str(), newstr.c_str()) != 0) {
+               return 1;
+       }
+
+       /* history file */
+       
+       oldstr = Glib::build_filename (newpath, _current_snapshot_name) + history_suffix;
+       newstr = Glib::build_filename (newpath, legal_name) + history_suffix;
+       
+       cerr << "Rename " << oldstr << " => " << newstr << endl;                
+
+       if (RENAME (oldstr.c_str(), newstr.c_str()) != 0) {
+               return 1;
+       }
+
+       _path = newpath;
+       _current_snapshot_name = new_name;
+       _name = new_name;
+
+       set_dirty ();
+
+       /* save state again to get everything just right */
+
+       save_state (_current_snapshot_name);
+
+       return 0;
+
+#undef RENAME
+}
index 158c9c144d66c18de5c80554f4f8d622bab495d5..9078a17608aaad0c2a7eebb002a2dd66cdf37e0a 100644 (file)
@@ -551,8 +551,8 @@ SMFSource::load_model (bool lock, bool force_reload)
                have_event_id = false;
        }
 
-       //_model->end_write (_length_beats, false, true);
-       _model->end_write (false);
+       _model->end_write (_length_beats, false, true);
+       //_model->end_write (false);
        _model->set_edited (false);
 
        _model_iter = _model->begin();
index 922b7594d4e42f21d6b6c768231d1da674dcd8a5..298ef48e52ec979e75c6a035fbdbdf79d9e188ac 100644 (file)
@@ -97,7 +97,7 @@ public:
 
        void start_write();
        bool writing() const { return _writing; }
-       void end_write(bool delete_stuck=false);
+        void end_write (Time when=0, bool delete_stuck=false, bool resolve=false);
 
        void append(const Event<Time>& ev, Evoral::event_id_t evid);
 
index 7296ff4e1c55ce4fe5235e4690940af1b97f6f10..5c06e8c2ca858e6e237ef8e8c681bc4e626e496c 100644 (file)
@@ -623,7 +623,7 @@ Sequence<Time>::start_write()
  */
 template<typename Time>
 void
-Sequence<Time>::end_write (bool delete_stuck)
+Sequence<Time>::end_write (Time when, bool delete_stuck, bool resolve)
 {
        WriteLock lock(write_lock());
 
@@ -631,27 +631,40 @@ Sequence<Time>::end_write (bool delete_stuck)
                return;
        }
 
+       if (resolve) {
+               assert (when != 0);
+               assert (!delete_stuck);
+       }
+
        DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 : end_write (%2 notes)\n", this, _notes.size()));
 
-        if (!_percussive && delete_stuck) {
+        if (!_percussive) {
+
                 for (typename Notes::iterator n = _notes.begin(); n != _notes.end() ;) {
                         typename Notes::iterator next = n;
                         ++next;
                        
                         if ((*n)->length() == 0) {
-                                cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
-                                _notes.erase(n);
-                        }
-                        
+                               if (delete_stuck) {
+                                       cerr << "WARNING: Stuck note lost: " << (*n)->note() << endl;
+                                       _notes.erase(n);
+                               } else if (resolve) {
+                                       if (when <= (*n)->time()) {
+                                               cerr << "WARNING: Stuck note resolution - end time @ " 
+                                                    << when << " is before note on: " << (**n) << endl;
+                                               _notes.erase (*n);
+                                       } else {
+                                               (*n)->set_length (when - (*n)->time());
+                                               cerr << "WARNING: resolved note-on with no note-off to generate " << (**n) << endl;
+                                       }
+                               }
+                       }
+
                         n = next;
                 }
         }
 
        for (int i = 0; i < 16; ++i) {
-               if (!_write_notes[i].empty()) {
-                       cerr << "WARNING: Sequence<Time>::end_write: Channel " << i << " has "
-                                       << _write_notes[i].size() << " stuck notes" << endl;
-               }
                _write_notes[i].clear();
        }
 
@@ -925,7 +938,7 @@ Sequence<Time>::append_note_off_unlocked (NotePtr note)
                         nn->set_off_velocity (note->velocity());
 
                         _write_notes[note->channel()].erase(n);
-                        DEBUG_TRACE (DEBUG::Sequence, string_compose ("resolved note, length: %1\n", nn->length()));
+                        DEBUG_TRACE (DEBUG::Sequence, string_compose ("resolved note @ %2 length: %1\n", nn->length(), nn->time()));
                         resolved = true;
                         break;
                 }