* Clean up (fix?) ExportStatus signal handling
[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 #include <gtkmm2ext/window_title.h>
33
34 #include "prompter.h"
35 #include "i18n.h"
36
37 using namespace ARDOUR;
38
39 SessionImportDialog::SessionImportDialog (ARDOUR::Session & target) :
40   ArdourDialog (_("Import from session")),
41   target (target),
42   file_browse_button (_("Browse"))
43 {
44         // File entry
45         file_entry.set_name ("ImportFileNameEntry");
46         file_entry.set_text ("/");
47         Gtkmm2ext::set_size_request_to_display_given_text (file_entry, X_("Kg/quite/a/reasonable/size/for/files/i/think"), 5, 8);
48         
49         file_browse_button.set_name ("EditorGTKButton");
50         file_browse_button.signal_clicked().connect (mem_fun(*this, &SessionImportDialog::browse));
51         
52         file_hbox.set_spacing (5);
53         file_hbox.set_border_width (5);
54         file_hbox.pack_start (file_entry, true, true);
55         file_hbox.pack_start (file_browse_button, false, false);
56         
57         file_frame.add (file_hbox);
58         file_frame.set_border_width (5);
59         file_frame.set_name ("ImportFrom");
60         file_frame.set_label (_("Import from Session"));
61         
62         get_vbox()->pack_start (file_frame, false, false);
63
64         // Session browser
65         session_tree = Gtk::TreeStore::create (sb_cols);
66         session_browser.set_model (session_tree);
67
68         session_browser.set_name ("SessionBrowser");
69         session_browser.append_column (_("Elements"), sb_cols.name);
70         session_browser.append_column_editable (_("Import"), sb_cols.queued);
71         session_browser.get_column(0)->set_min_width (180);
72         session_browser.get_column(1)->set_min_width (40);
73         session_browser.get_column(1)->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
74         
75         session_scroll.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
76         session_scroll.add (session_browser);
77         session_scroll.set_size_request (220, 400);
78         
79         // Connect signals
80         Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *> (session_browser.get_column_cell_renderer (1));
81         toggle->signal_toggled().connect(mem_fun (*this, &SessionImportDialog::update));
82         session_browser.signal_row_activated().connect(mem_fun (*this, &SessionImportDialog::show_info));
83         
84         get_vbox()->pack_start (session_scroll, false, false);
85         
86         // Tooltips
87         session_browser.set_has_tooltip();
88         session_browser.signal_query_tooltip().connect(mem_fun(*this, &SessionImportDialog::query_tooltip));
89         
90         // Buttons
91         cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
92         cancel_button->signal_clicked().connect (mem_fun (*this, &SessionImportDialog::end_dialog));
93         ok_button = add_button (_("Import"), Gtk::RESPONSE_ACCEPT);
94         ok_button->signal_clicked().connect (mem_fun (*this, &SessionImportDialog::do_merge));
95         
96         // prompt signals
97         ElementImporter::Rename.connect (mem_fun (*this, &SessionImportDialog::open_rename_dialog));
98         ElementImporter::Prompt.connect (mem_fun (*this, &SessionImportDialog::open_prompt_dialog));
99         
100         // Finalize
101         show_all();
102 }
103
104 void
105 SessionImportDialog::load_session (const string& filename)
106 {
107         tree.read (filename);
108         AudioRegionImportHandler *region_handler;
109         
110         region_handler = new AudioRegionImportHandler (tree, target);
111         handlers.push_back (HandlerPtr(region_handler));
112         handlers.push_back (HandlerPtr(new AudioPlaylistImportHandler (tree, target, *region_handler)));
113         handlers.push_back (HandlerPtr(new UnusedAudioPlaylistImportHandler (tree, target, *region_handler)));
114         handlers.push_back (HandlerPtr(new AudioTrackImportHandler (tree, target)));
115         handlers.push_back (HandlerPtr(new LocationImportHandler (tree, target)));
116         handlers.push_back (HandlerPtr(new TempoMapImportHandler (tree, target)));
117         
118         fill_list();
119         
120         if (ElementImportHandler::dirty()) {
121                 // Warn user
122                 string txt = _("Some elements had errors in them. Please see the log for details");
123                 Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
124                 msg.run();
125         }
126 }
127
128 void
129 SessionImportDialog::fill_list ()
130 {
131         session_tree->clear();
132         
133         // Loop through element types
134         for (HandlerList::iterator handler = handlers.begin(); handler != handlers.end(); ++handler) {
135                 Gtk::TreeModel::iterator iter = session_tree->append();
136                 Gtk::TreeModel::Row row = *iter;
137                 row[sb_cols.name] = (*handler)->get_info();
138                 row[sb_cols.queued] = false;
139                 row[sb_cols.element] = ElementPtr(); // "Null" pointer
140                 
141                 // Loop through elements
142                 ElementList &elements = (*handler)->elements;
143                 for (ElementList::iterator element = elements.begin(); element != elements.end(); ++element) {
144                         iter = session_tree->append(row.children());
145                         Gtk::TreeModel::Row child = *iter;
146                         child[sb_cols.name] = (*element)->get_name();
147                         child[sb_cols.queued] = false;
148                         child[sb_cols.element] = *element;
149                 }
150         }
151 }
152
153 void
154 SessionImportDialog::browse ()
155 {
156         Gtk::FileChooserDialog dialog(_("Import from session"), browse_action());
157         dialog.set_transient_for(*this);
158         dialog.set_filename (file_entry.get_text());
159
160         dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
161         dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
162   
163         int result = dialog.run();
164
165         if (result == Gtk::RESPONSE_OK) {
166                 string filename = dialog.get_filename();
167         
168                 if (filename.length()) {
169                         file_entry.set_text (filename);
170                         load_session (filename);
171                 }
172         }
173 }
174
175 void
176 SessionImportDialog::do_merge ()
177 {
178         
179         // element types
180         Gtk::TreeModel::Children types = session_browser.get_model()->children();
181         Gtk::TreeModel::Children::iterator ti;
182         for (ti = types.begin(); ti != types.end(); ++ti) {
183                 // elements
184                 Gtk::TreeModel::Children elements = ti->children();
185                 Gtk::TreeModel::Children::iterator ei;
186                 for (ei = elements.begin(); ei != elements.end(); ++ei) {
187                         if ((*ei)[sb_cols.queued]) {
188                                 ElementPtr element = (*ei)[sb_cols.element];
189                                 element->move();
190                         }
191                 }
192         }
193         
194         end_dialog();
195         
196         if (ElementImportHandler::errors()) {
197                 // Warn user
198                 string txt = _("Some elements had errors in them. Please see the log for details");
199                 Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
200                 msg.run();
201         }
202 }
203
204
205 void
206 SessionImportDialog::update (string path)
207 {
208         Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
209         
210         // Select all elements if element type is selected
211         if (path.size() == 1) {
212                 {
213                         // Prompt user for verification
214                         string txt = _("This will select all elements of this type!");
215                         Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
216                         if (msg.run() == Gtk::RESPONSE_CANCEL) {
217                                 (*cell)[sb_cols.queued] = false;
218                                 return;
219                         }
220                 }
221                 
222                 Gtk::TreeModel::Children elements = cell->children();
223                 Gtk::TreeModel::Children::iterator ei;
224                 for (ei = elements.begin(); ei != elements.end(); ++ei) {
225                         ElementPtr element = (*ei)[sb_cols.element];
226                         if (element->prepare_move()) {
227                                 (*ei)[sb_cols.queued] = true;
228                         } else {
229                                 (*cell)[sb_cols.queued] = false; // Not all are selected
230                         }
231                 }
232                 return;
233         }
234         
235         ElementPtr element = (*cell)[sb_cols.element];
236         if ((*cell)[sb_cols.queued]) {
237                 if (!element->prepare_move()) {
238                         (*cell)[sb_cols.queued] = false;
239                 }
240         } else {
241                 element->cancel_move();
242         }
243 }
244
245 void
246 SessionImportDialog::show_info(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column)
247 {
248         if (path.size() == 1) {
249                 return;
250         }
251         
252         Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
253         ElementPtr element = (*cell)[sb_cols.element];
254         string info = element->get_info();
255         
256         Gtk::MessageDialog msg (info, false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, true);
257         msg.run();
258 }
259
260 bool
261 SessionImportDialog::query_tooltip(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip)
262 {
263         Gtk::TreeModel::Path path;
264         Gtk::TreeViewColumn* column;
265         int cell_x, cell_y;
266         
267         // Get element
268         session_browser.get_path_at_pos (x, y, path, column, cell_x, cell_y);
269         if (path.gobj() == 0) {
270                 return false;
271         }
272         Gtk::TreeModel::iterator row = session_browser.get_model()->get_iter (path);
273         //--row; // FIXME Strange offset in rows, if someone figures this out, please fix
274         ElementPtr element = (*row)[sb_cols.element];
275         if (element.get() == 0) {
276                 return false;
277         }
278         
279         // Prepare tooltip
280         tooltip->set_text(element->get_info());
281         
282         return true;
283 }
284
285 void
286 SessionImportDialog::end_dialog ()
287 {
288         hide_all();
289
290         set_modal (false);
291         ok_button->set_sensitive(true);
292 }
293
294 std::pair<bool, string>
295 SessionImportDialog::open_rename_dialog (string text, string name)
296 {
297         ArdourPrompter prompter(true);
298         string new_name;
299
300         prompter.set_name ("Prompter");
301         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
302         prompter.set_prompt (text);
303         prompter.set_initial_text (name);
304         
305         if (prompter.run() == Gtk::RESPONSE_ACCEPT) {
306                 prompter.get_result (new_name);
307                 if (new_name.length()) {
308                         name = new_name;
309                 }
310                 return std::make_pair (true, new_name);
311         }
312         return std::make_pair (false, new_name);
313 }
314
315 bool
316 SessionImportDialog::open_prompt_dialog (string text)
317 {
318         Gtk::MessageDialog msg (text, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
319         if (msg.run() == Gtk::RESPONSE_OK) {
320                 return true;
321         }
322         return false;
323 }