1 /* === S Y N F I G ========================================================= */
2 /*! \file action_system.cpp
3 ** \brief Template File
5 ** $Id: action_system.cpp,v 1.1.1.1 2005/01/07 03:34:37 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
31 #include "action_system.h"
33 #include "canvasinterface.h"
37 /* === U S I N G =========================================================== */
41 using namespace synfigapp;
42 using namespace synfig;
44 /* === M A C R O S ========================================================= */
46 /* === G L O B A L S ======================================================= */
48 /* === P R O C E D U R E S ================================================= */
50 /* === M E T H O D S ======================================================= */
54 Action::System::System():
58 clear_redo_stack_on_new_action_=false;
61 Action::System::~System()
66 Action::System::perform_action(handle<Action::Base> action)
68 handle<UIInterface> uim(get_ui_interface());
72 if(!action->is_ready())
74 uim->error(action->get_name()+": "+_("Action is not ready."));
78 most_recent_action_=action;
80 static bool inuse=false;
82 if(inuse) return false;
89 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
91 if(canvas_specific && canvas_specific->get_canvas())
93 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas_specific->get_canvas());
94 assert(canvas_interface);
95 uim=canvas_interface->get_ui_interface();
98 handle<Action::Undoable> undoable_action=handle<Action::Undoable>::cast_dynamic(action);
100 // If we cannot undo this action, make sure
101 // that the user knows this.
106 _("This action cannot be undone! Are you sure you want to continue?"),
107 UIInterface::RESPONSE_NO
108 ) == UIInterface::RESPONSE_NO
113 // Because this action cannot be undone,
114 // we need to clear the undo stack
119 assert(undoable_action->is_active());
121 // Perform the action
122 try { action->perform(); }
123 catch(Action::Error err)
125 uim->task(action->get_name()+' '+_("Failed"));
128 if(err.get_type()!=Action::Error::TYPE_UNABLE)
130 if(err.get_desc().empty())
131 uim->error(action->get_name()+": "+strprintf("%d",err.get_type()));
133 uim->error(action->get_name()+": "+err.get_desc());
136 // If action failed for whatever reason, just return false and do
137 // not add the action onto the list
140 catch(std::exception err)
142 uim->task(action->get_name()+' '+_("Failed"));
145 uim->error(action->get_name()+": "+err.what());
147 // If action failed for whatever reason, just return false and do
148 // not add the action onto the list
153 uim->task(action->get_name()+' '+_("Failed"));
156 // If action failed for whatever reason, just return false and do
157 // not add the action onto the list
161 // Clear the redo stack
162 if(clear_redo_stack_on_new_action_)
165 if(!group_stack_.empty())
166 group_stack_.front()->inc_depth();
170 // Push this action onto the action list if we can undo it
173 // If necessary, signal the change in status of undo
174 if(undo_action_stack_.empty()) signal_undo_status_(true);
176 // Add it to the list
177 undo_action_stack_.push_front(undoable_action);
179 // Signal that a new action has been added
180 if(group_stack_.empty())
181 signal_new_action()(undoable_action);
186 uim->task(action->get_name()+' '+_("Successful"));
188 // If the action has "dirtied" the preview, signal it.
189 if(0)if(canvas_specific && canvas_specific->is_dirty())
191 Canvas::Handle canvas=canvas_specific->get_canvas();
192 if(!group_stack_.empty())
193 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
196 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
197 assert(canvas_interface);
199 //canvas_interface->signal_dirty_preview()();
203 }catch(...) { inuse=false; throw; }
209 synfigapp::Action::System::undo_(handle<UIInterface> uim)
211 handle<Action::Undoable> action(undo_action_stack().front());
212 most_recent_action_=action;
214 try { if(action->is_active()) action->undo(); }
215 catch(Action::Error err)
217 if(err.get_type()!=Action::Error::TYPE_UNABLE)
219 if(err.get_desc().empty())
220 uim->error(action->get_name()+_(" (Undo): ")+strprintf("%d",err.get_type()));
222 uim->error(action->get_name()+_(" (Undo): ")+err.get_desc());
227 catch(std::runtime_error x)
229 uim->error(x.what());
239 if(redo_action_stack_.empty()) signal_redo_status()(true);
241 redo_action_stack_.push_front(undo_action_stack_.front());
242 undo_action_stack_.pop_front();
244 if(undo_action_stack_.empty()) signal_undo_status()(false);
246 if(!group_stack_.empty())
247 group_stack_.front()->dec_depth();
255 synfigapp::Action::System::undo()
257 //! \todo This function is not exception safe!
258 static bool inuse=false;
260 // If there is nothing on the action list, there is nothing to undo
261 if(undo_action_stack().empty() || inuse)
264 handle<Action::Undoable> action=undo_action_stack().front();
265 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
267 handle<UIInterface> uim;
268 if(canvas_specific && canvas_specific->get_canvas())
270 Canvas::Handle canvas=canvas_specific->get_canvas();
271 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
272 assert(canvas_interface);
273 uim=canvas_interface->get_ui_interface();
276 uim=get_ui_interface();
282 uim->error(undo_action_stack_.front()->get_name()+": "+_("Failed to undo."));
289 // If the action has "dirtied" the preview, signal it.
290 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
292 Canvas::Handle canvas=canvas_specific->get_canvas();
293 if(!group_stack_.empty())
294 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
297 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
298 assert(canvas_interface);
300 //canvas_interface->signal_dirty_preview()();
308 Action::System::redo_(handle<UIInterface> uim)
310 handle<Action::Undoable> action(redo_action_stack().front());
311 most_recent_action_=action;
313 try { if(action->is_active()) action->perform(); }
314 catch(Action::Error err)
316 if(err.get_type()!=Action::Error::TYPE_UNABLE)
318 if(err.get_desc().empty())
319 uim->error(action->get_name()+_(" (Redo): ")+strprintf("%d",err.get_type()));
321 uim->error(action->get_name()+_(" (Redo): ")+err.get_desc());
326 catch(std::runtime_error x)
328 uim->error(x.what());
338 if(undo_action_stack_.empty()) signal_undo_status()(true);
340 undo_action_stack_.push_front(redo_action_stack_.front());
341 redo_action_stack_.pop_front();
343 if(redo_action_stack_.empty()) signal_redo_status()(false);
345 if(!group_stack_.empty())
346 group_stack_.front()->inc_depth();
354 Action::System::redo()
356 //! \todo This function is not exception safe!
357 static bool inuse=false;
359 // If there is nothing on the action list, there is nothing to undo
360 if(redo_action_stack_.empty() || inuse)
365 handle<Action::Undoable> action=redo_action_stack().front();
366 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
368 handle<UIInterface> uim;
369 if(canvas_specific && canvas_specific->get_canvas())
371 Canvas::Handle canvas=canvas_specific->get_canvas();
372 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
373 assert(canvas_interface);
374 uim=canvas_interface->get_ui_interface();
377 uim=get_ui_interface();
381 uim->error(redo_action_stack_.front()->get_name()+": "+_("Failed to redo."));
388 // If the action has "dirtied" the preview, signal it.
389 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
391 Canvas::Handle canvas=canvas_specific->get_canvas();
392 if(!group_stack_.empty())
393 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
396 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
397 assert(canvas_interface);
399 //canvas_interface->signal_dirty_preview()();
407 Action::System::inc_action_count()const
411 signal_unsaved_status_changed_(true);
413 signal_unsaved_status_changed_(false);
417 Action::System::dec_action_count()const
420 if(action_count_==-1)
421 signal_unsaved_status_changed_(true);
423 signal_unsaved_status_changed_(false);
427 Action::System::reset_action_count()const
433 signal_unsaved_status_changed_(false);
437 Action::System::clear_undo_stack()
439 if(undo_action_stack_.empty()) return;
440 undo_action_stack_.clear();
441 signal_undo_status_(false);
442 signal_undo_stack_cleared_();
446 Action::System::clear_redo_stack()
448 if(redo_action_stack_.empty()) return;
449 redo_action_stack_.clear();
450 signal_redo_status_(false);
451 signal_redo_stack_cleared_();
455 Action::System::set_action_status(etl::handle<Action::Undoable> action, bool x)
457 Stack::iterator iter;
460 if(action->is_active()==x)
463 handle<Action::Undoable> cur_pos=undo_action_stack_.front();
465 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
467 handle<UIInterface> uim=new ConfidentUIInterface();
469 iter=find(undo_action_stack_.begin(),undo_action_stack_.end(),action);
470 if(iter!=undo_action_stack_.end())
472 while(undo_action_stack_.front()!=action)
484 action->set_active(x);
486 if(redo_(get_ui_interface()))
488 signal_action_status_changed_(action);
492 action->set_active(!x);
497 while(undo_action_stack_.front()!=cur_pos)
501 redo_action_stack_.front()->set_active(false);
502 signal_action_status_changed_(redo_action_stack_.front());
506 if(!failed && canvas_specific && canvas_specific->is_dirty())
508 Canvas::Handle canvas=canvas_specific->get_canvas();
509 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
510 assert(canvas_interface);
512 //canvas_interface->signal_dirty_preview()();
518 iter=find(redo_action_stack_.begin(),redo_action_stack_.end(),action);
519 if(iter!=redo_action_stack_.end())
521 action->set_active(x);
522 signal_action_status_changed_(action);
527 if(canvas_specific && canvas_specific->is_dirty())
529 Canvas::Handle canvas=canvas_specific->get_canvas();
530 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
531 assert(canvas_interface);
533 //canvas_interface->signal_dirty_preview()();
542 Action::PassiveGrouper::PassiveGrouper(etl::loose_handle<Action::System> instance_,synfig::String name_):
543 instance_(instance_),
545 redraw_requested_(false),
548 // Add this group onto the group stack
549 instance_->group_stack_.push_front(this);
553 Action::PassiveGrouper::request_redraw(handle<CanvasInterface> x)
556 if(instance_->group_stack_.empty())
558 if(x!=canvas_interface_)
561 x->signal_dirty_preview()();
564 redraw_requested_=false;
569 if(instance_->group_stack_.back()==this)
572 redraw_requested_=true;
577 instance_->group_stack_.back()->request_redraw(x);
578 redraw_requested_=false;
586 redraw_requested_=true;
591 Action::PassiveGrouper::~PassiveGrouper()
593 assert(instance_->group_stack_.front()==this);
595 // Remove this group from the group stack
596 instance_->group_stack_.pop_front();
598 handle<Action::Group> group;
602 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
604 group=handle<Action::Group>::cast_dynamic(action);
608 // If the only action inside of us is a group,
609 // then we should rename the group to our name.
610 group->set_name(name_);
614 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
616 if(0)if(canvas_specific && canvas_specific->is_dirty() && canvas_specific->get_canvas_interface())
618 if(instance_->group_stack_.empty())
619 request_redraw(canvas_specific->get_canvas_interface());
623 if(instance_->group_stack_.empty())
625 instance_->inc_action_count();
626 instance_->signal_new_action()(instance_->undo_action_stack_.front());
629 instance_->group_stack_.front()->inc_depth();
635 group=new Action::Group(name_);
637 for(int i=0;i<depth_;i++)
638 // for(;depth_;depth_--)
640 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
641 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
643 if(0)if(canvas_specific && canvas_specific->is_dirty())
645 group->set_dirty(true);
646 group->set_canvas(canvas_specific->get_canvas());
647 group->set_canvas_interface(canvas_specific->get_canvas_interface());
650 // Copy the action from the undo stack to the group
651 group->add_action_front(action);
653 // Remove the action from the undo stack
654 instance_->undo_action_stack_.pop_front();
657 // Push the group onto the stack
658 instance_->undo_action_stack_.push_front(group);
660 if(0)if(group->is_dirty())
661 request_redraw(group->get_canvas_interface());
662 // group->get_canvas_interface()->signal_dirty_preview()();
664 if(instance_->group_stack_.empty())
666 instance_->inc_action_count();
667 instance_->signal_new_action()(instance_->undo_action_stack_.front());
670 instance_->group_stack_.front()->inc_depth();
673 if(0)if(redraw_requested_)
675 if(instance_->group_stack_.empty())
677 assert(canvas_interface_);
679 canvas_interface_->signal_dirty_preview()();
683 instance_->group_stack_.front()->request_redraw(canvas_interface_);
684 redraw_requested_=false;
690 Action::PassiveGrouper::cancel()
694 // Cancel any groupers that may be on top of us first
695 //while(instance_->group_stack_.front()!=this)
696 // instance_->group_stack_.front()->cancel();
698 synfig::warning("Cancel depth: %d",depth_);
701 if(!instance_->undo())
708 instance_->get_ui_interface()->error(_("State restore failure"));
710 redraw_requested_=false;