another get_vbox() fix, this time for PortSelectorWindow
[ardour.git] / gtk2_ardour / redirect_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     $Id$
19 */
20
21 #include <cmath>
22 #include <glib.h>
23
24 #include <sigc++/bind.h>
25
26 #include <gtkmm2ext/gtk_ui.h>
27 #include <gtkmm2ext/utils.h>
28 #include <gtkmm2ext/choice.h>
29 #include <gtkmm2ext/utils.h>
30 #include <gtkmm2ext/stop_signal.h>
31 #include <gtkmm2ext/doi.h>
32
33 #include <ardour/ardour.h>
34 #include <ardour/session.h>
35 #include <ardour/audioengine.h>
36 #include <ardour/route.h>
37 #include <ardour/audio_track.h>
38 #include <ardour/diskstream.h>
39 #include <ardour/send.h>
40 #include <ardour/insert.h>
41 #include <ardour/ladspa_plugin.h>
42 #include <ardour/connection.h>
43 #include <ardour/session_connection.h>
44
45 #include "ardour_ui.h"
46 #include "ardour_dialog.h"
47 #include "ardour_message.h"
48 #include "public_editor.h"
49 #include "redirect_box.h"
50 #include "keyboard.h"
51 #include "plugin_selector.h"
52 #include "route_redirect_selection.h"
53 #include "mixer_ui.h"
54 #include "actions.h"
55
56 #include "plugin_ui.h"
57 #include "send_ui.h"
58 #include "io_selector.h"
59 #include "utils.h"
60 #include "gui_thread.h"
61
62 #include "i18n.h"
63
64 using namespace sigc;
65 using namespace ARDOUR;
66 using namespace Gtk;
67 using namespace Glib;
68 using namespace Gtkmm2ext;
69
70 RedirectBox* RedirectBox::_current_redirect_box = 0;
71 RefPtr<Action> RedirectBox::paste_action;
72 bool RedirectBox::get_colors = true;
73 Gdk::Color* RedirectBox::active_redirect_color;
74 Gdk::Color* RedirectBox::inactive_redirect_color;
75
76 RedirectBox::RedirectBox (Placement pcmnt, Session& sess, Route& rt, PluginSelector &plugsel, 
77                           RouteRedirectSelection & rsel, bool owner_is_mixer)
78         : _route(rt), 
79           _session(sess), 
80           _owner_is_mixer (owner_is_mixer), 
81           _placement(pcmnt), 
82           _plugin_selector(plugsel),
83           _rr_selection(rsel)
84 {
85         if (get_colors) {
86                 active_redirect_color = new Gdk::Color;
87                 inactive_redirect_color = new Gdk::Color;
88                 set_color (*active_redirect_color, rgba_from_style ("RedirectSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_ACTIVE, false ));
89                 set_color (*inactive_redirect_color, rgba_from_style ("RedirectSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_NORMAL, false ));
90                 get_colors = false;
91         }
92
93         _width = Wide;
94         redirect_menu = 0;
95         send_action_menu = 0;
96         redirect_drag_in_progress = false;
97         no_redirect_redisplay = false;
98         ignore_delete = false;
99
100         model = ListStore::create(columns);
101
102         RefPtr<TreeSelection> selection = redirect_display.get_selection();
103         selection->set_mode (Gtk::SELECTION_MULTIPLE);
104         selection->signal_changed().connect (mem_fun (*this, &RedirectBox::selection_changed));
105
106         redirect_display.set_model (model);
107         redirect_display.append_column (X_("notshown"), columns.text);
108         redirect_display.set_name ("RedirectSelector");
109         redirect_display.set_headers_visible (false);
110         redirect_display.set_reorderable (true);
111         redirect_display.set_size_request (-1, -1);
112         redirect_display.get_column(0)->set_sizing(TREE_VIEW_COLUMN_FIXED);
113         redirect_display.get_column(0)->set_fixed_width(48);
114         redirect_display.add_object_drag (columns.redirect.index(), "redirects");
115         redirect_display.signal_object_drop.connect (mem_fun (*this, &RedirectBox::object_drop));
116
117         TreeViewColumn* name_col = redirect_display.get_column(0);
118         CellRendererText* renderer = dynamic_cast<CellRendererText*>(redirect_display.get_column_cell_renderer (0));
119         name_col->add_attribute(renderer->property_foreground_gdk(), columns.color);
120
121         redirect_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
122         
123         model->signal_row_deleted().connect (mem_fun (*this, &RedirectBox::row_deleted));
124
125         redirect_scroller.add (redirect_display);
126         redirect_eventbox.add (redirect_scroller);
127
128         pack_start (redirect_eventbox, true, true);
129
130         _route.redirects_changed.connect (mem_fun(*this, &RedirectBox::redisplay_redirects));
131
132         redirect_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (RedirectBox::enter_box), this));
133
134         redirect_display.signal_button_press_event().connect (mem_fun(*this, &RedirectBox::redirect_button_press_event), false);
135         redirect_display.signal_button_release_event().connect (mem_fun(*this, &RedirectBox::redirect_button_press_event));
136
137         /* start off as a passthru strip. we'll correct this, if necessary,
138            in update_diskstream_display().
139         */
140
141         /* now force an update of all the various elements */
142
143         redisplay_redirects (0);
144 }
145
146 RedirectBox::~RedirectBox ()
147 {
148 }
149
150 void
151 RedirectBox::object_drop (string type, uint32_t cnt, void** ptr)
152 {
153         if (type != "redirects" || cnt == 0 || ptr == 0) {
154                 return;
155         }
156
157         /* do something with the dropped redirects */
158
159         list<Redirect*> redirects;
160
161         for (uint32_t n = 0; n < cnt; ++n) {
162                 redirects.push_back ((Redirect*) ptr[n]);
163         }
164         
165         paste_redirect_list (redirects);
166 }
167
168 void
169 RedirectBox::update()
170 {
171         redisplay_redirects (0);
172 }
173
174
175 void
176 RedirectBox::set_width (Width w)
177 {
178         if (_width == w) {
179                 return;
180         }
181         _width = w;
182
183         redisplay_redirects (0);
184 }
185
186 void
187 RedirectBox::remove_redirect_gui (Redirect *redirect)
188 {
189         Insert *insert = 0;
190         Send *send = 0;
191         PortInsert *port_insert = 0;
192
193         if ((insert = dynamic_cast<Insert *> (redirect)) != 0) {
194
195                 if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
196                         PortInsertUI *io_selector = reinterpret_cast<PortInsertUI *> (port_insert->get_gui());
197                         port_insert->set_gui (0);
198                         delete io_selector;
199                 } 
200
201         } else if ((send = dynamic_cast<Send *> (insert)) != 0) {
202                 SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui());
203                 send->set_gui (0);
204                 delete sui;
205         }
206 }
207
208 void 
209 RedirectBox::build_send_action_menu ()
210
211 {
212         using namespace Menu_Helpers;
213
214         send_action_menu = new Menu;
215         send_action_menu->set_name ("ArdourContextMenu");
216         MenuList& items = send_action_menu->items();
217
218         items.push_back (MenuElem (_("New send"), mem_fun(*this, &RedirectBox::new_send)));
219         items.push_back (MenuElem (_("Show send controls"), mem_fun(*this, &RedirectBox::show_send_controls)));
220 }
221
222 void
223 RedirectBox::show_send_controls ()
224
225 {
226 }
227
228 void
229 RedirectBox::new_send ()
230
231 {
232 }
233
234 void
235 RedirectBox::show_redirect_menu (gint arg)
236 {
237         if (redirect_menu == 0) {
238                 redirect_menu = build_redirect_menu ();
239         }
240
241         paste_action->set_sensitive (!_rr_selection.redirects.empty());
242
243         redirect_menu->popup (1, 0);
244 }
245
246 void
247 RedirectBox::redirect_drag_begin (GdkDragContext *context)
248 {
249         redirect_drag_in_progress = true;
250 }
251
252 void
253 RedirectBox::redirect_drag_end (GdkDragContext *context)
254 {
255         redirect_drag_in_progress = false;
256 }
257
258 bool
259 RedirectBox::redirect_button_press_event (GdkEventButton *ev)
260 {
261         TreeIter iter;
262         TreeModel::Path path;
263         TreeViewColumn* column;
264         int cellx;
265         int celly;
266         Redirect* redirect = 0;
267         int ret = false;
268         bool selected = false;
269
270         if (redirect_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
271                 if ((iter = model->get_iter (path))) {
272                         redirect = (*iter)[columns.redirect];
273                         selected = redirect_display.get_selection()->is_selected (iter);
274                 }
275                 
276         }
277         
278         if (redirect && Keyboard::is_delete_event (ev)) {
279                 
280                 Glib::signal_idle().connect (bind (mem_fun(*this, &RedirectBox::idle_delete_redirect), redirect));
281                 ret = true;
282                 
283         } else if (redirect && (Keyboard::is_edit_event (ev) || (ev->button == 1 && ev->type == GDK_2BUTTON_PRESS && ev->state == 0))) {
284                 
285                 if (_session.engine().connected()) {
286                         /* XXX giving an error message here is hard, because we may be in the midst of a button press */
287                         edit_redirect (redirect);
288                 }
289                 ret = true;
290                 
291         } else if (Keyboard::is_context_menu_event (ev)) {
292
293                 show_redirect_menu(0);
294                 ret = true;
295
296         } else if (redirect && ev->button == 2 && ev->state == 0) {
297                 
298                 redirect->set_active (!redirect->active(), this);
299                 ret = true;
300
301         } 
302
303         return ret;
304 }
305
306 Menu *
307 RedirectBox::build_redirect_menu ()
308 {
309         redirect_menu = dynamic_cast<Gtk::Menu*>(ActionManager::get_widget("/redirectmenu") );
310         redirect_menu->set_name ("ArdourContextMenu");
311
312         show_all_children();
313
314         return redirect_menu;
315 }
316
317 void
318 RedirectBox::selection_changed ()
319 {
320         bool sensitive = (redirect_display.get_selection()->count_selected_rows()) ? true : false;
321
322         for (vector<Glib::RefPtr<Gtk::Action> >::iterator i = ActionManager::plugin_selection_sensitive_actions.begin(); i != ActionManager::plugin_selection_sensitive_actions.end(); ++i) {
323                 (*i)->set_sensitive (sensitive);
324         }
325 }
326
327 void
328 RedirectBox::select_all_redirects ()
329 {
330         redirect_display.get_selection()->select_all();
331 }
332
333 void
334 RedirectBox::deselect_all_redirects ()
335 {
336         redirect_display.get_selection()->unselect_all();
337 }
338
339 void
340 RedirectBox::choose_plugin ()
341 {
342         sigc::connection newplug_connection = _plugin_selector.PluginCreated.connect (mem_fun(*this,&RedirectBox::insert_plugin_chosen));
343         _plugin_selector.show_all();
344         _plugin_selector.run ();
345         newplug_connection.disconnect();
346 }
347
348 void
349 RedirectBox::insert_plugin_chosen (Plugin *plugin)
350 {
351         if (plugin) {
352
353                 Redirect *redirect = new PluginInsert (_session, *plugin, _placement);
354                 
355                 redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active));
356
357                 uint32_t err_streams;
358
359                 if (_route.add_redirect (redirect, this, &err_streams)) {
360                         wierd_plugin_dialog (*plugin, err_streams, _route);
361                         delete redirect;
362                 }
363         }
364 }
365
366 void
367 RedirectBox::wierd_plugin_dialog (Plugin& p, uint32_t streams, IO& io)
368 {
369         ArdourDialog dialog ("wierd plugin dialog");
370         Label label;
371
372         /* i hate this kind of code */
373
374         if (streams > p.get_info().n_inputs) {
375                 label.set_text (string_compose (_(
376 "You attempted to add a plugin (%1).\n"
377 "The plugin has %2 inputs\n"
378 "but at the insertion point, there are\n"
379 "%3 active signal streams.\n"
380 "\n"
381 "This makes no sense - you are throwing away\n"
382 "part of the signal."),
383                                          p.name(),
384                                          p.get_info().n_inputs,
385                                          streams));
386         } else if (streams < p.get_info().n_inputs) {
387                 label.set_text (string_compose (_(
388 "You attempted to add a plugin (%1).\n"
389 "The plugin has %2 inputs\n"
390 "but at the insertion point there are\n"
391 "only %3 active signal streams.\n"
392 "\n"
393 "This makes no sense - unless the plugin supports\n"
394 "side-chain inputs. A future version of Ardour will\n"
395 "support this type of configuration."),
396                                          p.name(),
397                                          p.get_info().n_inputs,
398                                          streams));
399         } else {
400                 label.set_text (string_compose (_(
401 "You attempted to add a plugin (%1).\n"
402 "\n"
403 "The I/O configuration doesn't make sense:\n"
404 "\n" 
405 "The plugin has %2 inputs and %3 outputs.\n"
406 "The track/bus has %4 inputs and %5 outputs.\n"
407 "The insertion point, has %6 active signals.\n"
408 "\n"
409 "Ardour does not understand what to do in such situations.\n"),
410                                          p.name(),
411                                          p.get_info().n_inputs,
412                                          p.get_info().n_outputs,
413                                          io.n_inputs(),
414                                          io.n_outputs(),
415                                          streams));
416         }
417
418         dialog.get_vbox()->pack_start (label);
419         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
420
421         dialog.set_name (X_("PluginIODialog"));
422         dialog.set_position (Gtk::WIN_POS_MOUSE);
423         dialog.set_modal (true);
424         dialog.show_all ();
425
426         // GTK2FIX
427         //dialog.realize();
428         //dialog.get_window()->set_decorations (Gdk::WMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
429
430         dialog.run ();
431 }
432
433 void
434 RedirectBox::choose_insert ()
435 {
436         Redirect *redirect = new PortInsert (_session, _placement);
437         redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active));
438         _route.add_redirect (redirect, this);
439 }
440
441 void
442 RedirectBox::choose_send ()
443 {
444         Send *send = new Send (_session, _placement);
445
446         /* XXX need redirect lock on route */
447
448         send->ensure_io (0, _route.max_redirect_outs(), false, this);
449         
450         IOSelectorWindow *ios = new IOSelectorWindow (_session, *send, false, true);
451         
452         ios->show_all ();
453         ios->selector().Finished.connect (bind (mem_fun(*this, &RedirectBox::send_io_finished), static_cast<Redirect*>(send), ios));
454 }
455
456 void
457 RedirectBox::send_io_finished (IOSelector::Result r, Redirect* redirect, IOSelectorWindow* ios)
458 {
459         switch (r) {
460         case IOSelector::Cancelled:
461                 delete redirect;
462                 break;
463
464         case IOSelector::Accepted:
465                 _route.add_redirect (redirect, this);
466                 break;
467         }
468
469         delete_when_idle (ios);
470 }
471
472 void
473 RedirectBox::redisplay_redirects (void *src)
474 {
475         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::redisplay_redirects), src));
476
477         if (no_redirect_redisplay) {
478                 return;
479         }
480
481         ignore_delete = true;
482         model->clear ();
483         ignore_delete = false;
484
485         redirect_active_connections.clear ();
486         redirect_name_connections.clear ();
487
488         _route.foreach_redirect (this, &RedirectBox::add_redirect_to_display);
489
490         switch (_placement) {
491         case PreFader:
492                 build_redirect_tooltip(redirect_eventbox, _("Pre-fader inserts, sends & plugins:"));
493                 break;
494         case PostFader:
495                 build_redirect_tooltip(redirect_eventbox, _("Post-fader inserts, sends & plugins:"));
496                 break;
497         }
498 }
499
500 void
501 RedirectBox::add_redirect_to_display (Redirect *redirect)
502 {
503         if (redirect->placement() != _placement) {
504                 return;
505         }
506         
507         Gtk::TreeModel::Row row = *(model->append());
508         row[columns.text] = redirect_name (*redirect);
509         row[columns.redirect] = redirect;
510         
511         show_redirect_active (redirect, this);
512
513         redirect_active_connections.push_back (redirect->active_changed.connect (mem_fun(*this, &RedirectBox::show_redirect_active)));
514         redirect_name_connections.push_back (redirect->name_changed.connect (bind (mem_fun(*this, &RedirectBox::show_redirect_name), redirect)));
515 }
516
517 string
518 RedirectBox::redirect_name (Redirect& redirect)
519 {
520         Send *send;
521         string name_display;
522
523         if (!redirect.active()) {
524                 name_display = " (";
525         }
526
527         if ((send = dynamic_cast<Send *> (&redirect)) != 0) {
528
529                 name_display += '>';
530
531                 /* grab the send name out of its overall name */
532
533                 string::size_type lbracket, rbracket;
534                 lbracket = send->name().find ('[');
535                 rbracket = send->name().find (']');
536
537                 switch (_width) {
538                 case Wide:
539                         name_display += send->name().substr (lbracket+1, lbracket-rbracket-1);
540                         break;
541                 case Narrow:
542                         name_display += short_version (send->name().substr (lbracket+1, lbracket-rbracket-1), 4);
543                         break;
544                 }
545
546         } else {
547
548                 switch (_width) {
549                 case Wide:
550                         name_display += redirect.name();
551                         break;
552                 case Narrow:
553                         name_display += short_version (redirect.name(), 5);
554                         break;
555                 }
556
557         }
558
559         if (!redirect.active()) {
560                 name_display += ')';
561         }
562
563         return name_display;
564 }
565
566 void
567 RedirectBox::build_redirect_tooltip (EventBox& box, string start)
568 {
569         string tip(start);
570
571         Gtk::TreeModel::Children children = model->children();
572         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
573                 Gtk::TreeModel::Row row = *iter;
574                 tip += '\n';
575                 tip += row[columns.text];
576         }
577         ARDOUR_UI::instance()->tooltips().set_tip (box, tip);
578 }
579
580 void
581 RedirectBox::show_redirect_name (void* src, Redirect *redirect)
582 {
583         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::show_redirect_name), src, redirect));
584         
585         show_redirect_active (redirect, src);
586 }
587
588 void
589 RedirectBox::show_redirect_active (Redirect *redirect, void *src)
590 {
591         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RedirectBox::show_redirect_active), redirect, src));
592
593         Gtk::TreeModel::Children children = model->children();
594         Gtk::TreeModel::Children::iterator iter = children.begin();
595
596         while( iter != children.end())
597         {
598                 if ((*iter)[columns.redirect] == redirect)
599                         break;
600                 iter++;
601         }
602
603         (*iter)[columns.text] = redirect_name (*redirect);
604
605         if (redirect->active()) {
606                 (*iter)[columns.color] = *active_redirect_color;
607         } else {
608                 (*iter)[columns.color] = *inactive_redirect_color;
609         }
610 }
611
612 void
613 RedirectBox::row_deleted (const Gtk::TreeModel::Path& path)
614 {
615         if (!ignore_delete) {
616                 compute_redirect_sort_keys ();
617         }
618 }
619
620 void
621 RedirectBox::compute_redirect_sort_keys ()
622 {
623         uint32_t sort_key = 0;
624         Gtk::TreeModel::Children children = model->children();
625
626         for (Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
627                 Redirect *redirect = (*iter)[columns.redirect];
628                 redirect->set_sort_key (sort_key);
629                 sort_key++;
630         }
631
632         if (_route.sort_redirects ()) {
633
634                 redisplay_redirects (0);
635
636                 /* now tell them about the problem */
637
638                 ArdourDialog dialog ("wierd plugin dialog");
639                 Label label;
640
641                 label.set_text (_("\
642 You cannot reorder this set of redirects\n\
643 in that way because the inputs and\n\
644 outputs do not work correctly."));
645
646                 dialog.get_vbox()->pack_start (label);
647                 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
648
649                 dialog.set_name (X_("PluginIODialog"));
650                 dialog.set_position (Gtk::WIN_POS_MOUSE);
651                 dialog.set_modal (true);
652                 dialog.show_all ();
653
654                 dialog.run ();
655         }
656 }
657
658 void
659 RedirectBox::rename_redirects ()
660 {
661         vector<Redirect*> to_be_renamed;
662         
663         get_selected_redirects (to_be_renamed);
664
665         if (to_be_renamed.empty()) {
666                 return;
667         }
668
669         for (vector<Redirect*>::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) {
670                 rename_redirect (*i);
671         }
672 }
673
674 void
675 RedirectBox::cut_redirects ()
676 {
677         vector<Redirect*> to_be_removed;
678         
679         get_selected_redirects (to_be_removed);
680
681         if (to_be_removed.empty()) {
682                 return;
683         }
684
685         /* this essentially transfers ownership of the redirect
686            of the redirect from the route to the mixer
687            selection.
688         */
689         
690         _rr_selection.set (to_be_removed);
691
692         for (vector<Redirect*>::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) {
693                 
694                 void* gui = (*i)->get_gui ();
695                 
696                 if (gui) {
697                         static_cast<Gtk::Widget*>(gui)->hide ();
698                 }
699                 
700                 if (_route.remove_redirect (*i, this)) {
701                         /* removal failed */
702                         _rr_selection.remove (*i);
703                 }
704
705         }
706 }
707
708 void
709 RedirectBox::copy_redirects ()
710 {
711         vector<Redirect*> to_be_copied;
712         vector<Redirect*> copies;
713
714         get_selected_redirects (to_be_copied);
715
716         if (to_be_copied.empty()) {
717                 return;
718         }
719
720         for (vector<Redirect*>::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) {
721                 copies.push_back (Redirect::clone (**i));
722         }
723
724         _rr_selection.set (copies);
725 }
726
727 gint
728 RedirectBox::idle_delete_redirect (Redirect *redirect)
729 {
730         /* NOT copied to _mixer.selection() */
731
732         if (_route.remove_redirect (redirect, this)) {
733                 /* removal failed */
734                 return FALSE;
735         }
736
737         delete redirect;
738         return FALSE;
739 }
740
741 void
742 RedirectBox::rename_redirect (Redirect* redirect)
743 {
744         ArdourDialog dialog (_("ardour: rename redirect"), true);
745         Entry  entry;
746         VBox   vbox;
747         HBox   hbox;
748         Button ok_button (_("OK"));
749         Button cancel_button (_("Cancel"));
750
751         dialog.set_name ("RedirectRenameWindow");
752         dialog.set_size_request (300, -1);
753         dialog.set_position (Gtk::WIN_POS_MOUSE);
754
755         dialog.add_action_widget (entry, RESPONSE_ACCEPT);
756         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
757         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
758         
759         entry.set_name ("RedirectNameDisplay");
760         entry.set_text (redirect->name());
761         entry.select_region (0, -1);
762         entry.grab_focus ();
763
764         switch (dialog.run ()) {
765         case RESPONSE_ACCEPT:
766                 redirect->set_name (entry.get_text(), this);
767                 break;
768         default:
769                 break;
770         }
771 }
772
773 void
774 RedirectBox::cut_redirect (Redirect *redirect)
775 {
776         /* this essentially transfers ownership of the redirect
777            of the redirect from the route to the mixer
778            selection.
779         */
780
781         _rr_selection.add (redirect);
782         
783         void* gui = redirect->get_gui ();
784
785         if (gui) {
786                 static_cast<Gtk::Widget*>(gui)->hide ();
787         }
788         
789         if (_route.remove_redirect (redirect, this)) {
790                 _rr_selection.remove (redirect);
791         }
792 }
793
794 void
795 RedirectBox::copy_redirect (Redirect *redirect)
796 {
797         Redirect* copy = Redirect::clone (*redirect);
798         _rr_selection.add (copy);
799 }
800
801 void
802 RedirectBox::paste_redirects ()
803 {
804         if (_rr_selection.redirects.empty()) {
805                 return;
806         }
807
808         paste_redirect_list (_rr_selection.redirects);
809 }
810
811 void
812 RedirectBox::paste_redirect_list (list<Redirect*>& redirects)
813 {
814         list<Redirect*> copies;
815
816         for (list<Redirect*>::iterator i = redirects.begin(); i != redirects.end(); ++i) {
817
818                 Redirect* copy = Redirect::clone (**i);
819
820                 copy->set_placement (_placement, this);
821                 copies.push_back (copy);
822         }
823
824         if (_route.add_redirects (copies, this)) {
825                 for (list<Redirect*>::iterator i = copies.begin(); i != copies.end(); ++i) {
826                         delete *i;
827                 }
828
829                 string msg = _(
830                         "Copying the set of redirects on the clipboard failed,\n\
831 probably because the I/O configuration of the plugins\n\
832 could not match the configuration of this track.");
833                 ArdourMessage am (0, X_("bad redirect copy dialog"), msg);
834         }
835 }
836
837 void
838 RedirectBox::activate_redirect (Redirect *r)
839 {
840         r->set_active (true, 0);
841 }
842
843 void
844 RedirectBox::deactivate_redirect (Redirect *r)
845 {
846         r->set_active (false, 0);
847 }
848
849 void
850 RedirectBox::get_selected_redirects (vector<Redirect*>& redirects)
851 {
852     vector<Gtk::TreeModel::Path> pathlist = redirect_display.get_selection()->get_selected_rows();
853  
854         for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter)
855                 redirects.push_back ((*(model->get_iter(*iter)))[columns.redirect]);
856 }
857
858 void
859 RedirectBox::for_selected_redirects (void (RedirectBox::*pmf)(Redirect*))
860 {
861     vector<Gtk::TreeModel::Path> pathlist = redirect_display.get_selection()->get_selected_rows();
862
863         for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) {
864                 Redirect* redirect = (*(model->get_iter(*iter)))[columns.redirect];
865                 (this->*pmf)(redirect);
866         }
867 }
868
869 void
870 RedirectBox::clone_redirects ()
871 {
872         RouteSelection& routes (_rr_selection.routes);
873
874         if (!routes.empty()) {
875                 if (_route.copy_redirects (*routes.front(), _placement)) {
876                         string msg = _(
877 "Copying the set of redirects on the clipboard failed,\n\
878 probably because the I/O configuration of the plugins\n\
879 could not match the configuration of this track.");
880                         ArdourMessage am (0, X_("bad redirect copy dialog"), msg);
881                 }
882         }
883 }
884
885 void
886 RedirectBox::all_redirects_active (bool state)
887 {
888         _route.all_redirects_active (state);
889 }
890
891 void
892 RedirectBox::clear_redirects()
893 {
894         string prompt;
895         vector<string> choices;
896
897         if (dynamic_cast<AudioTrack*>(&_route) != 0) {
898                 prompt = _("Do you really want to remove all redirects from this track?\n"
899                            "(this cannot be undone)");
900         } else {
901                 prompt = _("Do you really want to remove all redirects from this bus?\n"
902                            "(this cannot be undone)");
903         }
904
905         choices.push_back (_("Yes, remove them all"));
906         choices.push_back (_("Cancel"));
907
908         Gtkmm2ext::Choice prompter (prompt, choices);
909
910         prompter.chosen.connect(sigc::ptr_fun(Gtk::Main::quit));
911         prompter.show_all ();
912
913         Gtk::Main::run ();
914
915         if (prompter.get_choice() == 0) {
916                 _route.clear_redirects (this);
917         }
918 }
919
920
921 void
922 RedirectBox::edit_redirect (Redirect* redirect)
923 {
924         Insert *insert;
925
926         if (dynamic_cast<AudioTrack*>(&_route) != 0) {
927
928                 if (dynamic_cast<AudioTrack*> (&_route)->freeze_state() == AudioTrack::Frozen) {
929                         return;
930                 }
931         }
932         
933         if ((insert = dynamic_cast<Insert *> (redirect)) == 0) {
934                 
935                 /* its a send */
936                 
937                 if (!_session.engine().connected()) {
938                         return;
939                 }
940
941                 Send *send = dynamic_cast<Send*> (redirect);
942                 
943                 SendUIWindow *send_ui;
944                 
945                 if (send->get_gui() == 0) {
946                         
947                         string title;
948                         title = string_compose(_("ardour: %1"), send->name());  
949                         
950                         send_ui = new SendUIWindow (*send, _session);
951                         send_ui->set_title (title);
952                         send->set_gui (send_ui);
953                         
954                 } else {
955                         send_ui = reinterpret_cast<SendUIWindow *> (send->get_gui());
956                 }
957                 
958                 if (send_ui->is_visible()) {
959                         send_ui->get_window()->raise ();
960                 } else {
961                         send_ui->show_all ();
962                 }
963                 
964         } else {
965                 
966                 /* its an insert */
967                 
968                 PluginInsert *plugin_insert;
969                 PortInsert *port_insert;
970                 
971                 if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
972                         
973                         PluginUIWindow *plugin_ui;
974                         
975                         if (plugin_insert->get_gui() == 0) {
976                                 
977                                 string title;
978                                 string maker = plugin_insert->plugin().maker();
979                                 string::size_type email_pos;
980                                 
981                                 if ((email_pos = maker.find_first_of ('<')) != string::npos) {
982                                         maker = maker.substr (0, email_pos - 1);
983                                 }
984                                 
985                                 if (maker.length() > 32) {
986                                         maker = maker.substr (0, 32);
987                                         maker += " ...";
988                                 }
989
990                                 title = string_compose(_("ardour: %1: %2 (by %3)"), _route.name(), plugin_insert->name(), maker);       
991                                 
992                                 plugin_ui = new PluginUIWindow (_session.engine(), *plugin_insert);
993                                 if (_owner_is_mixer) {
994                                         ARDOUR_UI::instance()->the_mixer()->ensure_float (*plugin_ui);
995                                 } else {
996                                         ARDOUR_UI::instance()->the_editor().ensure_float (*plugin_ui);
997                                 }
998                                 plugin_ui->set_title (title);
999                                 plugin_insert->set_gui (plugin_ui);
1000                                 
1001                         } else {
1002                                 plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
1003                         }
1004                         
1005                         if (plugin_ui->is_visible()) {
1006                                 plugin_ui->get_window()->raise ();
1007                         } else {
1008                                 plugin_ui->show_all ();
1009                         }
1010                         
1011                 } else if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
1012                         
1013                         if (!_session.engine().connected()) {
1014                                 ArdourMessage msg (NULL, "nojackdialog", _("Not connected to JACK - no I/O changes are possible"));
1015                                 return;
1016                         }
1017
1018                         PortInsertWindow *io_selector;
1019
1020                         if (port_insert->get_gui() == 0) {
1021                                 io_selector = new PortInsertWindow (_session, *port_insert);
1022                                 port_insert->set_gui (io_selector);
1023                                 
1024                         } else {
1025                                 io_selector = reinterpret_cast<PortInsertWindow *> (port_insert->get_gui());
1026                         }
1027                         
1028                         if (io_selector->is_visible()) {
1029                                 io_selector->get_window()->raise ();
1030                         } else {
1031                                 io_selector->show_all ();
1032                         }
1033                 }
1034         }
1035 }
1036
1037 bool
1038 RedirectBox::enter_box (GdkEventCrossing *ev, RedirectBox* rb)
1039 {
1040         switch (ev->detail) {
1041         case GDK_NOTIFY_INFERIOR:
1042                 break;
1043
1044         case GDK_NOTIFY_VIRTUAL:
1045                 /* fallthru */
1046
1047         default:
1048                 _current_redirect_box = rb;
1049         }
1050
1051         return false;
1052 }
1053
1054 void
1055 RedirectBox::register_actions ()
1056 {
1057         Glib::RefPtr<Gtk::ActionGroup> popup_act_grp = Gtk::ActionGroup::create(X_("redirectmenu"));
1058         Glib::RefPtr<Action> act;
1059
1060         /* new stuff */
1061         ActionManager::register_action (popup_act_grp, X_("newplugin"), _("New Plugin ..."),  sigc::ptr_fun (RedirectBox::rb_choose_plugin));
1062         ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"),  sigc::ptr_fun (RedirectBox::rb_choose_insert));
1063         ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."),  sigc::ptr_fun (RedirectBox::rb_choose_send));
1064         ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"),  sigc::ptr_fun (RedirectBox::rb_clear));
1065
1066         /* standard editing stuff */
1067         act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),  sigc::ptr_fun (RedirectBox::rb_cut));
1068         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1069         act = ActionManager::register_action (popup_act_grp, X_("copy"), _("Copy"),  sigc::ptr_fun (RedirectBox::rb_copy));
1070         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1071         paste_action = ActionManager::register_action (popup_act_grp, X_("paste"), _("Paste"),  sigc::ptr_fun (RedirectBox::rb_paste));
1072         act = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),  sigc::ptr_fun (RedirectBox::rb_rename));
1073         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1074         ActionManager::register_action (popup_act_grp, X_("selectall"), _("Select All"),  sigc::ptr_fun (RedirectBox::rb_select_all));
1075         ActionManager::register_action (popup_act_grp, X_("deselectall"), _("Deselect All"),  sigc::ptr_fun (RedirectBox::rb_deselect_all));
1076                 
1077         /* activation */
1078         act = ActionManager::register_action (popup_act_grp, X_("activate"), _("Activate"),  sigc::ptr_fun (RedirectBox::rb_activate));
1079         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1080         act = ActionManager::register_action (popup_act_grp, X_("deactivate"), _("Deactivate"),  sigc::ptr_fun (RedirectBox::rb_deactivate));
1081         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1082         ActionManager::register_action (popup_act_grp, X_("activate_all"), _("Activate all"),  sigc::ptr_fun (RedirectBox::rb_activate_all));
1083         ActionManager::register_action (popup_act_grp, X_("deactivate_all"), _("Deactivate all"),  sigc::ptr_fun (RedirectBox::rb_deactivate_all));
1084
1085         /* show editors */
1086         act = ActionManager::register_action (popup_act_grp, X_("edit"), _("Edit"),  sigc::ptr_fun (RedirectBox::rb_edit));
1087         ActionManager::plugin_selection_sensitive_actions.push_back(act);
1088
1089         ActionManager::add_action_group (popup_act_grp);
1090 }
1091
1092 void
1093 RedirectBox::rb_choose_plugin ()
1094 {
1095         if (_current_redirect_box == 0) {
1096                 return;
1097         }
1098         _current_redirect_box->choose_plugin ();
1099 }
1100
1101 void
1102 RedirectBox::rb_choose_insert ()
1103 {
1104         if (_current_redirect_box == 0) {
1105                 return;
1106         }
1107         _current_redirect_box->choose_insert ();
1108 }
1109
1110 void
1111 RedirectBox::rb_choose_send ()
1112 {
1113         if (_current_redirect_box == 0) {
1114                 return;
1115         }
1116         _current_redirect_box->choose_send ();
1117 }
1118
1119 void
1120 RedirectBox::rb_clear ()
1121 {
1122         if (_current_redirect_box == 0) {
1123                 return;
1124         }
1125
1126         _current_redirect_box->clear_redirects ();
1127 }
1128
1129 void
1130 RedirectBox::rb_cut ()
1131 {
1132         if (_current_redirect_box == 0) {
1133                 return;
1134         }
1135
1136         _current_redirect_box->cut_redirects ();
1137 }
1138
1139 void
1140 RedirectBox::rb_copy ()
1141 {
1142         if (_current_redirect_box == 0) {
1143                 return;
1144         }
1145         _current_redirect_box->copy_redirects ();
1146 }
1147
1148 void
1149 RedirectBox::rb_paste ()
1150 {
1151         if (_current_redirect_box == 0) {
1152                 return;
1153         }
1154
1155         _current_redirect_box->paste_redirects ();
1156 }
1157
1158 void
1159 RedirectBox::rb_rename ()
1160 {
1161         if (_current_redirect_box == 0) {
1162                 return;
1163         }
1164         _current_redirect_box->rename_redirects ();
1165 }
1166
1167 void
1168 RedirectBox::rb_select_all ()
1169 {
1170         if (_current_redirect_box == 0) {
1171                 return;
1172         }
1173
1174         _current_redirect_box->select_all_redirects ();
1175 }
1176
1177 void
1178 RedirectBox::rb_deselect_all ()
1179 {
1180         if (_current_redirect_box == 0) {
1181                 return;
1182         }
1183
1184         _current_redirect_box->deselect_all_redirects ();
1185 }
1186
1187 void
1188 RedirectBox::rb_activate ()
1189 {
1190         if (_current_redirect_box == 0) {
1191                 return;
1192         }
1193
1194         _current_redirect_box->for_selected_redirects (&RedirectBox::activate_redirect);
1195 }
1196
1197 void
1198 RedirectBox::rb_deactivate ()
1199 {
1200         if (_current_redirect_box == 0) {
1201                 return;
1202         }
1203         _current_redirect_box->for_selected_redirects (&RedirectBox::deactivate_redirect);
1204 }
1205
1206 void
1207 RedirectBox::rb_activate_all ()
1208 {
1209         if (_current_redirect_box == 0) {
1210                 return;
1211         }
1212
1213         _current_redirect_box->all_redirects_active (true);
1214 }
1215
1216 void
1217 RedirectBox::rb_deactivate_all ()
1218 {
1219         if (_current_redirect_box == 0) {
1220                 return;
1221         }
1222         _current_redirect_box->all_redirects_active (false);
1223 }
1224
1225 void
1226 RedirectBox::rb_edit ()
1227 {
1228         if (_current_redirect_box == 0) {
1229                 return;
1230         }
1231
1232         _current_redirect_box->for_selected_redirects (&RedirectBox::edit_redirect);
1233 }
1234