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