627bada5715bf64a46cc3c5385d1df85f565666d
[ardour.git] / gtk2_ardour / processor_box.cc
1 /*
2     Copyright (C) 2000-2004 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <cmath>
21 #include <iostream>
22 #include <set>
23
24 #include <sigc++/bind.h>
25
26 #include "pbd/convert.h"
27
28 #include <glibmm/miscutils.h>
29
30 #include <gtkmm/messagedialog.h>
31
32 #include <gtkmm2ext/gtk_ui.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/choice.h>
35 #include <gtkmm2ext/utils.h>
36 #include <gtkmm2ext/stop_signal.h>
37 #include <gtkmm2ext/doi.h>
38 #include <gtkmm2ext/window_title.h>
39
40 #include "ardour/ardour.h"
41 #include "ardour/session.h"
42 #include "ardour/audioengine.h"
43 #include "ardour/route.h"
44 #include "ardour/audio_track.h"
45 #include "ardour/audio_diskstream.h"
46 #include "ardour/send.h"
47 #include "ardour/plugin_insert.h"
48 #include "ardour/port_insert.h"
49 #include "ardour/ladspa_plugin.h"
50 #include "ardour/profile.h"
51
52 #include "ardour_ui.h"
53 #include "ardour_dialog.h"
54 #include "public_editor.h"
55 #include "processor_box.h"
56 #include "keyboard.h"
57 #include "plugin_selector.h"
58 #include "route_processor_selection.h"
59 #include "mixer_ui.h"
60 #include "actions.h"
61 #include "plugin_ui.h"
62 #include "io_selector.h"
63 #include "utils.h"
64 #include "gui_thread.h"
65
66 #include "i18n.h"
67
68 #ifdef HAVE_AUDIOUNITS
69 class AUPluginUI;
70 #endif
71
72 using namespace sigc;
73 using namespace ARDOUR;
74 using namespace PBD;
75 using namespace Gtk;
76 using namespace Glib;
77 using namespace Gtkmm2ext;
78
79 ProcessorBox* ProcessorBox::_current_processor_box = 0;
80 RefPtr<Action> ProcessorBox::paste_action;
81 bool ProcessorBox::get_colors = true;
82 Gdk::Color* ProcessorBox::active_processor_color;
83 Gdk::Color* ProcessorBox::inactive_processor_color;
84
85 ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel, 
86                             RouteRedirectSelection & rsel, bool owner_is_mixer)
87         : _session(sess), 
88           _owner_is_mixer (owner_is_mixer), 
89           _placement(pcmnt), 
90           _plugin_selector(plugsel),
91           _rr_selection(rsel)
92 {
93         if (get_colors) {
94                 active_processor_color = new Gdk::Color;
95                 inactive_processor_color = new Gdk::Color;
96                 set_color (*active_processor_color, rgba_from_style ("ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_ACTIVE, false ));
97                 set_color (*inactive_processor_color, rgba_from_style ("ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_NORMAL, false ));
98                 get_colors = false;
99         }
100
101         _width = Wide;
102         processor_menu = 0;
103         send_action_menu = 0;
104         processor_drag_in_progress = false;
105         no_processor_redisplay = false;
106         ignore_delete = false;
107
108         model = ListStore::create(columns);
109
110         RefPtr<TreeSelection> selection = processor_display.get_selection();
111         selection->set_mode (Gtk::SELECTION_MULTIPLE);
112         selection->signal_changed().connect (mem_fun (*this, &ProcessorBox::selection_changed));
113
114         processor_display.set_model (model);
115         processor_display.append_column (X_("notshown"), columns.text);
116         processor_display.set_name ("ProcessorSelector");
117         processor_display.set_headers_visible (false);
118         processor_display.set_reorderable (true);
119         processor_display.set_size_request (-1, 40);
120         processor_display.get_column(0)->set_sizing(TREE_VIEW_COLUMN_FIXED);
121         processor_display.get_column(0)->set_fixed_width(48);
122         processor_display.add_object_drag (columns.processor.index(), "processors");
123         processor_display.signal_drop.connect (mem_fun (*this, &ProcessorBox::object_drop));
124
125         TreeViewColumn* name_col = processor_display.get_column(0);
126         CellRendererText* renderer = dynamic_cast<CellRendererText*>(processor_display.get_column_cell_renderer (0));
127         name_col->add_attribute(renderer->property_foreground_gdk(), columns.color);
128
129         processor_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
130         
131         model->signal_row_deleted().connect (mem_fun (*this, &ProcessorBox::row_deleted));
132
133         processor_scroller.add (processor_display);
134         processor_eventbox.add (processor_scroller);
135         
136         processor_scroller.set_size_request (-1, 40);
137
138         pack_start (processor_eventbox, true, true);
139
140         processor_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (ProcessorBox::enter_box), this));
141
142         processor_display.signal_button_press_event().connect (mem_fun(*this, &ProcessorBox::processor_button_press_event), false);
143         processor_display.signal_button_release_event().connect (mem_fun(*this, &ProcessorBox::processor_button_release_event));
144 }
145
146 ProcessorBox::~ProcessorBox ()
147 {
148 }
149
150 void
151 ProcessorBox::set_route (boost::shared_ptr<Route> r)
152 {
153         connections.clear ();
154
155         _route = r;
156
157         connections.push_back (_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors)));
158         connections.push_back (_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away)));
159         connections.push_back (_route->NameChanged.connect (mem_fun(*this, &ProcessorBox::route_name_changed)));
160
161         redisplay_processors ();
162 }
163
164 void
165 ProcessorBox::route_going_away ()
166 {
167         /* don't keep updating display as processors are deleted */
168         no_processor_redisplay = true;
169 }
170
171
172 void
173 ProcessorBox::object_drop (const list<boost::shared_ptr<Processor> >& procs)
174 {
175         for (std::list<boost::shared_ptr<Processor> >::const_iterator i = procs.begin(); i != procs.end(); ++i) {
176
177                 XMLNode& state = (*i)->get_state ();
178                 XMLNodeList nlist;
179                 nlist.push_back (&state);
180                 paste_processor_state (nlist);
181                 delete &state;
182         }
183 }
184
185 void
186 ProcessorBox::update()
187 {
188         redisplay_processors ();
189 }
190
191
192 void
193 ProcessorBox::set_width (Width w)
194 {
195         if (_width == w) {
196                 return;
197         }
198         _width = w;
199
200         redisplay_processors ();
201 }
202
203 void
204 ProcessorBox::remove_processor_gui (boost::shared_ptr<Processor> processor)
205 {
206         boost::shared_ptr<Send> send;
207         boost::shared_ptr<PortInsert> port_insert;
208
209         if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
210
211                 PortInsertUI *io_selector = reinterpret_cast<PortInsertUI *> (port_insert->get_gui());
212                 port_insert->set_gui (0);
213                 delete io_selector;
214
215         } else if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
216                 SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui());
217                 send->set_gui (0);
218                 delete sui;
219         }
220 }
221
222 void 
223 ProcessorBox::build_send_action_menu ()
224
225 {
226         using namespace Menu_Helpers;
227
228         send_action_menu = new Menu;
229         send_action_menu->set_name ("ArdourContextMenu");
230         MenuList& items = send_action_menu->items();
231
232         items.push_back (MenuElem (_("New send"), mem_fun(*this, &ProcessorBox::new_send)));
233         items.push_back (MenuElem (_("Show send controls"), mem_fun(*this, &ProcessorBox::show_send_controls)));
234 }
235
236 void
237 ProcessorBox::show_send_controls ()
238
239 {
240 }
241
242 void
243 ProcessorBox::new_send ()
244
245 {
246 }
247
248 void
249 ProcessorBox::show_processor_menu (gint arg)
250 {
251         if (processor_menu == 0) {
252                 processor_menu = build_processor_menu ();
253         }
254
255         Gtk::MenuItem* plugin_menu_item = dynamic_cast<Gtk::MenuItem*>(ActionManager::get_widget("/processormenu/newplugin"));
256
257         if (plugin_menu_item) {
258                 plugin_menu_item->set_submenu (_plugin_selector.plugin_menu());
259         }
260
261         paste_action->set_sensitive (!_rr_selection.processors.empty());
262
263         processor_menu->popup (1, arg);
264 }
265
266 void
267 ProcessorBox::processor_drag_begin (GdkDragContext *context)
268 {
269         processor_drag_in_progress = true;
270 }
271
272 void
273 ProcessorBox::processor_drag_end (GdkDragContext *context)
274 {
275         processor_drag_in_progress = false;
276 }
277
278 bool
279 ProcessorBox::processor_button_press_event (GdkEventButton *ev)
280 {
281         TreeIter iter;
282         TreeModel::Path path;
283         TreeViewColumn* column;
284         int cellx;
285         int celly;
286         boost::shared_ptr<Processor> processor;
287         int ret = false;
288         bool selected = false;
289
290         if (processor_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
291                 if ((iter = model->get_iter (path))) {
292                         processor = (*iter)[columns.processor];
293                         selected = processor_display.get_selection()->is_selected (iter);
294                 }
295                 
296         }
297
298         if (processor && (Keyboard::is_edit_event (ev) || (ev->button == 1 && ev->type == GDK_2BUTTON_PRESS))) {
299                 
300                 if (_session.engine().connected()) {
301                         /* XXX giving an error message here is hard, because we may be in the midst of a button press */
302                         edit_processor (processor);
303                 }
304                 ret = true;
305                 
306         } else if (processor && ev->button == 1 && selected) {
307
308                 // this is purely informational but necessary
309                 ProcessorSelected (processor); // emit
310
311         } else if (!processor && ev->button == 1 && ev->type == GDK_2BUTTON_PRESS) {
312
313                 choose_plugin ();
314                 _plugin_selector.show_manager ();
315         }
316
317         
318         return ret;
319 }
320
321 bool
322 ProcessorBox::processor_button_release_event (GdkEventButton *ev)
323 {
324         TreeIter iter;
325         TreeModel::Path path;
326         TreeViewColumn* column;
327         int cellx;
328         int celly;
329         boost::shared_ptr<Processor> processor;
330         int ret = false;
331
332
333         if (processor_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
334                 if ((iter = model->get_iter (path))) {
335                         processor = (*iter)[columns.processor];
336                 }
337         }
338
339         if (processor && Keyboard::is_delete_event (ev)) {
340                 
341                 Glib::signal_idle().connect (bind (mem_fun(*this, &ProcessorBox::idle_delete_processor), boost::weak_ptr<Processor>(processor)));
342                 ret = true;
343                 
344         } else if (Keyboard::is_context_menu_event (ev)) {
345
346                 show_processor_menu(ev->time);
347                 ret = true;
348
349         } else if (processor && Keyboard::is_button2_event (ev)
350 #ifndef GTKOSX
351                    && (Keyboard::no_modifier_keys_pressed (ev) && ((ev->state & Gdk::BUTTON2_MASK) == Gdk::BUTTON2_MASK))
352 #endif
353                 ) {             
354
355                 /* button2-click with no/appropriate modifiers */
356
357                 if (processor->active()) {
358                         processor->deactivate ();
359                 } else {
360                         processor->activate ();
361                 }
362                 ret = true;
363
364         } 
365
366         return ret;
367 }
368
369 Menu *
370 ProcessorBox::build_processor_menu ()
371 {
372         processor_menu = dynamic_cast<Gtk::Menu*>(ActionManager::get_widget("/processormenu") );
373         processor_menu->set_name ("ArdourContextMenu");
374
375         show_all_children();
376
377         return processor_menu;
378 }
379
380 void
381 ProcessorBox::selection_changed ()
382 {
383         bool sensitive = (processor_display.get_selection()->count_selected_rows()) ? true : false;
384         ActionManager::set_sensitive (ActionManager::plugin_selection_sensitive_actions, sensitive);
385 }
386
387 void
388 ProcessorBox::select_all_processors ()
389 {
390         processor_display.get_selection()->select_all();
391 }
392
393 void
394 ProcessorBox::deselect_all_processors ()
395 {
396         processor_display.get_selection()->unselect_all();
397 }
398
399 void
400 ProcessorBox::choose_plugin ()
401 {
402         _plugin_selector.set_interested_object (*this);
403 }
404
405 void
406 ProcessorBox::use_plugins (const SelectedPlugins& plugins)
407 {
408         for (SelectedPlugins::const_iterator p = plugins.begin(); p != plugins.end(); ++p) {
409
410                 boost::shared_ptr<Processor> processor (new PluginInsert (_session, *p, _placement));
411
412                 Route::ProcessorStreams err_streams;
413
414                 if (Config->get_new_plugins_active()) {
415                         processor->activate ();
416                 }
417                 
418                 if (_route->add_processor (processor, &err_streams)) {
419                         weird_plugin_dialog (**p, err_streams, _route);
420                         // XXX SHAREDPTR delete plugin here .. do we even need to care? 
421                 } else {
422                         
423                         if (Profile->get_sae()) {
424                                 processor->activate ();
425                         }
426                         processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
427                 }
428         }
429 }
430
431 void
432 ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, boost::shared_ptr<IO> io)
433 {
434         ArdourDialog dialog (_("ardour: weird plugin dialog"));
435         Label label;
436
437         /* i hate this kind of code */
438
439         if (streams.count > p.get_info()->n_inputs) {
440                 label.set_text (string_compose (_(
441 "You attempted to add a plugin (%1).\n"
442 "The plugin has %2 inputs\n"
443 "but at the processorion point, there are\n"
444 "%3 active signal streams.\n"
445 "\n"
446 "This makes no sense - you are throwing away\n"
447 "part of the signal."),
448                                          p.name(),
449                                          p.get_info()->n_inputs.n_total(),
450                                          streams.count.n_total()));
451         } else if (streams.count < p.get_info()->n_inputs) {
452                 label.set_text (string_compose (_(
453 "You attempted to add a plugin (%1).\n"
454 "The plugin has %2 inputs\n"
455 "but at the processorion point there are\n"
456 "only %3 active signal streams.\n"
457 "\n"
458 "This makes no sense - unless the plugin supports\n"
459 "side-chain inputs. A future version of Ardour will\n"
460 "support this type of configuration."),
461                                          p.name(),
462                                          p.get_info()->n_inputs.n_total(),
463                                          streams.count.n_total()));
464         } else {
465                 label.set_text (string_compose (_(
466 "You attempted to add a plugin (%1).\n"
467 "\n"
468 "The I/O configuration doesn't make sense:\n"
469 "\n" 
470 "The plugin has %2 inputs and %3 outputs.\n"
471 "The track/bus has %4 inputs and %5 outputs.\n"
472 "The processorion point, has %6 active signals.\n"
473 "\n"
474 "Ardour does not understand what to do in such situations.\n"),
475                                          p.name(),
476                                          p.get_info()->n_inputs.n_total(),
477                                          p.get_info()->n_outputs.n_total(),
478                                          io->n_inputs().n_total(),
479                                          io->n_outputs().n_total(),
480                                          streams.count.n_total()));
481         }
482
483         dialog.get_vbox()->pack_start (label);
484         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
485
486         dialog.set_name (X_("PluginIODialog"));
487         dialog.set_position (Gtk::WIN_POS_MOUSE);
488         dialog.set_modal (true);
489         dialog.show_all ();
490
491         dialog.run ();
492 }
493
494 void
495 ProcessorBox::choose_insert ()
496 {
497         boost::shared_ptr<Processor> processor (new PortInsert (_session, _placement));
498         processor->ActiveChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
499         _route->add_processor (processor);
500 }
501
502 void
503 ProcessorBox::choose_send ()
504 {
505         boost::shared_ptr<Send> send (new Send (_session, _placement));
506         //send->set_default_type(_route->default_type());
507
508         ChanCount outs;
509
510         /* make an educated guess at the initial number of outputs for the send */
511
512         if (_session.master_out()) {
513                 outs = _session.master_out()->n_outputs();
514         } else {
515                 outs = _route->n_outputs();
516         }
517
518         /* XXX need processor lock on route */
519
520         try {
521                 send->io()->ensure_io (ChanCount::ZERO, outs, false, this);
522         } catch (AudioEngine::PortRegistrationFailure& err) {
523                 error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg;
524                 return;
525         }
526         
527         /* let the user adjust the output setup (number and connections) before passing
528            it along to the Route
529         */
530         
531         IOSelectorWindow *ios = new IOSelectorWindow (_session, send->io(), false, true);
532
533         ios->show_all ();
534
535         /* bit of a hack; keep a shared_ptr to send around so that it doesn't get deleted while
536            the IOSelectorWindow is doing its stuff */
537         _send_being_created = send;
538
539         boost::shared_ptr<Processor> r = boost::static_pointer_cast<Processor>(send);
540         
541         ios->selector().Finished.connect (bind (mem_fun(*this, &ProcessorBox::send_io_finished), boost::weak_ptr<Processor>(r), ios));
542 }
543
544 void
545 ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor> weak_processor, IOSelectorWindow* ios)
546 {
547         boost::shared_ptr<Processor> processor (weak_processor.lock());
548
549         /* now we can lose the dummy shared_ptr */
550         _send_being_created.reset ();
551
552         if (!processor) {
553                 return;
554         }
555
556         switch (r) {
557         case IOSelector::Cancelled:
558                 // processor will go away when all shared_ptrs to it vanish
559                 break;
560
561         case IOSelector::Accepted:
562                 _route->add_processor (processor);
563                 if (Profile->get_sae()) {
564                         processor->activate ();
565                 }
566                 break;
567         }
568
569         delete_when_idle (ios);
570 }
571
572 void
573 ProcessorBox::redisplay_processors ()
574 {
575         ENSURE_GUI_THREAD (mem_fun(*this, &ProcessorBox::redisplay_processors));
576
577         if (no_processor_redisplay) {
578                 return;
579         }
580         
581         ignore_delete = true;
582         model->clear ();
583         ignore_delete = false;
584
585         processor_active_connections.clear ();
586         processor_name_connections.clear ();
587
588         _route->foreach_processor (mem_fun (*this, &ProcessorBox::add_processor_to_display));
589
590         switch (_placement) {
591         case PreFader:
592                 build_processor_tooltip(processor_eventbox, _("Pre-fader inserts, sends & plugins:"));
593                 break;
594         case PostFader:
595                 build_processor_tooltip(processor_eventbox, _("Post-fader inserts, sends & plugins:"));
596                 break;
597         }
598 }
599
600 void
601 ProcessorBox::add_processor_to_display (boost::weak_ptr<Processor> p)
602 {
603         boost::shared_ptr<Processor> processor (p.lock ());
604         if (!processor) {
605                 return;
606         }
607         
608         if (processor->placement() != _placement) {
609                 return;
610         }
611         
612         Gtk::TreeModel::Row row = *(model->append());
613         row[columns.text] = processor_name (processor);
614         row[columns.processor] = processor;
615
616         show_processor_active (processor);
617
618         processor_active_connections.push_back (processor->ActiveChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor))));
619         processor_name_connections.push_back (processor->NameChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_name), boost::weak_ptr<Processor>(processor))));
620 }
621
622 string
623 ProcessorBox::processor_name (boost::weak_ptr<Processor> weak_processor)
624 {
625         boost::shared_ptr<Processor> processor (weak_processor.lock());
626
627         if (!processor) {
628                 return string();
629         }
630
631         boost::shared_ptr<Send> send;
632         string name_display;
633
634         if (!processor->active()) {
635                 name_display = " (";
636         }
637
638         if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
639
640                 name_display += '>';
641
642                 /* grab the send name out of its overall name */
643
644                 string::size_type lbracket, rbracket;
645                 lbracket = send->name().find ('[');
646                 rbracket = send->name().find (']');
647
648                 switch (_width) {
649                 case Wide:
650                         name_display += send->name().substr (lbracket+1, lbracket-rbracket-1);
651                         break;
652                 case Narrow:
653                         name_display += PBD::short_version (send->name().substr (lbracket+1, lbracket-rbracket-1), 4);
654                         break;
655                 }
656
657         } else {
658
659                 switch (_width) {
660                 case Wide:
661                         name_display += processor->name();
662                         break;
663                 case Narrow:
664                         name_display += PBD::short_version (processor->name(), 5);
665                         break;
666                 }
667
668         }
669
670         if (!processor->active()) {
671                 name_display += ')';
672         }
673
674         return name_display;
675 }
676
677 void
678 ProcessorBox::build_processor_tooltip (EventBox& box, string start)
679 {
680         string tip(start);
681
682         Gtk::TreeModel::Children children = model->children();
683         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
684                 Gtk::TreeModel::Row row = *iter;
685                 tip += '\n';
686                 tip += row[columns.text];
687         }
688         ARDOUR_UI::instance()->tooltips().set_tip (box, tip);
689 }
690
691 void
692 ProcessorBox::show_processor_name (boost::weak_ptr<Processor> processor)
693 {
694         ENSURE_GUI_THREAD(bind (mem_fun(*this, &ProcessorBox::show_processor_name), processor));
695         show_processor_active (processor);
696 }
697
698 void
699 ProcessorBox::show_processor_active (boost::weak_ptr<Processor> weak_processor)
700 {
701         boost::shared_ptr<Processor> processor (weak_processor.lock());
702         
703         if (!processor) {
704                 return;
705         }
706
707         ENSURE_GUI_THREAD(bind (mem_fun(*this, &ProcessorBox::show_processor_active), weak_processor));
708         
709         Gtk::TreeModel::Children children = model->children();
710         Gtk::TreeModel::Children::iterator iter = children.begin();
711
712         while (iter != children.end()) {
713
714                 boost::shared_ptr<Processor> r = (*iter)[columns.processor];
715
716                 if (r == processor) {
717                         (*iter)[columns.text] = processor_name (r);
718                         
719                         if (processor->active()) {
720                                 (*iter)[columns.color] = *active_processor_color;
721                         } else {
722                                 (*iter)[columns.color] = *inactive_processor_color;
723                         }
724                         break;
725                 }
726
727                 iter++;
728         }
729 }
730
731 void
732 ProcessorBox::row_deleted (const Gtk::TreeModel::Path& path)
733 {
734         if (!ignore_delete) {
735                 compute_processor_sort_keys ();
736         }
737 }
738
739 void
740 ProcessorBox::compute_processor_sort_keys ()
741 {
742         uint32_t sort_key = 0;
743         Gtk::TreeModel::Children children = model->children();
744
745         for (Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
746                 boost::shared_ptr<Processor> r = (*iter)[columns.processor];
747                 r->set_sort_key (sort_key);
748                 sort_key++;
749         }
750
751         if (_route->sort_processors ()) {
752
753                 redisplay_processors ();
754
755                 /* now tell them about the problem */
756
757                 ArdourDialog dialog (_("ardour: weird plugin dialog"));
758                 Label label;
759
760                 label.set_text (_("\
761 You cannot reorder this set of processors\n\
762 in that way because the inputs and\n\
763 outputs do not work correctly."));
764
765                 dialog.get_vbox()->pack_start (label);
766                 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
767
768                 dialog.set_name (X_("PluginIODialog"));
769                 dialog.set_position (Gtk::WIN_POS_MOUSE);
770                 dialog.set_modal (true);
771                 dialog.show_all ();
772
773                 dialog.run ();
774         }
775 }
776
777 void
778 ProcessorBox::rename_processors ()
779 {
780         vector<boost::shared_ptr<Processor> > to_be_renamed;
781         
782         get_selected_processors (to_be_renamed);
783
784         if (to_be_renamed.empty()) {
785                 return;
786         }
787
788         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) {
789                 rename_processor (*i);
790         }
791 }
792
793 void
794 ProcessorBox::cut_processors ()
795 {
796         vector<boost::shared_ptr<Processor> > to_be_removed;
797         XMLNode* node = new XMLNode (X_("cut"));
798
799         get_selected_processors (to_be_removed);
800
801         if (to_be_removed.empty()) {
802                 return;
803         }
804
805         no_processor_redisplay = true;
806         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) {
807                 // Do not cut inserts
808                 if (boost::dynamic_pointer_cast<PluginInsert>((*i)) != 0 ||
809                     (boost::dynamic_pointer_cast<Send>((*i)) != 0)) {
810
811                         void* gui = (*i)->get_gui ();
812                 
813                         if (gui) {
814                                 static_cast<Gtk::Widget*>(gui)->hide ();
815                         }
816                         
817                         XMLNode& child ((*i)->get_state());
818
819                         if (_route->remove_processor (*i) == 0) {
820                                 /* success */
821                                 node->add_child_nocopy (child);
822                         } else {
823                                 delete &child;
824                         }
825                 } 
826         }
827
828         _rr_selection.set (node);
829
830         no_processor_redisplay = false;
831         redisplay_processors ();
832 }
833
834 void
835 ProcessorBox::copy_processors ()
836 {
837         vector<boost::shared_ptr<Processor> > to_be_copied;
838         XMLNode* node = new XMLNode (X_("copy"));
839
840         get_selected_processors (to_be_copied);
841
842         if (to_be_copied.empty()) {
843                 return;
844         }
845
846         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) {
847                 // Do not copy inserts
848                 if (boost::dynamic_pointer_cast<PluginInsert>((*i)) != 0 ||
849                     (boost::dynamic_pointer_cast<Send>((*i)) != 0)) {
850                         node->add_child_nocopy ((*i)->get_state());
851                 }
852         }
853
854         _rr_selection.set (node);
855 }
856
857 void
858 ProcessorBox::delete_processors ()
859 {
860         vector<boost::shared_ptr<Processor> > to_be_deleted;
861         
862         get_selected_processors (to_be_deleted);
863
864         if (to_be_deleted.empty()) {
865                 return;
866         }
867
868         for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
869                 
870                 void* gui = (*i)->get_gui ();
871                 
872                 if (gui) {
873                         static_cast<Gtk::Widget*>(gui)->hide ();
874                 }
875
876                 _route->remove_processor(*i);
877         }
878
879         no_processor_redisplay = false;
880         redisplay_processors ();
881 }
882
883 gint
884 ProcessorBox::idle_delete_processor (boost::weak_ptr<Processor> weak_processor)
885 {
886         boost::shared_ptr<Processor> processor (weak_processor.lock());
887
888         if (!processor) {
889                 return false;
890         }
891
892         /* NOT copied to _mixer.selection() */
893
894         no_processor_redisplay = true;
895         _route->remove_processor (processor);
896         no_processor_redisplay = false;
897         redisplay_processors ();
898
899         return false;
900 }
901
902 void
903 ProcessorBox::rename_processor (boost::shared_ptr<Processor> processor)
904 {
905         ArdourPrompter name_prompter (true);
906         string result;
907         name_prompter.set_prompt (_("rename processor"));
908         name_prompter.set_initial_text (processor->name());
909         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
910         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
911         name_prompter.show_all ();
912
913         switch (name_prompter.run ()) {
914
915         case Gtk::RESPONSE_ACCEPT:
916         name_prompter.get_result (result);
917         if (result.length()) {
918                         processor->set_name (result);
919                 }       
920                 break;
921         }
922
923         return;
924 }
925
926 void
927 ProcessorBox::paste_processors ()
928 {
929         if (_rr_selection.processors.empty()) {
930                 return;
931         }
932
933         cerr << "paste from node called " << _rr_selection.processors.get_node().name() << endl;
934
935         paste_processor_state (_rr_selection.processors.get_node().children());
936 }
937
938 void
939 ProcessorBox::paste_processor_state (const XMLNodeList& nlist)
940 {
941         XMLNodeConstIterator niter;
942         list<boost::shared_ptr<Processor> > copies;
943
944         cerr << "Pasting processor selection containing " << nlist.size() << endl;
945
946         if (nlist.empty()) {
947                 return;
948         }
949
950         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
951                 cerr << "try using " << (*niter)->name() << endl;
952                 XMLProperty const * type = (*niter)->property ("type");
953                 assert (type);
954
955                 boost::shared_ptr<Processor> p;
956                 try {
957                         if (type->value() == "send") {
958                                 XMLNode n (**niter);
959                                 Send::make_unique (n, _session);
960                                 p.reset (new Send (_session, n));
961                                 
962                         } else {
963                                 p.reset (new PluginInsert (_session, **niter));
964                         }
965
966                         p->set_placement (_placement);
967                         copies.push_back (p);
968                 }
969                 catch (...) {
970                         cerr << "plugin insert constructor failed\n";
971                 }
972         }
973
974         if (_route->add_processors (copies)) {
975
976                 string msg = _(
977                         "Copying the set of processors on the clipboard failed,\n\
978 probably because the I/O configuration of the plugins\n\
979 could not match the configuration of this track.");
980                 MessageDialog am (msg);
981                 am.run ();
982         }
983 }
984
985 void
986 ProcessorBox::activate_processor (boost::shared_ptr<Processor> r)
987 {
988         r->activate ();
989 }
990
991 void
992 ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r)
993 {
994         r->deactivate ();
995 }
996
997 void
998 ProcessorBox::get_selected_processors (vector<boost::shared_ptr<Processor> >& processors)
999 {
1000     vector<Gtk::TreeModel::Path> pathlist = processor_display.get_selection()->get_selected_rows();
1001  
1002     for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) {
1003             processors.push_back ((*(model->get_iter(*iter)))[columns.processor]);
1004     }
1005 }
1006
1007 void
1008 ProcessorBox::for_selected_processors (void (ProcessorBox::*method)(boost::shared_ptr<Processor>))
1009 {
1010     vector<Gtk::TreeModel::Path> pathlist = processor_display.get_selection()->get_selected_rows();
1011
1012         for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) {
1013                 boost::shared_ptr<Processor> processor = (*(model->get_iter(*iter)))[columns.processor];
1014                 (this->*method)(processor);
1015         }
1016 }
1017
1018 void
1019 ProcessorBox::all_processors_active (bool state)
1020 {
1021         _route->all_processors_active (_placement, state);
1022 }
1023
1024 void
1025 ProcessorBox::ab_plugins ()
1026 {
1027         _route->ab_plugins (ab_direction);
1028         ab_direction = !ab_direction;
1029 }
1030
1031
1032 void
1033 ProcessorBox::clear_processors ()
1034 {
1035         string prompt;
1036         vector<string> choices;
1037
1038         if (boost::dynamic_pointer_cast<AudioTrack>(_route) != 0) {
1039                 if (_placement == PreFader) {
1040                         prompt = _("Do you really want to remove all pre-fader processors from this track?\n"
1041                                    "(this cannot be undone)");
1042                 } else {
1043                         prompt = _("Do you really want to remove all post-fader processors from this track?\n"
1044                                    "(this cannot be undone)");
1045                 }
1046         } else {
1047                 if (_placement == PreFader) {
1048                         prompt = _("Do you really want to remove all pre-fader processors from this bus?\n"
1049                                    "(this cannot be undone)");
1050                 } else {
1051                         prompt = _("Do you really want to remove all post-fader processors from this bus?\n"
1052                                    "(this cannot be undone)");
1053                 }
1054         }
1055
1056         choices.push_back (_("Cancel"));
1057         choices.push_back (_("Yes, remove them all"));
1058
1059         Gtkmm2ext::Choice prompter (prompt, choices);
1060
1061         if (prompter.run () == 1) {
1062                 _route->clear_processors (_placement);
1063         }
1064 }
1065
1066 void
1067 ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
1068 {
1069         boost::shared_ptr<Send> send;
1070         boost::shared_ptr<PluginInsert> plugin_insert;
1071         boost::shared_ptr<PortInsert> port_insert;
1072         Window* gidget = 0;
1073
1074         if (boost::dynamic_pointer_cast<AudioTrack>(_route) != 0) {
1075
1076                 if (boost::dynamic_pointer_cast<AudioTrack> (_route)->freeze_state() == AudioTrack::Frozen) {
1077                         return;
1078                 }
1079         }
1080         
1081         if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
1082                 
1083                 if (!_session.engine().connected()) {
1084                         return;
1085                 }
1086
1087                 boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (processor);
1088                 
1089                 SendUIWindow *send_ui;
1090                 
1091                 if (send->get_gui() == 0) {
1092                         
1093                         send_ui = new SendUIWindow (send, _session);
1094
1095                         WindowTitle title(Glib::get_application_name());
1096                         title += send->name();
1097                         send_ui->set_title (title.get_string());
1098
1099                         send->set_gui (send_ui);
1100                         
1101                 } else {
1102                         send_ui = reinterpret_cast<SendUIWindow *> (send->get_gui());
1103                 }
1104                 
1105                 gidget = send_ui;
1106                 
1107         } else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (processor)) != 0) {
1108                 
1109                 PluginUIWindow *plugin_ui;
1110                 
1111                 /* these are both allowed to be null */
1112                 
1113                 Container* toplevel = get_toplevel();
1114                 Window* win = dynamic_cast<Gtk::Window*>(toplevel);
1115                 
1116                 if (plugin_insert->get_gui() == 0) {
1117                         
1118                         plugin_ui = new PluginUIWindow (win, plugin_insert);
1119                         
1120                         WindowTitle title(Glib::get_application_name());
1121                         title += generate_processor_title (plugin_insert);
1122                         plugin_ui->set_title (title.get_string());
1123                         
1124                         plugin_insert->set_gui (plugin_ui);
1125                         
1126                 } else {
1127                         plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
1128                         plugin_ui->set_parent (win);
1129                 }
1130                 
1131                 gidget = plugin_ui;
1132                 
1133         } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
1134                 
1135                 if (!_session.engine().connected()) {
1136                         MessageDialog msg ( _("Not connected to JACK - no I/O changes are possible"));
1137                         msg.run ();
1138                         return;
1139                 }
1140                 
1141                 PortInsertWindow *io_selector;
1142                 
1143                 if (port_insert->get_gui() == 0) {
1144                         io_selector = new PortInsertWindow (_session, port_insert);
1145                         port_insert->set_gui (io_selector);
1146                         
1147                 } else {
1148                         io_selector = reinterpret_cast<PortInsertWindow *> (port_insert->get_gui());
1149                 }
1150                 
1151                 gidget = io_selector;
1152         }
1153
1154         if (gidget) {
1155                 if (gidget->is_visible()) {
1156                         gidget->get_window()->raise ();
1157                 } else {
1158                         gidget->show_all ();
1159                         gidget->present ();
1160                 }
1161         }
1162 }
1163
1164 bool
1165 ProcessorBox::enter_box (GdkEventCrossing *ev, ProcessorBox* rb)
1166 {
1167         switch (ev->detail) {
1168         case GDK_NOTIFY_INFERIOR:
1169                 break;
1170
1171         case GDK_NOTIFY_VIRTUAL:
1172                 /* fallthru */
1173
1174         default:
1175                 _current_processor_box = rb;
1176         }
1177
1178         return false;
1179 }
1180
1181 void
1182 ProcessorBox::register_actions ()
1183 {
1184         Glib::RefPtr<Gtk::ActionGroup> popup_act_grp = Gtk::ActionGroup::create(X_("processormenu"));
1185         Glib::RefPtr<Action> act;
1186
1187         /* new stuff */
1188         ActionManager::register_action (popup_act_grp, X_("newplugin"), _("New Plugin"),  sigc::ptr_fun (ProcessorBox::rb_choose_plugin));
1189
1190         act = ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"),  sigc::ptr_fun (ProcessorBox::rb_choose_insert));
1191         ActionManager::jack_sensitive_actions.push_back (act);
1192         act = ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."),  sigc::ptr_fun (ProcessorBox::rb_choose_send));
1193         ActionManager::jack_sensitive_actions.push_back (act);
1194
1195         ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"),  sigc::ptr_fun (ProcessorBox::rb_clear));
1196
1197         /* standard editing stuff */
1198         act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),  sigc::ptr_fun (ProcessorBox::rb_cut));
1199         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1200         act = ActionManager::register_action (popup_act_grp, X_("copy"), _("Copy"),  sigc::ptr_fun (ProcessorBox::rb_copy));
1201         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1202
1203         act = ActionManager::register_action (popup_act_grp, X_("delete"), _("Delete"),  sigc::ptr_fun (ProcessorBox::rb_delete));
1204         ActionManager::plugin_selection_sensitive_actions.push_back(act); // ??
1205
1206         paste_action = ActionManager::register_action (popup_act_grp, X_("paste"), _("Paste"),  sigc::ptr_fun (ProcessorBox::rb_paste));
1207         act = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),  sigc::ptr_fun (ProcessorBox::rb_rename));
1208         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1209         ActionManager::register_action (popup_act_grp, X_("selectall"), _("Select All"),  sigc::ptr_fun (ProcessorBox::rb_select_all));
1210         ActionManager::register_action (popup_act_grp, X_("deselectall"), _("Deselect All"),  sigc::ptr_fun (ProcessorBox::rb_deselect_all));
1211                 
1212         /* activation */
1213         act = ActionManager::register_action (popup_act_grp, X_("activate"), _("Activate"),  sigc::ptr_fun (ProcessorBox::rb_activate));
1214         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1215         act = ActionManager::register_action (popup_act_grp, X_("deactivate"), _("Deactivate"),  sigc::ptr_fun (ProcessorBox::rb_deactivate));
1216         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1217         ActionManager::register_action (popup_act_grp, X_("activate_all"), _("Activate all"),  sigc::ptr_fun (ProcessorBox::rb_activate_all));
1218         ActionManager::register_action (popup_act_grp, X_("deactivate_all"), _("Deactivate all"),  sigc::ptr_fun (ProcessorBox::rb_deactivate_all));
1219
1220         /* show editors */
1221         act = ActionManager::register_action (popup_act_grp, X_("edit"), _("Edit"),  sigc::ptr_fun (ProcessorBox::rb_edit));
1222         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1223
1224         ActionManager::add_action_group (popup_act_grp);
1225
1226
1227 }
1228
1229 void
1230 ProcessorBox::rb_choose_plugin ()
1231 {
1232         if (_current_processor_box == 0) {
1233                 return;
1234         }
1235         _current_processor_box->choose_plugin ();
1236 }
1237
1238 void
1239 ProcessorBox::rb_choose_insert ()
1240 {
1241         if (_current_processor_box == 0) {
1242                 return;
1243         }
1244         _current_processor_box->choose_insert ();
1245 }
1246
1247 void
1248 ProcessorBox::rb_choose_send ()
1249 {
1250         if (_current_processor_box == 0) {
1251                 return;
1252         }
1253         _current_processor_box->choose_send ();
1254 }
1255
1256 void
1257 ProcessorBox::rb_clear ()
1258 {
1259         if (_current_processor_box == 0) {
1260                 return;
1261         }
1262
1263         _current_processor_box->clear_processors ();
1264 }
1265
1266 void
1267 ProcessorBox::rb_cut ()
1268 {
1269         if (_current_processor_box == 0) {
1270                 return;
1271         }
1272
1273         _current_processor_box->cut_processors ();
1274 }
1275
1276 void
1277 ProcessorBox::rb_delete ()
1278 {
1279         if (_current_processor_box == 0) {
1280                 return;
1281         }
1282
1283         _current_processor_box->delete_processors ();
1284 }
1285
1286 void
1287 ProcessorBox::rb_copy ()
1288 {
1289         if (_current_processor_box == 0) {
1290                 return;
1291         }
1292         _current_processor_box->copy_processors ();
1293 }
1294
1295 void
1296 ProcessorBox::rb_paste ()
1297 {
1298         if (_current_processor_box == 0) {
1299                 return;
1300         }
1301
1302         _current_processor_box->paste_processors ();
1303 }
1304
1305 void
1306 ProcessorBox::rb_rename ()
1307 {
1308         if (_current_processor_box == 0) {
1309                 return;
1310         }
1311         _current_processor_box->rename_processors ();
1312 }
1313
1314 void
1315 ProcessorBox::rb_select_all ()
1316 {
1317         if (_current_processor_box == 0) {
1318                 return;
1319         }
1320
1321         _current_processor_box->select_all_processors ();
1322 }
1323
1324 void
1325 ProcessorBox::rb_deselect_all ()
1326 {
1327         if (_current_processor_box == 0) {
1328                 return;
1329         }
1330
1331         _current_processor_box->deselect_all_processors ();
1332 }
1333
1334 void
1335 ProcessorBox::rb_activate ()
1336 {
1337         if (_current_processor_box == 0) {
1338                 return;
1339         }
1340
1341         _current_processor_box->for_selected_processors (&ProcessorBox::activate_processor);
1342 }
1343
1344 void
1345 ProcessorBox::rb_deactivate ()
1346 {
1347         if (_current_processor_box == 0) {
1348                 return;
1349         }
1350         _current_processor_box->for_selected_processors (&ProcessorBox::deactivate_processor);
1351 }
1352
1353 void
1354 ProcessorBox::rb_activate_all ()
1355 {
1356         if (_current_processor_box == 0) {
1357                 return;
1358         }
1359
1360         _current_processor_box->all_processors_active (true);
1361 }
1362
1363 void
1364 ProcessorBox::rb_deactivate_all ()
1365 {
1366         if (_current_processor_box == 0) {
1367                 return;
1368         }
1369         _current_processor_box->all_processors_active (false);
1370 }
1371
1372 void
1373 ProcessorBox::rb_edit ()
1374 {
1375         if (_current_processor_box == 0) {
1376                 return;
1377         }
1378
1379         _current_processor_box->for_selected_processors (&ProcessorBox::edit_processor);
1380 }
1381
1382 void
1383 ProcessorBox::route_name_changed ()
1384 {
1385         ENSURE_GUI_THREAD (mem_fun (*this, &ProcessorBox::route_name_changed));
1386
1387         boost::shared_ptr<Processor> processor;
1388         boost::shared_ptr<PluginInsert> plugin_insert;
1389         boost::shared_ptr<Send> send;
1390
1391         Gtk::TreeModel::Children children = model->children();
1392
1393         for (Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
1394                 Gtk::TreeModel::Row row = *iter;
1395
1396                 processor= row[columns.processor];
1397                 
1398                 void* gui = processor->get_gui();
1399
1400                 if (!gui) {
1401                         continue;
1402                 }
1403
1404                 /* rename editor windows for sends and plugins */
1405
1406                 WindowTitle title (Glib::get_application_name());
1407                 
1408                 if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
1409                         title += send->name();
1410                         static_cast<Window*>(gui)->set_title (title.get_string());
1411                 } else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (processor)) != 0) {
1412                         title += generate_processor_title (plugin_insert);
1413                         static_cast<Window*>(gui)->set_title (title.get_string());
1414                 }
1415         }
1416 }
1417
1418 string 
1419 ProcessorBox::generate_processor_title (boost::shared_ptr<PluginInsert> pi)
1420 {
1421         string maker = pi->plugin()->maker() ? pi->plugin()->maker() : "";
1422         string::size_type email_pos;
1423
1424         if ((email_pos = maker.find_first_of ('<')) != string::npos) {
1425                 maker = maker.substr (0, email_pos - 1);
1426         }
1427
1428         if (maker.length() > 32) {
1429                 maker = maker.substr (0, 32);
1430                 maker += " ...";
1431         }
1432
1433         return string_compose(_("%1: %2 (by %3)"), _route->name(), pi->name(), maker);  
1434 }
1435