ardour
undo.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2001 Brett Viren & 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  $Id$
19 */
20 
21 #include <string>
22 #include <sstream>
23 #include <time.h>
24 
25 #include "pbd/undo.h"
26 #include "pbd/xml++.h"
27 
28 #include <sigc++/bind.h>
29 
30 using namespace std;
31 using namespace sigc;
32 
34  : _clearing(false)
35 {
36  gettimeofday (&_timestamp, 0);
37 }
38 
40  : Command(rhs._name)
41  , _clearing(false)
42 {
43  _timestamp = rhs._timestamp;
44  clear ();
45  actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end());
46 }
47 
49 {
50  drop_references ();
51  clear ();
52 }
53 
54 void
56 {
57  if (ut->clearing()) {
58  return;
59  }
60 
61  ut->remove_command (c);
62 
63  if (ut->empty()) {
64  delete ut;
65  }
66 }
67 
70 {
71  if (this == &rhs) return *this;
72  _name = rhs._name;
73  clear ();
74  actions.insert(actions.end(),rhs.actions.begin(),rhs.actions.end());
75  return *this;
76 }
77 
78 void
80 {
81  /* catch death of command (e.g. caused by death of object to
82  which it refers. command_death() is a normal static function
83  so there is no need to manage this connection.
84  */
85 
86  cmd->DropReferences.connect_same_thread (*this, boost::bind (&command_death, this, cmd));
87  actions.push_back (cmd);
88 }
89 
90 void
92 {
93  actions.remove (action);
94 }
95 
96 bool
98 {
99  return actions.empty();
100 }
101 
102 void
104 {
105  _clearing = true;
106  for (list<Command*>::iterator i = actions.begin(); i != actions.end(); ++i) {
107  delete *i;
108  }
109  actions.clear ();
110  _clearing = false;
111 }
112 
113 void
115 {
116  for (list<Command*>::iterator i = actions.begin(); i != actions.end(); ++i) {
117  (*(*i))();
118  }
119 }
120 
121 void
123 {
124  for (list<Command*>::reverse_iterator i = actions.rbegin(); i != actions.rend(); ++i) {
125  (*i)->undo();
126  }
127 }
128 
129 void
131 {
132  (*this)();
133 }
134 
136 {
137  XMLNode *node = new XMLNode ("UndoTransaction");
138  stringstream ss;
139  ss << _timestamp.tv_sec;
140  node->add_property("tv_sec", ss.str());
141  ss.str("");
142  ss << _timestamp.tv_usec;
143  node->add_property("tv_usec", ss.str());
144  node->add_property("name", _name);
145 
146  list<Command*>::iterator it;
147  for (it=actions.begin(); it!=actions.end(); it++)
148  node->add_child_nocopy((*it)->get_state());
149 
150  return *node;
151 }
152 
154 public:
156  : _history (uh) {
158  }
161  }
162 
163 private:
165 };
166 
168 {
169  _clearing = false;
170  _depth = 0;
171 }
172 
173 void
175 {
176  UndoTransaction* ut;
177  uint32_t current_depth = UndoList.size();
178 
179  _depth = d;
180 
181  if (d > current_depth) {
182  /* not even transactions to meet request */
183  return;
184  }
185 
186  if (_depth > 0) {
187 
188  uint32_t cnt = current_depth - d;
189 
190  while (cnt--) {
191  ut = UndoList.front();
192  UndoList.pop_front ();
193  delete ut;
194  }
195  }
196 }
197 
198 void
200 {
201  uint32_t current_depth = UndoList.size();
202 
203  ut->DropReferences.connect_same_thread (*this, boost::bind (&UndoHistory::remove, this, ut));
204 
205  /* if the current undo history is larger than or equal to the currently
206  requested depth, then pop off at least 1 element to make space
207  at the back for new one.
208  */
209 
210  if ((_depth > 0) && current_depth && (current_depth >= _depth)) {
211 
212  uint32_t cnt = 1 + (current_depth - _depth);
213 
214  while (cnt--) {
215  UndoTransaction* ut;
216  ut = UndoList.front ();
217  UndoList.pop_front ();
218  delete ut;
219  }
220  }
221 
222  UndoList.push_back (ut);
223  /* Adding a transacrion makes the redo list meaningless. */
224  _clearing = true;
225  for (std::list<UndoTransaction*>::iterator i = RedoList.begin(); i != RedoList.end(); ++i) {
226  delete *i;
227  }
228  RedoList.clear ();
229  _clearing = false;
230 
231  /* we are now owners of the transaction and must delete it when finished with it */
232 
233  Changed (); /* EMIT SIGNAL */
234 }
235 
236 void
238 {
239  if (_clearing) {
240  return;
241  }
242 
243  UndoList.remove (ut);
244  RedoList.remove (ut);
245 
246  Changed (); /* EMIT SIGNAL */
247 }
248 
252 void
253 UndoHistory::undo (unsigned int n)
254 {
255  if (n == 0) {
256  return;
257  }
258 
259  {
260  UndoRedoSignaller exception_safe_signaller (*this);
261 
262  while (n--) {
263  if (UndoList.size() == 0) {
264  return;
265  }
266  UndoTransaction* ut = UndoList.back ();
267  UndoList.pop_back ();
268  ut->undo ();
269  RedoList.push_back (ut);
270  }
271  }
272 
273  Changed (); /* EMIT SIGNAL */
274 }
275 
276 void
277 UndoHistory::redo (unsigned int n)
278 {
279  if (n == 0) {
280  return;
281  }
282 
283  {
284  UndoRedoSignaller exception_safe_signaller (*this);
285 
286  while (n--) {
287  if (RedoList.size() == 0) {
288  return;
289  }
290  UndoTransaction* ut = RedoList.back ();
291  RedoList.pop_back ();
292  ut->redo ();
293  UndoList.push_back (ut);
294  }
295  }
296 
297  Changed (); /* EMIT SIGNAL */
298 }
299 
300 void
302 {
303  _clearing = true;
304  for (std::list<UndoTransaction*>::iterator i = RedoList.begin(); i != RedoList.end(); ++i) {
305  delete *i;
306  }
307  RedoList.clear ();
308  _clearing = false;
309 
310  Changed (); /* EMIT SIGNAL */
311 
312 }
313 
314 void
316 {
317  _clearing = true;
318  for (std::list<UndoTransaction*>::iterator i = UndoList.begin(); i != UndoList.end(); ++i) {
319  delete *i;
320  }
321  UndoList.clear ();
322  _clearing = false;
323 
324  Changed (); /* EMIT SIGNAL */
325 }
326 
327 void
329 {
330  clear_undo ();
331  clear_redo ();
332 
333  Changed (); /* EMIT SIGNAL */
334 }
335 
336 XMLNode&
337 UndoHistory::get_state (int32_t depth)
338 {
339  XMLNode *node = new XMLNode ("UndoHistory");
340 
341  if (depth == 0) {
342 
343  return (*node);
344 
345  } else if (depth < 0) {
346 
347  /* everything */
348 
349  for (list<UndoTransaction*>::iterator it = UndoList.begin(); it != UndoList.end(); ++it) {
350  node->add_child_nocopy((*it)->get_state());
351  }
352 
353  } else {
354 
355  /* just the last "depth" transactions */
356 
357  list<UndoTransaction*> in_order;
358 
359  for (list<UndoTransaction*>::reverse_iterator it = UndoList.rbegin(); it != UndoList.rend() && depth; ++it, depth--) {
360  in_order.push_front (*it);
361  }
362 
363  for (list<UndoTransaction*>::iterator it = in_order.begin(); it != in_order.end(); it++) {
364  node->add_child_nocopy((*it)->get_state());
365  }
366  }
367 
368  return *node;
369 }
370 
371 
void redo(unsigned int n)
Definition: undo.cc:277
std::list< Command * > actions
Definition: undo.h:69
void undo(unsigned int n)
Definition: undo.cc:253
void remove(UndoTransaction *)
Definition: undo.cc:237
PBD::Signal0< void > Changed
Definition: undo.h:111
void clear_redo()
Definition: undo.cc:301
PBD::Signal0< void > DropReferences
Definition: destructible.h:34
uint32_t _depth
Definition: undo.h:117
UndoHistory()
Definition: undo.cc:167
void command_death(UndoTransaction *ut, Command *c)
Definition: undo.cc:55
void redo()
Definition: undo.cc:130
Definition: Beats.hpp:239
UndoTransaction & operator=(const UndoTransaction &)
Definition: undo.cc:69
bool empty() const
Definition: undo.cc:97
void clear_undo()
Definition: undo.cc:315
bool _clearing
Definition: undo.h:116
bool clearing() const
Definition: undo.h:49
void undo()
Definition: undo.cc:122
PBD::Signal0< void > EndUndoRedo
Definition: undo.h:113
XMLNode & get_state(int32_t depth=0)
Definition: undo.cc:337
void add(UndoTransaction *ut)
Definition: undo.cc:199
PBD::Signal0< void > BeginUndoRedo
Definition: undo.h:112
void set_depth(uint32_t)
Definition: undo.cc:174
std::list< UndoTransaction * > UndoList
Definition: undo.h:118
void remove_command(Command *const)
Definition: undo.cc:91
void add_command(Command *const)
Definition: undo.cc:79
std::string _name
Definition: command.h:55
void clear()
Definition: undo.cc:328
void clear()
Definition: undo.cc:103
void drop_references()
Definition: destructible.h:36
~UndoTransaction()
Definition: undo.cc:48
XMLProperty * add_property(const char *name, const std::string &value)
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
bool _clearing
Definition: undo.h:71
Definition: xml++.h:95
struct timeval _timestamp
Definition: undo.h:70
friend void command_death(UndoTransaction *, Command *)
Definition: undo.cc:55
void operator()()
Definition: undo.cc:114
UndoRedoSignaller(UndoHistory &uh)
Definition: undo.cc:155
std::list< UndoTransaction * > RedoList
Definition: undo.h:119
UndoHistory & _history
Definition: undo.cc:164
~UndoRedoSignaller()
Definition: undo.cc:159
XMLNode & get_state()
Definition: undo.cc:135
UndoTransaction()
Definition: undo.cc:33