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)
72 // synfig::info("%s:%d perform_action: '%s'", __FILE__, __LINE__, action->get_name().c_str());
74 handle<UIInterface> uim(get_ui_interface());
78 if(!action->is_ready())
80 uim->error(action->get_local_name()+": "+_("Action is not ready."));
84 most_recent_action_=action;
86 static bool inuse=false;
88 if(inuse) return false;
95 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
97 if(canvas_specific && canvas_specific->get_canvas())
99 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas_specific->get_canvas());
100 assert(canvas_interface);
101 uim=canvas_interface->get_ui_interface();
104 handle<Action::Undoable> undoable_action=handle<Action::Undoable>::cast_dynamic(action);
106 // If we cannot undo this action, make sure
107 // that the user knows this.
111 action->get_local_name(),
112 _("This action cannot be undone! Are you sure you want to continue?"),
113 UIInterface::RESPONSE_NO
114 ) == UIInterface::RESPONSE_NO
119 // Because this action cannot be undone,
120 // we need to clear the undo stack
125 assert(undoable_action->is_active());
127 // Perform the action
128 try { action->perform(); }
129 catch(Action::Error err)
131 uim->task(action->get_local_name()+' '+_("Failed"));
134 if(err.get_type()!=Action::Error::TYPE_UNABLE)
136 if(err.get_desc().empty())
137 uim->error(action->get_local_name()+": "+strprintf("%d",err.get_type()));
139 uim->error(action->get_local_name()+": "+err.get_desc());
142 // If action failed for whatever reason, just return false and do
143 // not add the action onto the list
146 catch(std::exception err)
148 uim->task(action->get_local_name()+' '+_("Failed"));
151 uim->error(action->get_local_name()+": "+err.what());
153 // If action failed for whatever reason, just return false and do
154 // not add the action onto the list
159 uim->task(action->get_local_name()+' '+_("Failed"));
162 // If action failed for whatever reason, just return false and do
163 // not add the action onto the list
167 // Clear the redo stack
168 if(clear_redo_stack_on_new_action_)
171 if(!group_stack_.empty())
172 group_stack_.front()->inc_depth();
176 // Push this action onto the action list if we can undo it
179 // If necessary, signal the change in status of undo
180 if(undo_action_stack_.empty()) signal_undo_status_(true);
182 // Add it to the list
183 undo_action_stack_.push_front(undoable_action);
185 // Signal that a new action has been added
186 if(group_stack_.empty())
187 signal_new_action()(undoable_action);
192 uim->task(action->get_local_name()+' '+_("Successful"));
194 // If the action has "dirtied" the preview, signal it.
195 if(0)if(canvas_specific && canvas_specific->is_dirty())
197 Canvas::Handle canvas=canvas_specific->get_canvas();
198 if(!group_stack_.empty())
199 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
202 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
203 assert(canvas_interface);
204 //canvas_interface->signal_dirty_preview()();
208 }catch(...) { inuse=false; throw; }
214 synfigapp::Action::System::undo_(etl::handle<UIInterface> uim)
216 handle<Action::Undoable> action(undo_action_stack().front());
217 most_recent_action_=action;
219 try { if(action->is_active()) action->undo(); }
220 catch(Action::Error err)
222 if(err.get_type()!=Action::Error::TYPE_UNABLE)
224 if(err.get_desc().empty())
225 uim->error(action->get_local_name()+_(" (Undo): ")+strprintf("%d",err.get_type()));
227 uim->error(action->get_local_name()+_(" (Undo): ")+err.get_desc());
232 catch(std::runtime_error x)
234 uim->error(x.what());
244 if(redo_action_stack_.empty()) signal_redo_status()(true);
246 redo_action_stack_.push_front(undo_action_stack_.front());
247 undo_action_stack_.pop_front();
249 if(undo_action_stack_.empty()) signal_undo_status()(false);
251 if(!group_stack_.empty())
252 group_stack_.front()->dec_depth();
260 synfigapp::Action::System::undo()
262 //! \todo This function is not exception safe!
263 static bool inuse=false;
265 // If there is nothing on the action list, there is nothing to undo
266 if(undo_action_stack().empty() || inuse)
269 handle<Action::Undoable> action=undo_action_stack().front();
270 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
272 handle<UIInterface> uim;
273 if(canvas_specific && canvas_specific->get_canvas())
275 Canvas::Handle canvas=canvas_specific->get_canvas();
276 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
277 assert(canvas_interface);
278 uim=canvas_interface->get_ui_interface();
281 uim=get_ui_interface();
287 uim->error(undo_action_stack_.front()->get_local_name()+": "+_("Failed to undo."));
294 // If the action has "dirtied" the preview, signal it.
295 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
297 Canvas::Handle canvas=canvas_specific->get_canvas();
298 if(!group_stack_.empty())
299 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
302 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
303 assert(canvas_interface);
304 //canvas_interface->signal_dirty_preview()();
312 Action::System::redo_(etl::handle<UIInterface> uim)
314 handle<Action::Undoable> action(redo_action_stack().front());
315 most_recent_action_=action;
317 try { if(action->is_active()) action->perform(); }
318 catch(Action::Error err)
320 if(err.get_type()!=Action::Error::TYPE_UNABLE)
322 if(err.get_desc().empty())
323 uim->error(action->get_local_name()+_(" (Redo): ")+strprintf("%d",err.get_type()));
325 uim->error(action->get_local_name()+_(" (Redo): ")+err.get_desc());
330 catch(std::runtime_error x)
332 uim->error(x.what());
342 if(undo_action_stack_.empty()) signal_undo_status()(true);
344 undo_action_stack_.push_front(redo_action_stack_.front());
345 redo_action_stack_.pop_front();
347 if(redo_action_stack_.empty()) signal_redo_status()(false);
349 if(!group_stack_.empty())
350 group_stack_.front()->inc_depth();
358 Action::System::redo()
360 //! \todo This function is not exception safe!
361 static bool inuse=false;
363 // If there is nothing on the action list, there is nothing to undo
364 if(redo_action_stack_.empty() || inuse)
369 handle<Action::Undoable> action=redo_action_stack().front();
370 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
372 handle<UIInterface> uim;
373 if(canvas_specific && canvas_specific->get_canvas())
375 Canvas::Handle canvas=canvas_specific->get_canvas();
376 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
377 assert(canvas_interface);
378 uim=canvas_interface->get_ui_interface();
381 uim=get_ui_interface();
385 uim->error(redo_action_stack_.front()->get_local_name()+": "+_("Failed to redo."));
392 // If the action has "dirtied" the preview, signal it.
393 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
395 Canvas::Handle canvas=canvas_specific->get_canvas();
396 if(!group_stack_.empty())
397 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
400 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
401 assert(canvas_interface);
402 //canvas_interface->signal_dirty_preview()();
410 Action::System::inc_action_count()const
414 signal_unsaved_status_changed_(true);
416 signal_unsaved_status_changed_(false);
420 Action::System::dec_action_count()const
423 if(action_count_==-1)
424 signal_unsaved_status_changed_(true);
426 signal_unsaved_status_changed_(false);
430 Action::System::reset_action_count()const
436 signal_unsaved_status_changed_(false);
440 Action::System::clear_undo_stack()
442 if(undo_action_stack_.empty()) return;
443 undo_action_stack_.clear();
444 signal_undo_status_(false);
445 signal_undo_stack_cleared_();
449 Action::System::clear_redo_stack()
451 if(redo_action_stack_.empty()) return;
452 redo_action_stack_.clear();
453 signal_redo_status_(false);
454 signal_redo_stack_cleared_();
458 Action::System::set_action_status(etl::handle<Action::Undoable> action, bool x)
460 Stack::iterator iter;
463 if(action->is_active()==x)
466 handle<Action::Undoable> cur_pos=undo_action_stack_.front();
468 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
470 handle<UIInterface> uim=new ConfidentUIInterface();
472 iter=find(undo_action_stack_.begin(),undo_action_stack_.end(),action);
473 if(iter!=undo_action_stack_.end())
475 while(undo_action_stack_.front()!=action)
487 action->set_active(x);
489 if(redo_(get_ui_interface()))
491 signal_action_status_changed_(action);
495 action->set_active(!x);
500 while(undo_action_stack_.front()!=cur_pos)
504 redo_action_stack_.front()->set_active(false);
505 signal_action_status_changed_(redo_action_stack_.front());
509 if(!failed && canvas_specific && canvas_specific->is_dirty())
511 Canvas::Handle canvas=canvas_specific->get_canvas();
512 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
513 assert(canvas_interface);
514 //canvas_interface->signal_dirty_preview()();
520 iter=find(redo_action_stack_.begin(),redo_action_stack_.end(),action);
521 if(iter!=redo_action_stack_.end())
523 action->set_active(x);
524 signal_action_status_changed_(action);
529 if(canvas_specific && canvas_specific->is_dirty())
531 Canvas::Handle canvas=canvas_specific->get_canvas();
532 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
533 assert(canvas_interface);
534 //canvas_interface->signal_dirty_preview()();
543 Action::PassiveGrouper::PassiveGrouper(etl::loose_handle<System> instance_,synfig::String name_):
544 instance_(instance_),
546 redraw_requested_(false),
549 // Add this group onto the group stack
550 instance_->group_stack_.push_front(this);
554 Action::PassiveGrouper::request_redraw(etl::handle<CanvasInterface> x)
556 /* if(instance_->group_stack_.empty())
558 if(x!=canvas_interface_)
560 x->signal_dirty_preview()();
563 redraw_requested_=false;
567 if(instance_->group_stack_.back()==this)
569 redraw_requested_=true;
573 instance_->group_stack_.back()->request_redraw(x);
574 redraw_requested_=false;
580 redraw_requested_=true;
585 Action::PassiveGrouper::~PassiveGrouper()
587 assert(instance_->group_stack_.front()==this);
589 // Remove this group from the group stack
590 instance_->group_stack_.pop_front();
592 handle<Action::Group> group;
596 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
598 group=handle<Action::Group>::cast_dynamic(action);
602 // If the only action inside of us is a group,
603 // then we should rename the group to our name.
604 group->set_name(name_);
608 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
610 if(0)if(canvas_specific && canvas_specific->is_dirty() && canvas_specific->get_canvas_interface())
612 if(instance_->group_stack_.empty())
613 request_redraw(canvas_specific->get_canvas_interface());
617 if(instance_->group_stack_.empty())
619 instance_->inc_action_count();
620 instance_->signal_new_action()(instance_->undo_action_stack_.front());
623 instance_->group_stack_.front()->inc_depth();
629 group=new Action::Group(name_);
631 for(int i=0;i<depth_;i++)
632 // for(;depth_;depth_--)
634 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
635 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
637 if(0)if(canvas_specific && canvas_specific->is_dirty())
639 group->set_dirty(true);
640 group->set_canvas(canvas_specific->get_canvas());
641 group->set_canvas_interface(canvas_specific->get_canvas_interface());
644 // Copy the action from the undo stack to the group
645 group->add_action_front(action);
647 // Remove the action from the undo stack
648 instance_->undo_action_stack_.pop_front();
651 // Push the group onto the stack
652 instance_->undo_action_stack_.push_front(group);
654 if(0)if(group->is_dirty())
655 request_redraw(group->get_canvas_interface());
656 // group->get_canvas_interface()->signal_dirty_preview()();
658 if(instance_->group_stack_.empty())
660 instance_->inc_action_count();
661 instance_->signal_new_action()(instance_->undo_action_stack_.front());
664 instance_->group_stack_.front()->inc_depth();
667 if(0)if(redraw_requested_)
669 if(instance_->group_stack_.empty())
671 assert(canvas_interface_);
672 canvas_interface_->signal_dirty_preview()();
676 instance_->group_stack_.front()->request_redraw(canvas_interface_);
677 redraw_requested_=false;
683 Action::PassiveGrouper::cancel()
687 // Cancel any groupers that may be on top of us first
688 //while(instance_->group_stack_.front()!=this)
689 // instance_->group_stack_.front()->cancel();
691 synfig::warning("Cancel depth: %d",depth_);
694 if(!instance_->undo())
701 instance_->get_ui_interface()->error(_("State restore failure"));
703 redraw_requested_=false;