PluginInfo::type added to copy constructor. But why is the copy constructor defined...
[ardour.git] / libs / ardour / session_command.cc
1 /*
2     Copyright (C) 2000-2007 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <ardour/session.h>
21 #include <ardour/route.h>
22 #include <pbd/memento_command.h>
23 #include <ardour/diskstream.h>
24 #include <ardour/playlist.h>
25 #include <ardour/audioplaylist.h>
26 #include <ardour/audio_track.h>
27 #include <ardour/tempo.h>
28 #include <ardour/audiosource.h>
29 #include <ardour/audioregion.h>
30 #include <pbd/error.h>
31 #include <pbd/id.h>
32 #include <pbd/statefuldestructible.h>
33 #include <pbd/failed_constructor.h>
34
35 using namespace PBD;
36 using namespace ARDOUR;
37
38 #include "i18n.h"
39
40 void Session::register_with_memento_command_factory(PBD::ID id, PBD::StatefulThingWithGoingAway *ptr)
41 {
42     registry[id] = ptr;
43 }
44     
45 Command *
46 Session::memento_command_factory(XMLNode *n)
47 {
48     PBD::ID id;
49     XMLNode *before = 0, *after = 0;
50     XMLNode *child = 0;
51
52     /* get id */
53     id = PBD::ID(n->property("obj_id")->value());
54
55     /* get before/after */
56
57     if (n->name() == "MementoCommand") {
58             before = new XMLNode(*n->children().front());
59             after = new XMLNode(*n->children().back());
60             child = before;
61     } else if (n->name() == "MementoUndoCommand") {
62             before = new XMLNode(*n->children().front());
63             child = before;
64     } else if (n->name() == "MementoRedoCommand") {
65             after = new XMLNode(*n->children().front());
66             child = after;
67     } else if (n->name() == "PlaylistCommand") {
68             before = new XMLNode(*n->children().front());
69             after = new XMLNode(*n->children().back());
70             child = before;
71     } 
72                     
73     if (!child)
74     {
75         error << _("Tried to reconstitute a MementoCommand with no contents, failing. id=") << id.to_s() << endmsg;
76         return 0;
77     }
78
79     /* create command */
80     string obj_T = n->property ("type_name")->value();
81     if (obj_T == typeid (AudioRegion).name() || obj_T == typeid (Region).name()) {
82             if (audio_regions.count(id)) {
83                     return new MementoCommand<AudioRegion>(*audio_regions[id], before, after);
84             }
85     } else if (obj_T == typeid (AudioSource).name()) {
86             if (audio_sources.count(id))
87                     return new MementoCommand<AudioSource>(*audio_sources[id], before, after);
88     } else if (obj_T == typeid (Location).name()) {
89             Location* loc = _locations.get_location_by_id(id);
90             if (loc) {
91                     return new MementoCommand<Location>(*loc, before, after);
92             }
93     } else if (obj_T == typeid (Locations).name()) {
94             return new MementoCommand<Locations>(_locations, before, after);
95     } else if (obj_T == typeid (TempoMap).name()) {
96             return new MementoCommand<TempoMap>(*_tempo_map, before, after);
97     } else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name()) {
98             if (boost::shared_ptr<Playlist> pl = playlist_by_name(child->property("name")->value())) {
99                     return new MementoCommand<Playlist>(*(pl.get()), before, after);
100             }
101     } else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) { 
102             return new MementoCommand<Route>(*route_by_id(id), before, after);
103     } else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) {
104             if (automation_lists.count(id))
105                     return new MementoCommand<AutomationList>(*automation_lists[id], before, after);
106     } else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits here
107             return new MementoCommand<PBD::StatefulThingWithGoingAway>(*registry[id], before, after);
108     }
109
110     /* we failed */
111     error << string_compose (_("could not reconstitute MementoCommand from XMLNode. object type = %1 id = %2"), obj_T, id.to_s()) << endmsg;
112
113     return 0 ;
114 }
115
116 Command *
117 Session::global_state_command_factory (const XMLNode& node)
118 {
119         const XMLProperty* prop;
120         Command* command = 0;
121
122         if ((prop = node.property ("type")) == 0) {
123                 error << _("GlobalRouteStateCommand has no \"type\" node, ignoring") << endmsg;
124                 return 0;
125         }
126         
127         try {
128
129                 if (prop->value() == "solo") {
130                         command = new GlobalSoloStateCommand (*this, node);
131                 } else if (prop->value() == "mute") {
132                         command = new GlobalMuteStateCommand (*this, node);
133                 } else if (prop->value() == "rec-enable") {
134                         command = new GlobalRecordEnableStateCommand (*this, node);
135                 } else if (prop->value() == "metering") {
136                         command = new GlobalMeteringStateCommand (*this, node);
137                 } else {
138                         error << string_compose (_("unknown type of GlobalRouteStateCommand (%1), ignored"), prop->value()) << endmsg;
139                 }
140         }
141
142         catch (failed_constructor& err) {
143                 return 0;
144         }
145
146         return command;
147 }
148
149 Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, void* p)
150         : sess (s), src (p)
151 {
152 }
153
154 Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, const XMLNode& node)
155         : sess (s), src (this)
156 {
157         if (set_state (node)) {
158                 throw failed_constructor ();
159         }
160 }
161
162 int
163 Session::GlobalRouteStateCommand::set_state (const XMLNode& node)
164 {
165         GlobalRouteBooleanState states;
166         XMLNodeList nlist;
167         const XMLProperty* prop;
168         XMLNode* child;
169         XMLNodeConstIterator niter;
170         int loop;
171
172         before.clear ();
173         after.clear ();
174         
175         for (loop = 0; loop < 2; ++loop) {
176
177                 const char *str;
178
179                 if (loop) {
180                         str = "after";
181                 } else {
182                         str = "before";
183                 }
184                 
185                 if ((child = node.child (str)) == 0) {
186                         warning << string_compose (_("global route state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
187                         return -1;
188                 }
189
190                 nlist = child->children();
191
192                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
193                         
194                         RouteBooleanState rbs;
195                         boost::shared_ptr<Route> route;
196                         ID id;
197                         
198                         prop = (*niter)->property ("id");
199                         id = prop->value ();
200                         
201                         if ((route = sess.route_by_id (id)) == 0) {
202                                 warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
203                                 continue;
204                         }
205                         
206                         rbs.first = boost::weak_ptr<Route> (route);
207                         
208                         prop = (*niter)->property ("yn");
209                         rbs.second = (prop->value() == "1");
210                         
211                         if (loop) {
212                                 after.push_back (rbs);
213                         } else {
214                                 before.push_back (rbs);
215                         }
216                 }
217         }
218
219         return 0;
220 }
221
222 XMLNode&
223 Session::GlobalRouteStateCommand::get_state ()
224 {
225         XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
226         XMLNode* nbefore = new XMLNode (X_("before"));
227         XMLNode* nafter = new XMLNode (X_("after"));
228
229         for (Session::GlobalRouteBooleanState::iterator x = before.begin(); x != before.end(); ++x) {
230                 XMLNode* child = new XMLNode ("s");
231                 boost::shared_ptr<Route> r = x->first.lock();
232
233                 if (r) {
234                         child->add_property (X_("id"), r->id().to_s());
235                         child->add_property (X_("yn"), (x->second ? "1" : "0"));
236                         nbefore->add_child_nocopy (*child);
237                 }
238         }
239
240         for (Session::GlobalRouteBooleanState::iterator x = after.begin(); x != after.end(); ++x) {
241                 XMLNode* child = new XMLNode ("s");
242                 boost::shared_ptr<Route> r = x->first.lock();
243
244                 if (r) {
245                         child->add_property (X_("id"), r->id().to_s());
246                         child->add_property (X_("yn"), (x->second ? "1" : "0"));
247                         nafter->add_child_nocopy (*child);
248                 }
249         }
250
251         node->add_child_nocopy (*nbefore);
252         node->add_child_nocopy (*nafter);
253
254         return *node;
255 }
256
257 // solo
258
259 Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src)
260         : GlobalRouteStateCommand (sess, src)
261 {
262     after = before = sess.get_global_route_boolean(&Route::soloed);
263 }
264
265 Session::GlobalSoloStateCommand::GlobalSoloStateCommand (Session& sess, const XMLNode& node)
266         : Session::GlobalRouteStateCommand (sess, node)
267 {
268 }
269
270 void 
271 Session::GlobalSoloStateCommand::mark()
272 {
273     after = sess.get_global_route_boolean(&Route::soloed);
274 }
275
276 void 
277 Session::GlobalSoloStateCommand::operator()()
278 {
279     sess.set_global_solo(after, src);
280 }
281
282 void 
283 Session::GlobalSoloStateCommand::undo()
284 {
285     sess.set_global_solo(before, src);
286 }
287
288 XMLNode&
289 Session::GlobalSoloStateCommand::get_state()
290 {
291         XMLNode& node = GlobalRouteStateCommand::get_state();
292         node.add_property ("type", "solo");
293         return node;
294 }
295
296 // mute
297 Session::GlobalMuteStateCommand::GlobalMuteStateCommand(Session &sess, void *src)
298         : GlobalRouteStateCommand (sess, src)
299 {
300     after = before = sess.get_global_route_boolean(&Route::muted);
301 }
302
303 Session::GlobalMuteStateCommand::GlobalMuteStateCommand (Session& sess, const XMLNode& node)
304         : Session::GlobalRouteStateCommand (sess, node)
305 {
306 }
307
308 void 
309 Session::GlobalMuteStateCommand::mark()
310 {
311         after = sess.get_global_route_boolean(&Route::muted);
312 }
313
314 void 
315 Session::GlobalMuteStateCommand::operator()()
316 {
317         sess.set_global_mute(after, src);
318 }
319
320 void 
321 Session::GlobalMuteStateCommand::undo()
322 {
323         sess.set_global_mute(before, src);
324 }
325
326 XMLNode&
327 Session::GlobalMuteStateCommand::get_state()
328 {
329         XMLNode& node = GlobalRouteStateCommand::get_state();
330         node.add_property ("type", "mute");
331         return node;
332 }
333
334 // record enable
335 Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand(Session &sess, void *src) 
336         : GlobalRouteStateCommand (sess, src)
337 {
338         after = before = sess.get_global_route_boolean(&Route::record_enabled);
339 }
340
341 Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand (Session& sess, const XMLNode& node)
342         : Session::GlobalRouteStateCommand (sess, node)
343 {
344 }
345
346 void 
347 Session::GlobalRecordEnableStateCommand::mark()
348 {
349         after = sess.get_global_route_boolean(&Route::record_enabled);
350 }
351
352 void 
353 Session::GlobalRecordEnableStateCommand::operator()()
354 {
355         sess.set_global_record_enable(after, src);
356 }
357
358 void 
359 Session::GlobalRecordEnableStateCommand::undo()
360 {
361         sess.set_global_record_enable(before, src);
362 }
363
364 XMLNode& 
365 Session::GlobalRecordEnableStateCommand::get_state()
366 {
367         XMLNode& node = GlobalRouteStateCommand::get_state();
368         node.add_property ("type", "rec-enable");
369         return node;
370 }
371
372 // metering
373 Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session &s, void *p) 
374         : sess (s), src (p)
375 {
376         after = before = sess.get_global_route_metering();
377 }
378
379 Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand (Session& s, const XMLNode& node)
380         : sess (s), src (this)
381 {
382         if (set_state (node)) {
383                 throw failed_constructor();
384         }
385 }
386
387 void 
388 Session::GlobalMeteringStateCommand::mark()
389 {
390         after = sess.get_global_route_metering();
391 }
392
393 void 
394 Session::GlobalMeteringStateCommand::operator()()
395 {
396         sess.set_global_route_metering(after, src);
397 }
398
399 void 
400 Session::GlobalMeteringStateCommand::undo()
401 {
402         sess.set_global_route_metering(before, src);
403 }
404
405 XMLNode&
406 Session::GlobalMeteringStateCommand::get_state()
407 {
408         XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
409         XMLNode* nbefore = new XMLNode (X_("before"));
410         XMLNode* nafter = new XMLNode (X_("after"));
411
412         for (Session::GlobalRouteMeterState::iterator x = before.begin(); x != before.end(); ++x) {
413                 XMLNode* child = new XMLNode ("s");
414                 boost::shared_ptr<Route> r = x->first.lock();
415
416                 if (r) {
417                         child->add_property (X_("id"), r->id().to_s());
418
419                         const char* meterstr = 0;
420                         
421                         switch (x->second) {
422                         case MeterInput:
423                                 meterstr = X_("input");
424                                 break;
425                         case MeterPreFader:
426                                 meterstr = X_("pre");
427                                 break;
428                         case MeterPostFader:
429                                 meterstr = X_("post");
430                                 break;
431                         default:
432                                 fatal << string_compose (_("programming error: %1") , "no meter state in Session::GlobalMeteringStateCommand::get_state") << endmsg;
433                         }
434
435                         child->add_property (X_("meter"), meterstr);
436                         nbefore->add_child_nocopy (*child);
437                 }
438         }
439
440         for (Session::GlobalRouteMeterState::iterator x = after.begin(); x != after.end(); ++x) {
441                 XMLNode* child = new XMLNode ("s");
442                 boost::shared_ptr<Route> r = x->first.lock();
443
444                 if (r) {
445                         child->add_property (X_("id"), r->id().to_s());
446
447                         const char* meterstr;
448                         
449                         switch (x->second) {
450                         case MeterInput:
451                                 meterstr = X_("input");
452                                 break;
453                         case MeterPreFader:
454                                 meterstr = X_("pre");
455                                 break;
456                         case MeterPostFader:
457                                 meterstr = X_("post");
458                                 break;
459                         default: meterstr = "";
460                         }
461
462                         child->add_property (X_("meter"), meterstr);
463                         nafter->add_child_nocopy (*child);
464                 }
465         }
466
467         node->add_child_nocopy (*nbefore);
468         node->add_child_nocopy (*nafter);
469
470         node->add_property ("type", "metering");
471
472         return *node;
473 }
474
475 int
476 Session::GlobalMeteringStateCommand::set_state (const XMLNode& node)
477 {
478         GlobalRouteBooleanState states;
479         XMLNodeList nlist;
480         const XMLProperty* prop;
481         XMLNode* child;
482         XMLNodeConstIterator niter;
483         int loop;
484
485         before.clear ();
486         after.clear ();
487         
488         for (loop = 0; loop < 2; ++loop) {
489
490                 const char *str;
491
492                 if (loop) {
493                         str = "after";
494                 } else {
495                         str = "before";
496                 }
497                 
498                 if ((child = node.child (str)) == 0) {
499                         warning << string_compose (_("global route meter state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
500                         return -1;
501                 }
502
503                 nlist = child->children();
504
505                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
506                         
507                         RouteMeterState rms;
508                         boost::shared_ptr<Route> route;
509                         ID id;
510                         
511                         prop = (*niter)->property ("id");
512                         id = prop->value ();
513                         
514                         if ((route = sess.route_by_id (id)) == 0) {
515                                 warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
516                                 continue;
517                         }
518                         
519                         rms.first = boost::weak_ptr<Route> (route);
520                         
521                         prop = (*niter)->property ("meter");
522
523                         if (prop->value() == X_("pre")) {
524                                 rms.second = MeterPreFader;
525                         } else if (prop->value() == X_("post")) {
526                                 rms.second = MeterPostFader;
527                         } else {
528                                 rms.second = MeterInput;
529                         }
530                         
531                         if (loop) {
532                                 after.push_back (rms);
533                         } else {
534                                 before.push_back (rms);
535                         }
536                 }
537         }
538
539         return 0;
540 }