enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[ardour.git] / gtk2_ardour / route_group_menu.cc
1 /*
2     Copyright (C) 2009 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 <gtkmm/menu.h>
21 #include <gtkmm/stock.h>
22
23 #include "gtkmm2ext/utils.h"
24 #include "gtkmm2ext/doi.h"
25
26 #include "ardour/session.h"
27 #include "ardour/route_group.h"
28 #include "ardour/route.h"
29 #include "route_group_menu.h"
30 #include "route_group_dialog.h"
31
32 #include "pbd/i18n.h"
33
34 using namespace Gtk;
35 using namespace ARDOUR;
36 using namespace PBD;
37
38 RouteGroupMenu::RouteGroupMenu (Session* s, PropertyList* plist)
39         : SessionHandlePtr (s)
40         , _menu (0)
41         , _default_properties (plist)
42         , _inhibit_group_selected (false)
43 {
44
45 }
46
47 RouteGroupMenu::~RouteGroupMenu()
48 {
49         delete _menu;
50         delete _default_properties;
51 }
52
53 /** @param s Routes to operate on */
54 void
55 RouteGroupMenu::build (WeakRouteList const & s)
56 {
57         assert (!s.empty ());
58
59         using namespace Menu_Helpers;
60
61         _subject = s;
62
63         /* FInd all the route groups that our subjects are members of */
64         std::set<RouteGroup*> groups;
65         for (WeakRouteList::const_iterator i = _subject.begin (); i != _subject.end(); ++i) {
66                 boost::shared_ptr<Route> r = i->lock ();
67                 if (r) {
68                         groups.insert (r->route_group ());
69                 }
70         }
71
72         _inhibit_group_selected = true;
73
74         delete _menu;
75
76         /* Note: don't use manage() here, otherwise if our _menu object is attached as a submenu
77            and its parent is then destroyed, our _menu object will be deleted and we'll have no
78            way of knowing about it.  Without manage(), when the above happens our _menu's gobject
79            will be destroyed and its value set to 0, so we know.
80         */
81         _menu = new Menu;
82
83         MenuList& items = _menu->items ();
84
85         items.push_back (MenuElem (_("New Group..."), sigc::mem_fun (*this, &RouteGroupMenu::new_group)));
86         items.push_back (SeparatorElem ());
87
88         RadioMenuItem::Group group;
89         items.push_back (RadioMenuElem (group, _("No Group")));
90         RadioMenuItem* i = static_cast<RadioMenuItem *> (&items.back ());
91         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::set_group), (RouteGroup *) 0));
92
93         if (groups.size() == 1 && *groups.begin() == 0) {
94                 i->set_active ();
95         } else if (groups.size() > 1) {
96                 i->set_inconsistent ();
97         }
98
99         if (_session) {
100                 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::add_item), groups, &group));
101         }
102
103         _inhibit_group_selected = false;
104 }
105
106 /** @param rg Route group to add.
107  *  @param groups Active route groups (may included 0 for `no group')
108  *  @param group Radio item group to add radio items to.
109  */
110 void
111 RouteGroupMenu::add_item (RouteGroup* rg, std::set<RouteGroup*> const & groups, RadioMenuItem::Group* group)
112 {
113         using namespace Menu_Helpers;
114
115         MenuList& items = _menu->items ();
116
117         items.push_back (RadioMenuElem (*group, rg->name()));
118         RadioMenuItem* i = static_cast<RadioMenuItem*> (&items.back ());
119         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::set_group), rg));
120
121         if (groups.size() == 1 && *groups.begin() == rg) {
122                 /* there's only one active group, and it's this one */
123                 i->set_active ();
124         } else if (groups.size() > 1) {
125                 /* there are >1 active groups */
126                 i->set_inconsistent ();
127         }
128 }
129
130 /** Called when a group is selected from the menu.
131  *  @param Group, or 0 for none.
132  */
133 void
134 RouteGroupMenu::set_group (RouteGroup* g)
135 {
136         if (_inhibit_group_selected) {
137                 return;
138         }
139
140         for (WeakRouteList::const_iterator i = _subject.begin(); i != _subject.end(); ++i) {
141                 boost::shared_ptr<Route> r = i->lock ();
142                 if (!r || r->route_group () == g) {
143                         /* lock of weak_ptr failed, or the group for this route is already right */
144                         continue;
145                 }
146
147                 if (g) {
148                         g->add (r);
149                 } else {
150                         if (r->route_group ()) {
151                                 r->route_group()->remove (r);
152                         }
153                 }
154         }
155 }
156
157 void
158 RouteGroupMenu::new_group ()
159 {
160         if (!_session) {
161                 return;
162         }
163
164         RouteGroup* g = new RouteGroup (*_session, "");
165         RouteGroupDialog* d = new RouteGroupDialog (g, true);
166
167         d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &RouteGroupMenu::new_group_dialog_finished), d));
168         d->present ();
169 }
170
171 void
172 RouteGroupMenu::new_group_dialog_finished (int r, RouteGroupDialog* d)
173 {
174         if (r == RESPONSE_OK) {
175                 _session->add_route_group (d->group());
176                 set_group (d->group());
177         } else {
178                 delete d->group ();
179         }
180
181         delete_when_idle (d);
182 }
183
184 Gtk::Menu *
185 RouteGroupMenu::menu ()
186 {
187         /* Our menu's gobject can be 0 if it was attached as a submenu whose
188            parent was subsequently deleted.
189         */
190         assert (_menu && _menu->gobj());
191         return _menu;
192 }
193
194 void
195 RouteGroupMenu::detach ()
196 {
197         if (_menu && _menu->gobj ()) {
198                 Gtkmm2ext::detach_menu (*_menu);
199         }
200 }