Reenable the correct sort column and type when redisplaying regions
[ardour.git] / gtk2_ardour / playlist_selector.cc
1 /*
2  * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
4  * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
5  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6  * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include <gtkmm/button.h>
24
25 #include "ardour/audio_track.h"
26 #include "ardour/audioplaylist.h"
27 #include "ardour/playlist.h"
28 #include "ardour/session_playlist.h"
29
30 #include <gtkmm2ext/gtk_ui.h>
31
32 #include "playlist_selector.h"
33 #include "route_ui.h"
34 #include "gui_thread.h"
35
36 #include "pbd/i18n.h"
37
38 using namespace std;
39 using namespace Gtk;
40 using namespace Gtkmm2ext;
41 using namespace ARDOUR;
42 using namespace PBD;
43
44 PlaylistSelector::PlaylistSelector ()
45         : ArdourDialog (_("Playlists"))
46 {
47         rui = 0;
48
49         set_name ("PlaylistSelectorWindow");
50         set_modal(true);
51         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
52         set_size_request (300, 200);
53
54         model = TreeStore::create (columns);
55         tree.set_model (model);
56         tree.append_column (_("Playlists grouped by track"), columns.text);
57
58         scroller.add (tree);
59         scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
60
61         get_vbox()->set_border_width (6);
62         get_vbox()->set_spacing (12);
63
64         get_vbox()->pack_start (scroller);
65
66         Button* b = add_button (_("Close"), RESPONSE_CANCEL);
67         b->signal_clicked().connect (sigc::mem_fun(*this, &PlaylistSelector::close_button_click));
68
69 }
70
71 PlaylistSelector::~PlaylistSelector ()
72 {
73         clear_map ();
74 }
75
76 void
77 PlaylistSelector::clear_map ()
78 {
79         for (TrackPlaylistMap::iterator x = trpl_map.begin(); x != trpl_map.end(); ++x) {
80                 delete x->second;
81         }
82         trpl_map.clear ();
83 }
84
85 bool
86 PlaylistSelector::on_unmap_event (GdkEventAny* ev)
87 {
88         clear_map ();
89         if (model) {
90                 model->clear ();
91         }
92         return Dialog::on_unmap_event (ev);
93 }
94
95 void
96 PlaylistSelector::show_for (RouteUI* ruix)
97 {
98         vector<const char*> item;
99         string str;
100
101         rui = ruix;
102
103         set_title (string_compose (_("Playlist for %1"), rui->route()->name()));
104
105         clear_map ();
106         select_connection.disconnect ();
107
108         model->clear ();
109
110         _session->playlists()->foreach (this, &PlaylistSelector::add_playlist_to_map);
111
112         boost::shared_ptr<Track> this_track = rui->track();
113
114         TreeModel::Row others = *(model->append ());
115
116         others[columns.text] = _("Other tracks");
117         boost::shared_ptr<Playlist> proxy = others[columns.playlist];
118         proxy.reset ();
119
120         for (TrackPlaylistMap::iterator x = trpl_map.begin(); x != trpl_map.end(); ++x) {
121
122                 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (_session->route_by_id (x->first));
123
124                 /* add a node for the track */
125
126                 string nodename;
127
128                 if (!tr || tr->name().empty()) {
129                         nodename = _("unassigned");
130                 } else {
131                         nodename = tr->name().c_str();
132                 }
133
134                 TreeModel::Row row;
135                 TreeModel::Row selected_row;
136                 bool have_selected = false;
137                 TreePath this_path;
138
139                 if (tr == this_track) {
140                         row = *(model->prepend());
141                         row[columns.text] = nodename;
142                         boost::shared_ptr<Playlist> proxy = row[columns.playlist];
143                         proxy.reset ();
144                 } else {
145                         row = *(model->append (others.children()));
146                         row[columns.text] = nodename;
147                         boost::shared_ptr<Playlist> proxy = row[columns.playlist];
148                         proxy.reset ();
149                 }
150
151                 /* Now insert all the playlists for this diskstream/track in a subtree */
152
153                 list<boost::shared_ptr<Playlist> >* pls = x->second;
154
155                 for (list<boost::shared_ptr<Playlist> >::iterator p = pls->begin(); p != pls->end(); ++p) {
156
157                         TreeModel::Row child_row;
158
159                         child_row = *(model->append (row.children()));
160                         child_row[columns.text] = (*p)->name();
161                         child_row[columns.playlist] = *p;
162
163                         if (*p == this_track->playlist()) {
164                                 selected_row = child_row;
165                                 have_selected = true;
166                         }
167                 }
168
169                 if (have_selected) {
170                         tree.get_selection()->select (selected_row);
171                 }
172         }
173
174         // Add unassigned (imported) playlists to the list
175         list<boost::shared_ptr<Playlist> > unassigned;
176         _session->playlists()->unassigned (unassigned);
177
178         TreeModel::Row row;
179         TreeModel::Row selected_row;
180         bool have_selected = false;
181         TreePath this_path;
182
183         row = *(model->append (others.children()));
184         row[columns.text] = _("Imported");
185         proxy = row[columns.playlist];
186         proxy.reset ();
187
188         for (list<boost::shared_ptr<Playlist> >::iterator p = unassigned.begin(); p != unassigned.end(); ++p) {
189                 TreeModel::Row child_row;
190
191                 child_row = *(model->append (row.children()));
192                 child_row[columns.text] = (*p)->name();
193                 child_row[columns.playlist] = *p;
194
195                 if (*p == this_track->playlist()) {
196                         selected_row = child_row;
197                         have_selected = true;
198                 }
199
200                 if (have_selected) {
201                         tree.get_selection()->select (selected_row);
202                 }
203         }
204
205         show_all ();
206         select_connection = tree.get_selection()->signal_changed().connect (sigc::mem_fun(*this, &PlaylistSelector::selection_changed));
207 }
208
209 void
210 PlaylistSelector::add_playlist_to_map (boost::shared_ptr<Playlist> pl)
211 {
212         boost::shared_ptr<AudioPlaylist> apl;
213
214         if (pl->frozen()) {
215                 return;
216         }
217
218         if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
219                 return;
220         }
221
222         TrackPlaylistMap::iterator x;
223
224         if ((x = trpl_map.find (apl->get_orig_track_id())) == trpl_map.end()) {
225                 x = trpl_map.insert (trpl_map.end(), make_pair (apl->get_orig_track_id(), new list<boost::shared_ptr<Playlist> >));
226         }
227
228         x->second->push_back (pl);
229 }
230
231 void
232 PlaylistSelector::close_button_click ()
233 {
234         rui = 0;
235         hide ();
236 }
237
238 void
239 PlaylistSelector::selection_changed ()
240 {
241         boost::shared_ptr<Playlist> playlist;
242
243         TreeModel::iterator iter = tree.get_selection()->get_selected();
244
245         if (!iter || rui == 0) {
246                 /* nothing selected */
247                 return;
248         }
249
250         if ((playlist = ((*iter)[columns.playlist])) != 0) {
251
252                 boost::shared_ptr<AudioTrack> at;
253                 boost::shared_ptr<AudioPlaylist> apl;
254
255                 if ((at = rui->audio_track()) == 0) {
256                         /* eh? */
257                         return;
258                 }
259
260                 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (playlist)) == 0) {
261                         /* eh? */
262                         return;
263                 }
264
265                 at->use_playlist (DataType::AUDIO, apl);
266
267                 hide ();
268         }
269
270 }
271