Add Import from session -functionality
[ardour.git] / libs / ardour / location_importer.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 <ardour/location_importer.h>
22
23 #include <sstream>
24 #include <stdexcept>
25
26 #include <ardour/session.h>
27 #include <pbd/convert.h>
28 #include <pbd/failed_constructor.h>
29
30 #include "i18n.h"
31
32 using namespace PBD;
33 using namespace ARDOUR;
34
35 /**** Handler ***/
36 LocationImportHandler::LocationImportHandler (XMLTree const & source, Session & session) :
37   ElementImportHandler (source, session)
38 {
39         XMLNode const *root = source.root();
40         XMLNode const * location_node;
41         
42         if (!(location_node = root->child ("Locations"))) {
43                 throw failed_constructor();
44         }
45         
46         // Construct importable locations
47         XMLNodeList const & locations = location_node->children();
48         for (XMLNodeList::const_iterator it = locations.begin(); it != locations.end(); it++) {
49                 try {
50                         elements.push_back (ElementPtr ( new LocationImporter (source, session, *this, **it)));
51                 } catch (failed_constructor err) {
52                         _dirty = true;
53                 }
54         }
55 }
56
57 string
58 LocationImportHandler::get_info () const
59 {
60         return _("Locations");
61 }
62
63 /*** LocationImporter ***/
64 LocationImporter::LocationImporter (XMLTree const & source, Session & session, LocationImportHandler & handler, XMLNode const & node) : 
65   ElementImporter (source, session),
66   handler (handler),
67   xml_location (node),
68   location (0)
69   {
70         // Parse XML
71         bool name_ok = false;
72         XMLPropertyList props = xml_location.properties();
73         
74         for (XMLPropertyIterator it = props.begin(); it != props.end(); ++it) {
75                 string prop = (*it)->name();
76                 if (!prop.compare ("id") || !prop.compare ("flags") || !prop.compare ("locked")) {
77                         // All ok
78                 } else if (!prop.compare ("start") || !prop.compare ("end")) {
79                         // Sample rate conversion
80                         (*it)->set_value (rate_convert_samples ((*it)->value()));
81                 } else if (!prop.compare ("name")) {
82                         // rename region if necessary
83                         name = (*it)->value();
84                         name_ok = true;
85                 } else {
86                         std::cerr << string_compose (X_("LocationImporter did not recognise XML-property \"%1\""), prop) << endmsg;
87                 }
88         }
89         
90         if (!name_ok) {
91                 error << X_("LocationImporter did not find necessary XML-property \"name\"") << endmsg;
92                 throw failed_constructor();
93         }
94 }
95
96 LocationImporter::~LocationImporter ()
97 {
98         if (!queued && location) {
99                 delete location;
100         }
101 }
102
103 string
104 LocationImporter::get_info () const
105 {
106         nframes_t start, end;
107         SMPTE::Time start_time, end_time;
108         
109         // Get sample positions
110         std::istringstream iss_start (xml_location.property ("start")->value());
111         iss_start >> start;
112         std::istringstream iss_end (xml_location.property ("end")->value());
113         iss_end >> end;
114         
115         // Convert to smpte
116         session.sample_to_smpte (start, start_time, true, false);
117         session.sample_to_smpte (end, end_time, true, false);
118         
119         // return info
120         std::ostringstream oss;
121         if (start == end) {
122                 oss << _("Location: ") << smpte_to_string (start_time);
123         } else {
124                 oss << _("Range\nstart: ") << smpte_to_string (start_time) <<
125                   _("\nend: ") << smpte_to_string (end_time);
126         }
127         
128         return oss.str();
129 }
130
131 bool
132 LocationImporter::prepare_move ()
133 {
134         try {
135                 Location const original (xml_location);
136                 location = new Location (original); // Updates id
137         } catch (failed_constructor& err) {
138                 throw std::runtime_error (X_("Error in session file!"));
139                 return false;
140         }
141         
142         std::pair<bool, string> rename_pair;
143         
144         if (location->is_auto_punch()) {
145                 rename_pair = Rename (_("The location is the Punch range. It will be imported as a normal range.\nYou may rename the imported location:"), name);
146                 if (!rename_pair.first) {
147                         return false;
148                 }
149                 
150                 name = rename_pair.second;
151                 location->set_auto_punch (false, this);
152                 location->set_is_range_marker (true, this);
153         }
154         
155         if (location->is_auto_loop()) {
156                 rename_pair = Rename (_("The location is a Loop range. It will be imported as a normal range.\nYou may rename the imported location:"), name);
157                 if (!rename_pair.first) { return false; }
158                 
159                 location->set_auto_loop (false, this);
160                 location->set_is_range_marker (true, this);
161         }
162         
163         // duplicate name checking
164         Locations::LocationList const & locations(session.locations()->list());
165         for (Locations::LocationList::const_iterator it = locations.begin(); it != locations.end(); ++it) {
166                 if (!((*it)->name().compare (location->name())) || !handler.check_name (location->name())) {
167                         rename_pair = Rename (_("A location with that name already exists.\nYou may rename the imported location:"), name);
168                         if (!rename_pair.first) { return false; }
169                         name = rename_pair.second;
170                 }
171         }
172         
173         location->set_name (name);
174         queued = true;
175         return true;
176 }
177
178 void
179 LocationImporter::cancel_move ()
180 {
181         queued = false;
182         if (location) {
183                 delete location;
184                 location = 0;
185         }
186 }
187
188 void
189 LocationImporter::move ()
190 {
191         if (!queued) {
192                 return;
193         }
194         session.locations()->add (location);
195 }