new mono panner widget; make stereo panner respond to changes in colors immediately
[ardour.git] / gtk2_ardour / session_import_dialog.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Sakari Bergen
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "session_import_dialog.h"
22
23 #include "pbd/failed_constructor.h"
24
25 #include "ardour/audio_region_importer.h"
26 #include "ardour/audio_playlist_importer.h"
27 #include "ardour/audio_track_importer.h"
28 #include "ardour/location_importer.h"
29 #include "ardour/tempo_map_importer.h"
30
31 #include <gtkmm2ext/utils.h>
32
33 #include "gui_thread.h"
34 #include "prompter.h"
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace PBD;
40 using namespace Gtk;
41
42 SessionImportDialog::SessionImportDialog (ARDOUR::Session* target) :
43   ArdourDialog (_("Import From Session")),
44   file_browse_button (_("Browse"))
45 {
46         set_session (target);
47
48         // File entry
49         file_entry.set_name ("ImportFileNameEntry");
50         file_entry.set_text ("/");
51         Gtkmm2ext::set_size_request_to_display_given_text (file_entry, X_("Kg/quite/a/reasonable/size/for/files/i/think"), 5, 8);
52
53         file_browse_button.set_name ("EditorGTKButton");
54         file_browse_button.signal_clicked().connect (sigc::mem_fun(*this, &SessionImportDialog::browse));
55
56         file_hbox.set_spacing (5);
57         file_hbox.set_border_width (5);
58         file_hbox.pack_start (file_entry, true, true);
59         file_hbox.pack_start (file_browse_button, false, false);
60
61         file_frame.add (file_hbox);
62         file_frame.set_border_width (5);
63         file_frame.set_name ("ImportFrom");
64         file_frame.set_label (_("Import from Session"));
65
66         get_vbox()->pack_start (file_frame, false, false);
67
68         // Session browser
69         session_tree = TreeStore::create (sb_cols);
70         session_browser.set_model (session_tree);
71
72         session_browser.set_name ("SessionBrowser");
73         session_browser.append_column (_("Elements"), sb_cols.name);
74         session_browser.append_column_editable (_("Import"), sb_cols.queued);
75         session_browser.set_tooltip_column (3);
76         session_browser.get_column(0)->set_min_width (180);
77         session_browser.get_column(1)->set_min_width (40);
78         session_browser.get_column(1)->set_sizing (TREE_VIEW_COLUMN_AUTOSIZE);
79
80         session_scroll.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC);
81         session_scroll.add (session_browser);
82         session_scroll.set_size_request (220, 400);
83
84         // Connect signals
85         CellRendererToggle *toggle = dynamic_cast<CellRendererToggle *> (session_browser.get_column_cell_renderer (1));
86         toggle->signal_toggled().connect(sigc::mem_fun (*this, &SessionImportDialog::update));
87         session_browser.signal_row_activated().connect(sigc::mem_fun (*this, &SessionImportDialog::show_info));
88
89         get_vbox()->pack_start (session_scroll, false, false);
90
91         // Buttons
92         cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
93         cancel_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::end_dialog));
94         ok_button = add_button (_("Import"), RESPONSE_ACCEPT);
95         ok_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::do_merge));
96
97         // prompt signals XXX: problem - handlers to be in the same thread since they return values
98         ElementImporter::Rename.connect_same_thread (connections, boost::bind (&SessionImportDialog::open_rename_dialog, this, _1, _2));
99         ElementImporter::Prompt.connect_same_thread (connections, boost::bind (&SessionImportDialog::open_prompt_dialog, this, _1));
100                 
101         // Finalize
102         show_all();
103 }
104
105 void
106 SessionImportDialog::load_session (const string& filename)
107 {
108         if (_session) {
109                 if (tree.read (filename)) {
110                         error << string_compose (_("Cannot load XML for session from %1"), filename) << endmsg;
111                         return;
112                 }
113                 boost::shared_ptr<AudioRegionImportHandler> region_handler (new AudioRegionImportHandler (tree, *_session));
114                 boost::shared_ptr<AudioPlaylistImportHandler> pl_handler (new AudioPlaylistImportHandler (tree, *_session, *region_handler));
115                 
116                 handlers.push_back (boost::static_pointer_cast<ElementImportHandler> (region_handler));
117                 handlers.push_back (boost::static_pointer_cast<ElementImportHandler> (pl_handler));
118                 handlers.push_back (HandlerPtr(new UnusedAudioPlaylistImportHandler (tree, *_session, *region_handler)));
119                 handlers.push_back (HandlerPtr(new AudioTrackImportHandler (tree, *_session, *pl_handler)));
120                 handlers.push_back (HandlerPtr(new LocationImportHandler (tree, *_session)));
121                 handlers.push_back (HandlerPtr(new TempoMapImportHandler (tree, *_session)));
122                 
123                 fill_list();
124                 
125                 if (ElementImportHandler::dirty()) {
126                         // Warn user
127                         string txt = _("Some elements had errors in them. Please see the log for details");
128                         MessageDialog msg (txt, false, MESSAGE_WARNING, BUTTONS_OK, true);
129                         msg.run();
130                 }
131         }
132 }
133
134 void
135 SessionImportDialog::fill_list ()
136 {
137         session_tree->clear();
138
139         // Loop through element types
140         for (HandlerList::iterator handler = handlers.begin(); handler != handlers.end(); ++handler) {
141                 TreeModel::iterator iter = session_tree->append();
142                 TreeModel::Row row = *iter;
143                 row[sb_cols.name] = (*handler)->get_info();
144                 row[sb_cols.queued] = false;
145                 row[sb_cols.element] = ElementPtr(); // "Null" pointer
146
147                 // Loop through elements
148                 ElementList &elements = (*handler)->elements;
149                 for (ElementList::iterator element = elements.begin(); element != elements.end(); ++element) {
150                         iter = session_tree->append(row.children());
151                         TreeModel::Row child = *iter;
152                         child[sb_cols.name] = (*element)->get_name();
153                         child[sb_cols.queued] = false;
154                         child[sb_cols.element] = *element;
155                         child[sb_cols.info] = (*element)->get_info();
156                 }
157         }
158 }
159
160 void
161 SessionImportDialog::browse ()
162 {
163         FileChooserDialog dialog(_("Import from session"), browse_action());
164         dialog.set_transient_for(*this);
165         dialog.set_filename (file_entry.get_text());
166
167         FileFilter session_filter;
168         session_filter.add_pattern ("*.ardour");
169         session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
170         dialog.add_filter (session_filter);
171         dialog.set_filter (session_filter);
172
173         dialog.add_button(Stock::CANCEL, RESPONSE_CANCEL);
174         dialog.add_button(Stock::OK, RESPONSE_OK);
175
176         int result = dialog.run();
177
178         if (result == RESPONSE_OK) {
179                 string filename = dialog.get_filename();
180
181                 if (filename.length()) {
182                         file_entry.set_text (filename);
183                         load_session (filename);
184                 }
185         }
186 }
187
188 void
189 SessionImportDialog::do_merge ()
190 {
191
192         // element types
193         TreeModel::Children types = session_browser.get_model()->children();
194         TreeModel::Children::iterator ti;
195         for (ti = types.begin(); ti != types.end(); ++ti) {
196                 // elements
197                 TreeModel::Children elements = ti->children();
198                 TreeModel::Children::iterator ei;
199                 for (ei = elements.begin(); ei != elements.end(); ++ei) {
200                         if ((*ei)[sb_cols.queued]) {
201                                 ElementPtr element = (*ei)[sb_cols.element];
202                                 element->move();
203                         }
204                 }
205         }
206
207         end_dialog();
208
209         if (ElementImportHandler::errors()) {
210                 // Warn user
211                 string txt = _("Some elements had errors in them. Please see the log for details");
212                 MessageDialog msg (txt, false, MESSAGE_WARNING, BUTTONS_OK, true);
213                 msg.run();
214         }
215 }
216
217
218 void
219 SessionImportDialog::update (string path)
220 {
221         TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
222
223         // Select all elements if element type is selected
224         if (path.size() == 1) {
225                 {
226                         // Prompt user for verification
227                         string txt = _("This will select all elements of this type!");
228                         MessageDialog msg (txt, false, MESSAGE_QUESTION, BUTTONS_OK_CANCEL, true);
229                         if (msg.run() == RESPONSE_CANCEL) {
230                                 (*cell)[sb_cols.queued] = false;
231                                 return;
232                         }
233                 }
234
235                 TreeModel::Children elements = cell->children();
236                 TreeModel::Children::iterator ei;
237                 for (ei = elements.begin(); ei != elements.end(); ++ei) {
238                         ElementPtr element = (*ei)[sb_cols.element];
239                         if (element->prepare_move()) {
240                                 (*ei)[sb_cols.queued] = true;
241                         } else {
242                                 (*cell)[sb_cols.queued] = false; // Not all are selected
243                         }
244                 }
245                 return;
246         }
247
248         ElementPtr element = (*cell)[sb_cols.element];
249         if ((*cell)[sb_cols.queued]) {
250                 if (!element->prepare_move()) {
251                         (*cell)[sb_cols.queued] = false;
252                 }
253         } else {
254                 element->cancel_move();
255         }
256 }
257
258 void
259 SessionImportDialog::show_info(const TreeModel::Path& path, TreeViewColumn*)
260 {
261         if (path.size() == 1) {
262                 return;
263         }
264
265         TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
266         string info = (*cell)[sb_cols.info];
267
268         MessageDialog msg (info, false, MESSAGE_INFO, BUTTONS_OK, true);
269         msg.run();
270 }
271
272 void
273 SessionImportDialog::end_dialog ()
274 {
275         hide_all();
276
277         set_modal (false);
278         ok_button->set_sensitive(true);
279 }
280
281 std::pair<bool, string>
282 SessionImportDialog::open_rename_dialog (string text, string name)
283 {
284         ArdourPrompter prompter(true);
285         string new_name;
286
287         prompter.set_name ("Prompter");
288         prompter.add_button (Stock::SAVE, RESPONSE_ACCEPT);
289         prompter.set_prompt (text);
290         prompter.set_initial_text (name);
291
292         if (prompter.run() == RESPONSE_ACCEPT) {
293                 prompter.get_result (new_name);
294                 if (new_name.length()) {
295                         name = new_name;
296                 }
297                 return std::make_pair (true, new_name);
298         }
299         return std::make_pair (false, new_name);
300 }
301
302 bool
303 SessionImportDialog::open_prompt_dialog (string text)
304 {
305         MessageDialog msg (text, false, MESSAGE_QUESTION, BUTTONS_OK_CANCEL, true);
306         if (msg.run() == RESPONSE_OK) {
307                 return true;
308         }
309         return false;
310 }