1 /* === S Y N F I G ========================================================= */
2 /*! \file action_system.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include "action_system.h"
34 #include "canvasinterface.h"
40 /* === U S I N G =========================================================== */
44 using namespace synfigapp;
45 using namespace synfig;
47 /* === M A C R O S ========================================================= */
49 /* === G L O B A L S ======================================================= */
51 /* === P R O C E D U R E S ================================================= */
53 /* === M E T H O D S ======================================================= */
57 Action::System::System():
61 clear_redo_stack_on_new_action_=false;
64 Action::System::~System()
69 Action::System::perform_action(etl::handle<Action::Base> action)
71 handle<UIInterface> uim(get_ui_interface());
75 if(!action->is_ready())
77 uim->error(action->get_name()+": "+_("Action is not ready."));
81 most_recent_action_=action;
83 static bool inuse=false;
85 if(inuse) return false;
92 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
94 if(canvas_specific && canvas_specific->get_canvas())
96 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas_specific->get_canvas());
97 assert(canvas_interface);
98 uim=canvas_interface->get_ui_interface();
101 handle<Action::Undoable> undoable_action=handle<Action::Undoable>::cast_dynamic(action);
103 // If we cannot undo this action, make sure
104 // that the user knows this.
109 _("This action cannot be undone! Are you sure you want to continue?"),
110 UIInterface::RESPONSE_NO
111 ) == UIInterface::RESPONSE_NO
116 // Because this action cannot be undone,
117 // we need to clear the undo stack
122 assert(undoable_action->is_active());
124 // Perform the action
125 try { action->perform(); }
126 catch(Action::Error err)
128 uim->task(action->get_name()+' '+_("Failed"));
131 if(err.get_type()!=Action::Error::TYPE_UNABLE)
133 if(err.get_desc().empty())
134 uim->error(action->get_name()+": "+strprintf("%d",err.get_type()));
136 uim->error(action->get_name()+": "+err.get_desc());
139 // If action failed for whatever reason, just return false and do
140 // not add the action onto the list
143 catch(std::exception err)
145 uim->task(action->get_name()+' '+_("Failed"));
148 uim->error(action->get_name()+": "+err.what());
150 // If action failed for whatever reason, just return false and do
151 // not add the action onto the list
156 uim->task(action->get_name()+' '+_("Failed"));
159 // If action failed for whatever reason, just return false and do
160 // not add the action onto the list
164 // Clear the redo stack
165 if(clear_redo_stack_on_new_action_)
168 if(!group_stack_.empty())
169 group_stack_.front()->inc_depth();
173 // Push this action onto the action list if we can undo it
176 // If necessary, signal the change in status of undo
177 if(undo_action_stack_.empty()) signal_undo_status_(true);
179 // Add it to the list
180 undo_action_stack_.push_front(undoable_action);
182 // Signal that a new action has been added
183 if(group_stack_.empty())
184 signal_new_action()(undoable_action);
189 uim->task(action->get_name()+' '+_("Successful"));
191 // If the action has "dirtied" the preview, signal it.
192 if(0)if(canvas_specific && canvas_specific->is_dirty())
194 Canvas::Handle canvas=canvas_specific->get_canvas();
195 if(!group_stack_.empty())
196 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
199 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
200 assert(canvas_interface);
201 //canvas_interface->signal_dirty_preview()();
205 }catch(...) { inuse=false; throw; }
211 synfigapp::Action::System::undo_(etl::handle<UIInterface> uim)
213 handle<Action::Undoable> action(undo_action_stack().front());
214 most_recent_action_=action;
216 try { if(action->is_active()) action->undo(); }
217 catch(Action::Error err)
219 if(err.get_type()!=Action::Error::TYPE_UNABLE)
221 if(err.get_desc().empty())
222 uim->error(action->get_name()+_(" (Undo): ")+strprintf("%d",err.get_type()));
224 uim->error(action->get_name()+_(" (Undo): ")+err.get_desc());
229 catch(std::runtime_error x)
231 uim->error(x.what());
241 if(redo_action_stack_.empty()) signal_redo_status()(true);
243 redo_action_stack_.push_front(undo_action_stack_.front());
244 undo_action_stack_.pop_front();
246 if(undo_action_stack_.empty()) signal_undo_status()(false);
248 if(!group_stack_.empty())
249 group_stack_.front()->dec_depth();
257 synfigapp::Action::System::undo()
259 //! \todo This function is not exception safe!
260 static bool inuse=false;
262 // If there is nothing on the action list, there is nothing to undo
263 if(undo_action_stack().empty() || inuse)
266 handle<Action::Undoable> action=undo_action_stack().front();
267 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
269 handle<UIInterface> uim;
270 if(canvas_specific && canvas_specific->get_canvas())
272 Canvas::Handle canvas=canvas_specific->get_canvas();
273 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
274 assert(canvas_interface);
275 uim=canvas_interface->get_ui_interface();
278 uim=get_ui_interface();
284 uim->error(undo_action_stack_.front()->get_name()+": "+_("Failed to undo."));
291 // If the action has "dirtied" the preview, signal it.
292 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
294 Canvas::Handle canvas=canvas_specific->get_canvas();
295 if(!group_stack_.empty())
296 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
299 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
300 assert(canvas_interface);
301 //canvas_interface->signal_dirty_preview()();
309 Action::System::redo_(etl::handle<UIInterface> uim)
311 handle<Action::Undoable> action(redo_action_stack().front());
312 most_recent_action_=action;
314 try { if(action->is_active()) action->perform(); }
315 catch(Action::Error err)
317 if(err.get_type()!=Action::Error::TYPE_UNABLE)
319 if(err.get_desc().empty())
320 uim->error(action->get_name()+_(" (Redo): ")+strprintf("%d",err.get_type()));
322 uim->error(action->get_name()+_(" (Redo): ")+err.get_desc());
327 catch(std::runtime_error x)
329 uim->error(x.what());
339 if(undo_action_stack_.empty()) signal_undo_status()(true);
341 undo_action_stack_.push_front(redo_action_stack_.front());
342 redo_action_stack_.pop_front();
344 if(redo_action_stack_.empty()) signal_redo_status()(false);
346 if(!group_stack_.empty())
347 group_stack_.front()->inc_depth();
355 Action::System::redo()
357 //! \todo This function is not exception safe!
358 static bool inuse=false;
360 // If there is nothing on the action list, there is nothing to undo
361 if(redo_action_stack_.empty() || inuse)
366 handle<Action::Undoable> action=redo_action_stack().front();
367 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
369 handle<UIInterface> uim;
370 if(canvas_specific && canvas_specific->get_canvas())
372 Canvas::Handle canvas=canvas_specific->get_canvas();
373 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
374 assert(canvas_interface);
375 uim=canvas_interface->get_ui_interface();
378 uim=get_ui_interface();
382 uim->error(redo_action_stack_.front()->get_name()+": "+_("Failed to redo."));
389 // If the action has "dirtied" the preview, signal it.
390 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
392 Canvas::Handle canvas=canvas_specific->get_canvas();
393 if(!group_stack_.empty())
394 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
397 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
398 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);
511 //canvas_interface->signal_dirty_preview()();
517 iter=find(redo_action_stack_.begin(),redo_action_stack_.end(),action);
518 if(iter!=redo_action_stack_.end())
520 action->set_active(x);
521 signal_action_status_changed_(action);
526 if(canvas_specific && canvas_specific->is_dirty())
528 Canvas::Handle canvas=canvas_specific->get_canvas();
529 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
530 assert(canvas_interface);
531 //canvas_interface->signal_dirty_preview()();
540 Action::PassiveGrouper::PassiveGrouper(etl::loose_handle<System> instance_,synfig::String name_):
541 instance_(instance_),
543 redraw_requested_(false),
546 // Add this group onto the group stack
547 instance_->group_stack_.push_front(this);
551 Action::PassiveGrouper::request_redraw(etl::handle<CanvasInterface> x)
553 /* if(instance_->group_stack_.empty())
555 if(x!=canvas_interface_)
557 x->signal_dirty_preview()();
560 redraw_requested_=false;
564 if(instance_->group_stack_.back()==this)
566 redraw_requested_=true;
570 instance_->group_stack_.back()->request_redraw(x);
571 redraw_requested_=false;
577 redraw_requested_=true;
582 Action::PassiveGrouper::~PassiveGrouper()
584 assert(instance_->group_stack_.front()==this);
586 // Remove this group from the group stack
587 instance_->group_stack_.pop_front();
589 handle<Action::Group> group;
593 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
595 group=handle<Action::Group>::cast_dynamic(action);
599 // If the only action inside of us is a group,
600 // then we should rename the group to our name.
601 group->set_name(name_);
605 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
607 if(0)if(canvas_specific && canvas_specific->is_dirty() && canvas_specific->get_canvas_interface())
609 if(instance_->group_stack_.empty())
610 request_redraw(canvas_specific->get_canvas_interface());
614 if(instance_->group_stack_.empty())
616 instance_->inc_action_count();
617 instance_->signal_new_action()(instance_->undo_action_stack_.front());
620 instance_->group_stack_.front()->inc_depth();
626 group=new Action::Group(name_);
628 for(int i=0;i<depth_;i++)
629 // for(;depth_;depth_--)
631 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
632 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
634 if(0)if(canvas_specific && canvas_specific->is_dirty())
636 group->set_dirty(true);
637 group->set_canvas(canvas_specific->get_canvas());
638 group->set_canvas_interface(canvas_specific->get_canvas_interface());
641 // Copy the action from the undo stack to the group
642 group->add_action_front(action);
644 // Remove the action from the undo stack
645 instance_->undo_action_stack_.pop_front();
648 // Push the group onto the stack
649 instance_->undo_action_stack_.push_front(group);
651 if(0)if(group->is_dirty())
652 request_redraw(group->get_canvas_interface());
653 // group->get_canvas_interface()->signal_dirty_preview()();
655 if(instance_->group_stack_.empty())
657 instance_->inc_action_count();
658 instance_->signal_new_action()(instance_->undo_action_stack_.front());
661 instance_->group_stack_.front()->inc_depth();
664 if(0)if(redraw_requested_)
666 if(instance_->group_stack_.empty())
668 assert(canvas_interface_);
669 canvas_interface_->signal_dirty_preview()();
673 instance_->group_stack_.front()->request_redraw(canvas_interface_);
674 redraw_requested_=false;
680 Action::PassiveGrouper::cancel()
684 // Cancel any groupers that may be on top of us first
685 //while(instance_->group_stack_.front()!=this)
686 // instance_->group_stack_.front()->cancel();
688 synfig::warning("Cancel depth: %d",depth_);
691 if(!instance_->undo())
698 instance_->get_ui_interface()->error(_("State restore failure"));
700 redraw_requested_=false;