d2bd765cce199ac66f5afcdbe582ab913cce68b2
[ardour.git] / gtk2_ardour / playlist_selector.cc
1 /*
2     Copyright (C) 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
22 #include <gtkmm/button.h>
23 #include <gtkmm/ctree.h>
24
25 #include <ardour/session_playlist.h>
26 #include <ardour/diskstream.h>
27 #include <ardour/playlist.h>
28 #include <ardour/audio_track.h>
29 #include <ardour/audioplaylist.h>
30 #include <ardour/configuration.h>
31
32 #include <gtkmm2ext/gtk_ui.h>
33
34 #include "playlist_selector.h"
35 #include "route_ui.h"
36 #include "gui_thread.h"
37
38 #include "i18n.h"
39
40 using namespace std;
41 using namespace sigc;
42 using namespace Gtk;
43 using namespace ARDOUR;
44
45 static const gchar *tree_display_titles[] = {
46         N_("Playlists grouped by track"), 
47         0
48 };
49
50 PlaylistSelector::PlaylistSelector ()
51         : ArdourDialog ("playlist selector"),
52           tree (internationalize (tree_display_titles)),
53           close_button (_("close"))
54 {
55         rui = 0;
56         
57         set_position (Gtk::WIN_POS_MOUSE);
58         set_name ("PlaylistSelectorWindow");
59         set_title (_("ardour: playlists"));
60         set_modal(true);
61         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
62         set_size_request (300, 200);
63
64         scroller.add_with_viewport (tree);
65         scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
66
67         close_button.signal_clicked().connect (mem_fun(*this, &PlaylistSelector::close_button_click));
68
69         vpacker.set_border_width (6);
70         vpacker.set_spacing (12);
71         vpacker.pack_start (scroller);
72         vpacker.pack_start (close_button, false, false);
73
74         add (vpacker);
75 }
76
77 PlaylistSelector::~PlaylistSelector ()
78 {
79         clear_map ();
80 }
81
82 void
83 PlaylistSelector::clear_map ()
84 {
85         for (DSPL_Map::iterator x = dspl_map.begin(); x != dspl_map.end(); ++x) {
86                 delete x->second;
87         }
88         dspl_map.clear ();
89 }
90
91 void
92 PlaylistSelector::show_for (RouteUI* ruix)
93 {
94         using namespace CTree_Helpers;
95         vector<const char*> item;
96         RowList::iterator i;
97         RowList::iterator tmpi;
98         RowList::iterator others;
99         DiskStream* this_ds;
100         string str;
101
102         rui = ruix;
103
104         str = _("ardour: playlist for ");
105         str += rui->route().name();
106
107         set_title (str);
108
109         clear_map ();
110         select_connection.disconnect ();
111
112         /* ---------------------------------------- */
113         /* XXX MAKE ME A FUNCTION (no CTree::clear() in gtkmm 1.2) */
114         gtk_ctree_remove_node (tree.gobj(), NULL);
115         /* ---------------------------------------- */
116         
117         session->foreach_playlist (this, &PlaylistSelector::add_playlist_to_map);
118
119         this_ds = rui->get_diskstream();
120
121         item.clear();
122         item.push_back (_("Other tracks"));
123         others = tree.rows().insert (tree.rows().begin(), Element (item));
124
125         for (DSPL_Map::iterator x = dspl_map.begin(); x != dspl_map.end(); ++x) {
126
127                 DiskStream* ds = session->diskstream_by_id (x->first);
128
129                 if (ds == 0) {
130                         continue;
131                 }
132
133                 /* add a node for the diskstream */
134
135                 item.clear ();
136
137                 if (ds->name().empty()) {
138                         item.push_back (_("unassigned"));
139                 } else {
140                         item.push_back (ds->name().c_str());
141                 }
142
143                 if (ds == this_ds) {
144                         i = tree.rows().insert (tree.rows().begin(),
145                                                 Gtk::CTree_Helpers::Element (item));
146                 } else {
147                         i = others->subtree().insert (others->subtree().end(),
148                                                       Gtk::CTree_Helpers::Element (item));
149                 }
150                 
151                 /* Now insert all the playlists for this diskstream/track in a subtree */
152                 
153                 list<Playlist*> *pls = x->second;
154
155                 for (list<Playlist*>::iterator p = pls->begin(); p != pls->end(); ++p) {
156
157                         item.clear ();
158                         item.push_back ((*p)->name().c_str());
159
160                         tmpi = i->subtree().insert (i->subtree().end(), Element (item));
161
162                         if (*p == this_ds->playlist()) {
163                                 (*tmpi).select ();
164                         } 
165
166                         (*tmpi).set_data (*p);
167                         
168                 }
169
170                 if (ds == this_ds) {
171                         i->expand ();
172                 }
173         }
174
175         show_all ();
176         select_connection = tree.tree_select_row.connect (mem_fun(*this, &PlaylistSelector::row_selected));
177 }
178
179 void
180 PlaylistSelector::add_playlist_to_map (Playlist *pl)
181 {
182         AudioPlaylist* apl;
183
184         if (pl->frozen()) {
185                 return;
186         }
187
188         if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
189                 return;
190         }
191
192         DSPL_Map::iterator x;
193
194         if ((x = dspl_map.find (apl->get_orig_diskstream_id())) == dspl_map.end()) {
195
196                 pair<ARDOUR::id_t,list<Playlist*>*> newp (apl->get_orig_diskstream_id(), new list<Playlist*>);
197                 
198                 x = dspl_map.insert (dspl_map.end(), newp);
199         }
200
201         x->second->push_back (pl);
202 }
203
204 void
205 PlaylistSelector::set_session (Session* s)
206 {
207         ENSURE_GUI_THREAD(bind (mem_fun(*this, &PlaylistSelector::set_session), s));
208
209         session = s;
210
211         if (session) {
212                 session->going_away.connect (bind (mem_fun(*this, &PlaylistSelector::set_session), static_cast<Session*> (0)));
213         }
214 }
215
216 void
217 PlaylistSelector::close_button_click ()
218 {
219         rui = 0;
220         hide ();
221 }
222
223 void
224 PlaylistSelector::row_selected (Gtk::CTree::Row row, gint col)
225 {
226         Playlist *playlist;
227         
228         if ((playlist = (Playlist *) row.get_data()) != 0) {
229                 
230                 AudioTrack* at;
231                 AudioPlaylist* apl;
232                 
233                 if ((at = dynamic_cast<AudioTrack*> (&rui->route())) == 0) {
234                         /* eh? */
235                         return;
236                 }
237                 
238                 if ((apl = dynamic_cast<AudioPlaylist*> (playlist)) == 0) {
239                         /* eh? */
240                         return;
241                 }
242                 
243                 at->disk_stream().use_playlist (apl);
244
245                 hide ();
246         }
247
248 }
249