fix rounding errors and bbox glitches that led to lines missing redraws, plus a few...
[ardour2.git] / gtk2_ardour / session_import_dialog.cc
blob6fdac9aa902f6ff69995749c44ed878c94ad6614
1 /*
2 Copyright (C) 2008 Paul Davis
3 Author: Sakari Bergen
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.
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.
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.
21 #include "session_import_dialog.h"
23 #include "pbd/failed_constructor.h"
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"
31 #include <gtkmm2ext/utils.h>
33 #include "gui_thread.h"
34 #include "prompter.h"
35 #include "i18n.h"
37 using namespace std;
38 using namespace ARDOUR;
40 SessionImportDialog::SessionImportDialog (ARDOUR::Session* target) :
41 ArdourDialog (_("Import From Session")),
42 file_browse_button (_("Browse"))
44 set_session (target);
46 // File entry
47 file_entry.set_name ("ImportFileNameEntry");
48 file_entry.set_text ("/");
49 Gtkmm2ext::set_size_request_to_display_given_text (file_entry, X_("Kg/quite/a/reasonable/size/for/files/i/think"), 5, 8);
51 file_browse_button.set_name ("EditorGTKButton");
52 file_browse_button.signal_clicked().connect (sigc::mem_fun(*this, &SessionImportDialog::browse));
54 file_hbox.set_spacing (5);
55 file_hbox.set_border_width (5);
56 file_hbox.pack_start (file_entry, true, true);
57 file_hbox.pack_start (file_browse_button, false, false);
59 file_frame.add (file_hbox);
60 file_frame.set_border_width (5);
61 file_frame.set_name ("ImportFrom");
62 file_frame.set_label (_("Import from Session"));
64 get_vbox()->pack_start (file_frame, false, false);
66 // Session browser
67 session_tree = Gtk::TreeStore::create (sb_cols);
68 session_browser.set_model (session_tree);
70 session_browser.set_name ("SessionBrowser");
71 session_browser.append_column (_("Elements"), sb_cols.name);
72 session_browser.append_column_editable (_("Import"), sb_cols.queued);
73 session_browser.set_tooltip_column (3);
74 session_browser.get_column(0)->set_min_width (180);
75 session_browser.get_column(1)->set_min_width (40);
76 session_browser.get_column(1)->set_sizing (Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
78 session_scroll.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
79 session_scroll.add (session_browser);
80 session_scroll.set_size_request (220, 400);
82 // Connect signals
83 Gtk::CellRendererToggle *toggle = dynamic_cast<Gtk::CellRendererToggle *> (session_browser.get_column_cell_renderer (1));
84 toggle->signal_toggled().connect(sigc::mem_fun (*this, &SessionImportDialog::update));
85 session_browser.signal_row_activated().connect(sigc::mem_fun (*this, &SessionImportDialog::show_info));
87 get_vbox()->pack_start (session_scroll, false, false);
89 // Buttons
90 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
91 cancel_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::end_dialog));
92 ok_button = add_button (_("Import"), Gtk::RESPONSE_ACCEPT);
93 ok_button->signal_clicked().connect (sigc::mem_fun (*this, &SessionImportDialog::do_merge));
95 // prompt signals XXX: problem - handlers to be in the same thread since they return values
96 ElementImporter::Rename.connect_same_thread (connections, boost::bind (&SessionImportDialog::open_rename_dialog, this, _1, _2));
97 ElementImporter::Prompt.connect_same_thread (connections, boost::bind (&SessionImportDialog::open_prompt_dialog, this, _1));
99 // Finalize
100 show_all();
103 void
104 SessionImportDialog::load_session (const string& filename)
106 if (_session) {
107 tree.read (filename);
108 boost::shared_ptr<AudioRegionImportHandler> region_handler (new AudioRegionImportHandler (tree, *_session));
109 boost::shared_ptr<AudioPlaylistImportHandler> pl_handler (new AudioPlaylistImportHandler (tree, *_session, *region_handler));
111 handlers.push_back (boost::static_pointer_cast<ElementImportHandler> (region_handler));
112 handlers.push_back (boost::static_pointer_cast<ElementImportHandler> (pl_handler));
113 handlers.push_back (HandlerPtr(new UnusedAudioPlaylistImportHandler (tree, *_session, *region_handler)));
114 handlers.push_back (HandlerPtr(new AudioTrackImportHandler (tree, *_session, *pl_handler)));
115 handlers.push_back (HandlerPtr(new LocationImportHandler (tree, *_session)));
116 handlers.push_back (HandlerPtr(new TempoMapImportHandler (tree, *_session)));
118 fill_list();
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();
129 void
130 SessionImportDialog::fill_list ()
132 session_tree->clear();
134 // Loop through element types
135 for (HandlerList::iterator handler = handlers.begin(); handler != handlers.end(); ++handler) {
136 Gtk::TreeModel::iterator iter = session_tree->append();
137 Gtk::TreeModel::Row row = *iter;
138 row[sb_cols.name] = (*handler)->get_info();
139 row[sb_cols.queued] = false;
140 row[sb_cols.element] = ElementPtr(); // "Null" pointer
142 // Loop through elements
143 ElementList &elements = (*handler)->elements;
144 for (ElementList::iterator element = elements.begin(); element != elements.end(); ++element) {
145 iter = session_tree->append(row.children());
146 Gtk::TreeModel::Row child = *iter;
147 child[sb_cols.name] = (*element)->get_name();
148 child[sb_cols.queued] = false;
149 child[sb_cols.element] = *element;
150 child[sb_cols.info] = (*element)->get_info();
155 void
156 SessionImportDialog::browse ()
158 Gtk::FileChooserDialog dialog(_("Import from session"), browse_action());
159 dialog.set_transient_for(*this);
160 dialog.set_filename (file_entry.get_text());
162 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
163 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
165 int result = dialog.run();
167 if (result == Gtk::RESPONSE_OK) {
168 string filename = dialog.get_filename();
170 if (filename.length()) {
171 file_entry.set_text (filename);
172 load_session (filename);
177 void
178 SessionImportDialog::do_merge ()
181 // element types
182 Gtk::TreeModel::Children types = session_browser.get_model()->children();
183 Gtk::TreeModel::Children::iterator ti;
184 for (ti = types.begin(); ti != types.end(); ++ti) {
185 // elements
186 Gtk::TreeModel::Children elements = ti->children();
187 Gtk::TreeModel::Children::iterator ei;
188 for (ei = elements.begin(); ei != elements.end(); ++ei) {
189 if ((*ei)[sb_cols.queued]) {
190 ElementPtr element = (*ei)[sb_cols.element];
191 element->move();
196 end_dialog();
198 if (ElementImportHandler::errors()) {
199 // Warn user
200 string txt = _("Some elements had errors in them. Please see the log for details");
201 Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
202 msg.run();
207 void
208 SessionImportDialog::update (string path)
210 Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
212 // Select all elements if element type is selected
213 if (path.size() == 1) {
215 // Prompt user for verification
216 string txt = _("This will select all elements of this type!");
217 Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
218 if (msg.run() == Gtk::RESPONSE_CANCEL) {
219 (*cell)[sb_cols.queued] = false;
220 return;
224 Gtk::TreeModel::Children elements = cell->children();
225 Gtk::TreeModel::Children::iterator ei;
226 for (ei = elements.begin(); ei != elements.end(); ++ei) {
227 ElementPtr element = (*ei)[sb_cols.element];
228 if (element->prepare_move()) {
229 (*ei)[sb_cols.queued] = true;
230 } else {
231 (*cell)[sb_cols.queued] = false; // Not all are selected
234 return;
237 ElementPtr element = (*cell)[sb_cols.element];
238 if ((*cell)[sb_cols.queued]) {
239 if (!element->prepare_move()) {
240 (*cell)[sb_cols.queued] = false;
242 } else {
243 element->cancel_move();
247 void
248 SessionImportDialog::show_info(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*)
250 if (path.size() == 1) {
251 return;
254 Gtk::TreeModel::iterator cell = session_browser.get_model()->get_iter (path);
255 string info = (*cell)[sb_cols.info];
257 Gtk::MessageDialog msg (info, false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, true);
258 msg.run();
261 void
262 SessionImportDialog::end_dialog ()
264 hide_all();
266 set_modal (false);
267 ok_button->set_sensitive(true);
270 std::pair<bool, string>
271 SessionImportDialog::open_rename_dialog (string text, string name)
273 ArdourPrompter prompter(true);
274 string new_name;
276 prompter.set_name ("Prompter");
277 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
278 prompter.set_prompt (text);
279 prompter.set_initial_text (name);
281 if (prompter.run() == Gtk::RESPONSE_ACCEPT) {
282 prompter.get_result (new_name);
283 if (new_name.length()) {
284 name = new_name;
286 return std::make_pair (true, new_name);
288 return std::make_pair (false, new_name);
291 bool
292 SessionImportDialog::open_prompt_dialog (string text)
294 Gtk::MessageDialog msg (text, false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL, true);
295 if (msg.run() == Gtk::RESPONSE_OK) {
296 return true;
298 return false;