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(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);
202 //canvas_interface->signal_dirty_preview()();
206 }catch(...) { inuse=false; throw; }
212 synfigapp::Action::System::undo_(handle<UIInterface> uim)
214 handle<Action::Undoable> action(undo_action_stack().front());
215 most_recent_action_=action;
217 try { if(action->is_active()) action->undo(); }
218 catch(Action::Error err)
220 if(err.get_type()!=Action::Error::TYPE_UNABLE)
222 if(err.get_desc().empty())
223 uim->error(action->get_name()+_(" (Undo): ")+strprintf("%d",err.get_type()));
225 uim->error(action->get_name()+_(" (Undo): ")+err.get_desc());
230 catch(std::runtime_error x)
232 uim->error(x.what());
242 if(redo_action_stack_.empty()) signal_redo_status()(true);
244 redo_action_stack_.push_front(undo_action_stack_.front());
245 undo_action_stack_.pop_front();
247 if(undo_action_stack_.empty()) signal_undo_status()(false);
249 if(!group_stack_.empty())
250 group_stack_.front()->dec_depth();
258 synfigapp::Action::System::undo()
260 //! \todo This function is not exception safe!
261 static bool inuse=false;
263 // If there is nothing on the action list, there is nothing to undo
264 if(undo_action_stack().empty() || inuse)
267 handle<Action::Undoable> action=undo_action_stack().front();
268 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
270 handle<UIInterface> uim;
271 if(canvas_specific && canvas_specific->get_canvas())
273 Canvas::Handle canvas=canvas_specific->get_canvas();
274 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
275 assert(canvas_interface);
276 uim=canvas_interface->get_ui_interface();
279 uim=get_ui_interface();
285 uim->error(undo_action_stack_.front()->get_name()+": "+_("Failed to undo."));
292 // If the action has "dirtied" the preview, signal it.
293 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
295 Canvas::Handle canvas=canvas_specific->get_canvas();
296 if(!group_stack_.empty())
297 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
300 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
301 assert(canvas_interface);
303 //canvas_interface->signal_dirty_preview()();
311 Action::System::redo_(handle<UIInterface> uim)
313 handle<Action::Undoable> action(redo_action_stack().front());
314 most_recent_action_=action;
316 try { if(action->is_active()) action->perform(); }
317 catch(Action::Error err)
319 if(err.get_type()!=Action::Error::TYPE_UNABLE)
321 if(err.get_desc().empty())
322 uim->error(action->get_name()+_(" (Redo): ")+strprintf("%d",err.get_type()));
324 uim->error(action->get_name()+_(" (Redo): ")+err.get_desc());
329 catch(std::runtime_error x)
331 uim->error(x.what());
341 if(undo_action_stack_.empty()) signal_undo_status()(true);
343 undo_action_stack_.push_front(redo_action_stack_.front());
344 redo_action_stack_.pop_front();
346 if(redo_action_stack_.empty()) signal_redo_status()(false);
348 if(!group_stack_.empty())
349 group_stack_.front()->inc_depth();
357 Action::System::redo()
359 //! \todo This function is not exception safe!
360 static bool inuse=false;
362 // If there is nothing on the action list, there is nothing to undo
363 if(redo_action_stack_.empty() || inuse)
368 handle<Action::Undoable> action=redo_action_stack().front();
369 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
371 handle<UIInterface> uim;
372 if(canvas_specific && canvas_specific->get_canvas())
374 Canvas::Handle canvas=canvas_specific->get_canvas();
375 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
376 assert(canvas_interface);
377 uim=canvas_interface->get_ui_interface();
380 uim=get_ui_interface();
384 uim->error(redo_action_stack_.front()->get_name()+": "+_("Failed to redo."));
391 // If the action has "dirtied" the preview, signal it.
392 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
394 Canvas::Handle canvas=canvas_specific->get_canvas();
395 if(!group_stack_.empty())
396 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
399 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
400 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);
515 //canvas_interface->signal_dirty_preview()();
521 iter=find(redo_action_stack_.begin(),redo_action_stack_.end(),action);
522 if(iter!=redo_action_stack_.end())
524 action->set_active(x);
525 signal_action_status_changed_(action);
530 if(canvas_specific && canvas_specific->is_dirty())
532 Canvas::Handle canvas=canvas_specific->get_canvas();
533 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
534 assert(canvas_interface);
536 //canvas_interface->signal_dirty_preview()();
545 Action::PassiveGrouper::PassiveGrouper(etl::loose_handle<Action::System> instance_,synfig::String name_):
546 instance_(instance_),
548 redraw_requested_(false),
551 // Add this group onto the group stack
552 instance_->group_stack_.push_front(this);
556 Action::PassiveGrouper::request_redraw(handle<CanvasInterface> x)
559 if(instance_->group_stack_.empty())
561 if(x!=canvas_interface_)
564 x->signal_dirty_preview()();
567 redraw_requested_=false;
572 if(instance_->group_stack_.back()==this)
575 redraw_requested_=true;
580 instance_->group_stack_.back()->request_redraw(x);
581 redraw_requested_=false;
589 redraw_requested_=true;
594 Action::PassiveGrouper::~PassiveGrouper()
596 assert(instance_->group_stack_.front()==this);
598 // Remove this group from the group stack
599 instance_->group_stack_.pop_front();
601 handle<Action::Group> group;
605 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
607 group=handle<Action::Group>::cast_dynamic(action);
611 // If the only action inside of us is a group,
612 // then we should rename the group to our name.
613 group->set_name(name_);
617 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
619 if(0)if(canvas_specific && canvas_specific->is_dirty() && canvas_specific->get_canvas_interface())
621 if(instance_->group_stack_.empty())
622 request_redraw(canvas_specific->get_canvas_interface());
626 if(instance_->group_stack_.empty())
628 instance_->inc_action_count();
629 instance_->signal_new_action()(instance_->undo_action_stack_.front());
632 instance_->group_stack_.front()->inc_depth();
638 group=new Action::Group(name_);
640 for(int i=0;i<depth_;i++)
641 // for(;depth_;depth_--)
643 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
644 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
646 if(0)if(canvas_specific && canvas_specific->is_dirty())
648 group->set_dirty(true);
649 group->set_canvas(canvas_specific->get_canvas());
650 group->set_canvas_interface(canvas_specific->get_canvas_interface());
653 // Copy the action from the undo stack to the group
654 group->add_action_front(action);
656 // Remove the action from the undo stack
657 instance_->undo_action_stack_.pop_front();
660 // Push the group onto the stack
661 instance_->undo_action_stack_.push_front(group);
663 if(0)if(group->is_dirty())
664 request_redraw(group->get_canvas_interface());
665 // group->get_canvas_interface()->signal_dirty_preview()();
667 if(instance_->group_stack_.empty())
669 instance_->inc_action_count();
670 instance_->signal_new_action()(instance_->undo_action_stack_.front());
673 instance_->group_stack_.front()->inc_depth();
676 if(0)if(redraw_requested_)
678 if(instance_->group_stack_.empty())
680 assert(canvas_interface_);
682 canvas_interface_->signal_dirty_preview()();
686 instance_->group_stack_.front()->request_redraw(canvas_interface_);
687 redraw_requested_=false;
693 Action::PassiveGrouper::cancel()
697 // Cancel any groupers that may be on top of us first
698 //while(instance_->group_stack_.front()!=this)
699 // instance_->group_stack_.front()->cancel();
701 synfig::warning("Cancel depth: %d",depth_);
704 if(!instance_->undo())
711 instance_->get_ui_interface()->error(_("State restore failure"));
713 redraw_requested_=false;