Add GPL boilerplate.
[ardour.git] / gtk2_ardour / processor_box.cc
index 96305ab19dafbf4ca5926c36c11e1eec49a2e0ea..cc322df13d060a00583ed68ee4f7c0df7cf1f13f 100644 (file)
 #include <gtkmm2ext/utils.h>
 #include <gtkmm2ext/choice.h>
 #include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/stop_signal.h>
 #include <gtkmm2ext/doi.h>
 
 #include "ardour/amp.h"
 #include "ardour/ardour.h"
-#include "ardour/audio_diskstream.h"
 #include "ardour/audio_track.h"
 #include "ardour/audioengine.h"
 #include "ardour/internal_send.h"
@@ -88,6 +86,8 @@ using namespace Gtkmm2ext;
 
 ProcessorBox* ProcessorBox::_current_processor_box = 0;
 RefPtr<Action> ProcessorBox::paste_action;
+RefPtr<Action> ProcessorBox::cut_action;
+RefPtr<Action> ProcessorBox::rename_action;
 Glib::RefPtr<Gdk::Pixbuf> SendProcessorEntry::_slider;
 
 ProcessorEntry::ProcessorEntry (boost::shared_ptr<Processor> p, Width w)
@@ -106,8 +106,8 @@ ProcessorEntry::ProcessorEntry (boost::shared_ptr<Processor> p, Width w)
        _active.set_active (_processor->active ());
        _active.signal_toggled().connect (sigc::mem_fun (*this, &ProcessorEntry::active_toggled));
        
-       _processor->ActiveChanged.connect (active_connection, boost::bind (&ProcessorEntry::processor_active_changed, this), gui_context());
-       _processor->NameChanged.connect (name_connection, boost::bind (&ProcessorEntry::processor_name_changed, this), gui_context());
+       _processor->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&ProcessorEntry::processor_active_changed, this), gui_context());
+       _processor->PropertyChanged.connect (name_connection, invalidator (*this), ui_bind (&ProcessorEntry::processor_property_changed, this, _1), gui_context());
 }
 
 EventBox&
@@ -163,9 +163,11 @@ ProcessorEntry::processor_active_changed ()
 }
 
 void
-ProcessorEntry::processor_name_changed ()
+ProcessorEntry::processor_property_changed (const PropertyChange& what_changed)
 {
-       _name.set_text (name ());
+       if (what_changed.contains (ARDOUR::Properties::name)) {
+               _name.set_text (name ());
+       }
 }
 
 string
@@ -174,10 +176,6 @@ ProcessorEntry::name () const
        boost::shared_ptr<Send> send;
        string name_display;
        
-       if (!_processor->active()) {
-               name_display = " (";
-       }
-       
        if ((send = boost::dynamic_pointer_cast<Send> (_processor)) != 0 &&
            !boost::dynamic_pointer_cast<InternalSend>(_processor)) {
                
@@ -211,10 +209,6 @@ ProcessorEntry::name () const
                
        }
        
-       if (!_processor->active()) {
-               name_display += ')';
-       }
-       
        return name_display;
 }
 
@@ -229,7 +223,7 @@ SendProcessorEntry::SendProcessorEntry (boost::shared_ptr<Send> s, Width w)
        _vbox.pack_start (_fader);
 
        _adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &SendProcessorEntry::gain_adjusted));
-       _send->amp()->gain_control()->Changed.connect (send_gain_connection, boost::bind (&SendProcessorEntry::show_gain, this), gui_context());
+       _send->amp()->gain_control()->Changed.connect (send_gain_connection, invalidator (*this), boost::bind (&SendProcessorEntry::show_gain, this), gui_context());
        show_gain ();
 }
 
@@ -326,9 +320,9 @@ ProcessorBox::set_route (boost::shared_ptr<Route> r)
        no_processor_redisplay = false;
        _route = r;
 
-       _route->processors_changed.connect (connections, ui_bind (&ProcessorBox::route_processors_changed, this, _1), gui_context());
-       _route->DropReferences.connect (connections, boost::bind (&ProcessorBox::route_going_away, this), gui_context());
-       _route->NameChanged.connect (connections, boost::bind (&ProcessorBox::route_name_changed, this), gui_context());
+       _route->processors_changed.connect (connections, invalidator (*this), ui_bind (&ProcessorBox::route_processors_changed, this, _1), gui_context());
+       _route->DropReferences.connect (connections, invalidator (*this), boost::bind (&ProcessorBox::route_going_away, this), gui_context());
+       _route->PropertyChanged.connect (connections, invalidator (*this), ui_bind (&ProcessorBox::route_property_changed, this, _1), gui_context());
 
        redisplay_processors ();
 }
@@ -492,6 +486,7 @@ ProcessorBox::show_processor_menu (gint arg)
                }
        }
 
+        cut_action->set_sensitive (can_cut());
        paste_action->set_sensitive (!_rr_selection.processors.empty());
 
        processor_menu->popup (1, arg);
@@ -721,6 +716,11 @@ ProcessorBox::selection_changed ()
 {
        bool sensitive = (processor_display.selection().empty()) ? false : true;
        ActionManager::set_sensitive (ActionManager::plugin_selection_sensitive_actions, sensitive);
+
+       /* disallow rename for multiple selections and for plugin inserts */
+       rename_action->set_sensitive (
+               processor_display.selection().size() == 1 && boost::dynamic_pointer_cast<PluginInsert> (processor_display.selection().front()->processor()) == 0
+               );
 }
 
 void
@@ -741,7 +741,8 @@ ProcessorBox::choose_plugin ()
        _get_plugin_selector()->set_interested_object (*this);
 }
 
-void
+/** @return true if an error occurred, otherwise false */
+bool
 ProcessorBox::use_plugins (const SelectedPlugins& plugins)
 {
        for (SelectedPlugins::const_iterator p = plugins.begin(); p != plugins.end(); ++p) {
@@ -756,6 +757,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
 
                if (_route->add_processor (processor, _placement, &err_streams)) {
                        weird_plugin_dialog (**p, err_streams);
+                       return true;
                        // XXX SHAREDPTR delete plugin here .. do we even need to care?
                } else {
 
@@ -764,12 +766,14 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
                        }
                }
        }
+
+       return false;
 }
 
 void
 ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams)
 {
-       ArdourDialog dialog (_("ardour: weird plugin dialog"));
+       ArdourDialog dialog (_("Plugin Incompatibility"));
        Label label;
 
        string text = string_compose(_("You attempted to add the plugin \"%1\" at index %2.\n"),
@@ -794,7 +798,7 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams)
                text += string_compose("\t%1 ", streams.count.n_audio()) + _("audio channel(s)\n");
        }
 
-       text += _("\nArdour is unable to insert this plugin here.\n");
+       text += string_compose (_("\n%1 is unable to insert this plugin here.\n"), PROGRAM_NAME);
        label.set_text(text);
 
        dialog.get_vbox()->pack_start (label);
@@ -988,7 +992,7 @@ ProcessorBox::build_processor_tooltip (EventBox& box, string start)
                tip += (*i)->processor()->name();
        }
        
-       ARDOUR_UI::instance()->tooltips().set_tip (box, tip);
+       ARDOUR_UI::instance()->set_tip (box, tip);
 }
 
 void
@@ -1015,14 +1019,15 @@ ProcessorBox::compute_processor_sort_keys ()
 
                /* now tell them about the problem */
 
-               ArdourDialog dialog (_("ardour: weird plugin dialog"));
+               ArdourDialog dialog (_("Plugin Incompatibility"));
                Label label;
 
                label.set_text (_("\
-You cannot reorder this set of processors\n\
+You cannot reorder these plugins/sends/inserts\n\
 in that way because the inputs and\n\
-outputs do not work correctly."));
+outputs will not work correctly."));
 
+               dialog.get_vbox()->set_border_width (12);
                dialog.get_vbox()->pack_start (label);
                dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
 
@@ -1051,6 +1056,27 @@ ProcessorBox::rename_processors ()
        }
 }
 
+bool
+ProcessorBox::can_cut () const
+{
+        vector<boost::shared_ptr<Processor> > sel;
+
+        get_selected_processors (sel);
+        
+        /* cut_processors () does not cut inserts */
+
+        for (vector<boost::shared_ptr<Processor> >::const_iterator i = sel.begin (); i != sel.end (); ++i) {
+                
+               if (boost::dynamic_pointer_cast<PluginInsert>((*i)) != 0 ||
+                   (boost::dynamic_pointer_cast<Send>((*i)) != 0) ||
+                   (boost::dynamic_pointer_cast<Return>((*i)) != 0)) {
+                        return true;
+                }
+        }
+        
+        return false;
+}
+
 void
 ProcessorBox::cut_processors ()
 {
@@ -1218,11 +1244,27 @@ ProcessorBox::rename_processor (boost::shared_ptr<Processor> processor)
        case Gtk::RESPONSE_ACCEPT:
                name_prompter.get_result (result);
                if (result.length()) {
-                       if (_session->route_by_name (result)) {
-                               ARDOUR_UI::instance()->popup_error (_("A track already exists with that name."));
-                               return;
-                       }
-                       processor->set_name (result);
+
+                       int tries = 0;
+                       string test = result;
+
+                       while (tries < 100) {
+                               if (_session->io_name_is_legal (test)) {
+                                       result = test;
+                                       break;
+                               }
+                               tries++;
+
+                               test = string_compose ("%1-%2", result, tries);
+                       }
+
+                       if (tries < 100) {
+                               processor->set_name (result);
+                       } else {
+                               /* unlikely! */
+                               ARDOUR_UI::instance()->popup_error
+                                       (string_compose (_("At least 100 IO objects exist with a name like %1 - name not changed"), result));
+                       }
                }
                break;
        }
@@ -1279,19 +1321,35 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr
 
                                XMLNode n (**niter);
                                Send::make_unique (n, *_session);
-                               p.reset (new Send (*_session, _route->mute_master(), n));
+                                Send* s = new Send (*_session, _route->mute_master());
+                                if (s->set_state (n, Stateful::loading_state_version)) {
+                                        delete s;
+                                        return;
+                                }
+
+                               p.reset (s);
+                                        
 
                        } else if (type->value() == "return") {
 
                                XMLNode n (**niter);
                                Return::make_unique (n, *_session);
-                               p.reset (new Return (*_session, **niter));
+                                Return* r = new Return (*_session);
+
+                                if (r->set_state (n, Stateful::loading_state_version)) {
+                                        delete r;
+                                        return;
+                                }
+
+                               p.reset (r);
 
                        } else {
                                /* XXX its a bit limiting to assume that everything else
                                   is a plugin.
                                */
-                               p.reset (new PluginInsert (*_session, **niter));
+
+                               p.reset (new PluginInsert (*_session));
+                                p->set_state (**niter, Stateful::current_state_version);
                        }
 
                        copies.push_back (p);
@@ -1330,10 +1388,10 @@ ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r)
 }
 
 void
-ProcessorBox::get_selected_processors (ProcSelection& processors)
+ProcessorBox::get_selected_processors (ProcSelection& processors) const
 {
-       list<ProcessorEntry*> selection = processor_display.selection ();
-       for (list<ProcessorEntry*>::iterator i = selection.begin(); i != selection.end(); ++i) {
+       const list<ProcessorEntry*> selection = processor_display.selection ();
+       for (list<ProcessorEntry*>::const_iterator i = selection.begin(); i != selection.end(); ++i) {
                processors.push_back ((*i)->processor ());
        }
 }
@@ -1373,7 +1431,7 @@ ProcessorBox::clear_processors ()
        choices.push_back (_("Cancel"));
        choices.push_back (_("Yes, remove them all"));
 
-       Gtkmm2ext::Choice prompter (prompt, choices);
+       Gtkmm2ext::Choice prompter (_("Remove processors"), prompt, choices);
 
        if (prompter.run () == 1) {
                _route->clear_processors (PreFader);
@@ -1398,7 +1456,7 @@ ProcessorBox::clear_processors (Placement p)
        choices.push_back (_("Cancel"));
        choices.push_back (_("Yes, remove them all"));
 
-       Gtkmm2ext::Choice prompter (prompt, choices);
+       Gtkmm2ext::Choice prompter (_("Remove processors"), prompt, choices);
 
        if (prompter.run () == 1) {
                _route->clear_processors (p);
@@ -1548,9 +1606,9 @@ ProcessorBox::register_actions ()
                        sigc::ptr_fun (ProcessorBox::rb_clear_post));
 
        /* standard editing stuff */
-       act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),
-                       sigc::ptr_fun (ProcessorBox::rb_cut));
-       ActionManager::plugin_selection_sensitive_actions.push_back(act);
+       cut_action = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),
+                                                     sigc::ptr_fun (ProcessorBox::rb_cut));
+       ActionManager::plugin_selection_sensitive_actions.push_back(cut_action);
        act = ActionManager::register_action (popup_act_grp, X_("copy"), _("Copy"),
                        sigc::ptr_fun (ProcessorBox::rb_copy));
        ActionManager::plugin_selection_sensitive_actions.push_back(act);
@@ -1561,9 +1619,8 @@ ProcessorBox::register_actions ()
 
        paste_action = ActionManager::register_action (popup_act_grp, X_("paste"), _("Paste"),
                        sigc::ptr_fun (ProcessorBox::rb_paste));
-       act = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),
+       rename_action = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),
                        sigc::ptr_fun (ProcessorBox::rb_rename));
-       ActionManager::plugin_selection_sensitive_actions.push_back(act);
        ActionManager::register_action (popup_act_grp, X_("selectall"), _("Select All"),
                        sigc::ptr_fun (ProcessorBox::rb_select_all));
        ActionManager::register_action (popup_act_grp, X_("deselectall"), _("Deselect All"),
@@ -1763,9 +1820,13 @@ ProcessorBox::rb_edit ()
 }
 
 void
-ProcessorBox::route_name_changed ()
+ProcessorBox::route_property_changed (const PropertyChange& what_changed)
 {
-       ENSURE_GUI_THREAD (*this, &ProcessorBox::route_name_changed)
+       if (!what_changed.contains (ARDOUR::Properties::name)) {
+               return;
+       }
+
+       ENSURE_GUI_THREAD (*this, &ProcessorBox::route_property_changed, what_changed);
 
        boost::shared_ptr<Processor> processor;
        boost::shared_ptr<PluginInsert> plugin_insert;