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-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"
38 /* === U S I N G =========================================================== */
42 using namespace synfigapp;
43 using namespace synfig;
45 /* === M A C R O S ========================================================= */
47 /* === G L O B A L S ======================================================= */
49 /* === P R O C E D U R E S ================================================= */
51 /* === M E T H O D S ======================================================= */
55 Action::System::System():
59 clear_redo_stack_on_new_action_=false;
62 Action::System::~System()
67 Action::System::perform_action(handle<Action::Base> action)
69 handle<UIInterface> uim(get_ui_interface());
73 if(!action->is_ready())
75 uim->error(action->get_name()+": "+_("Action is not ready."));
79 most_recent_action_=action;
81 static bool inuse=false;
83 if(inuse) return false;
90 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
92 if(canvas_specific && canvas_specific->get_canvas())
94 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas_specific->get_canvas());
95 assert(canvas_interface);
96 uim=canvas_interface->get_ui_interface();
99 handle<Action::Undoable> undoable_action=handle<Action::Undoable>::cast_dynamic(action);
101 // If we cannot undo this action, make sure
102 // that the user knows this.
107 _("This action cannot be undone! Are you sure you want to continue?"),
108 UIInterface::RESPONSE_NO
109 ) == UIInterface::RESPONSE_NO
114 // Because this action cannot be undone,
115 // we need to clear the undo stack
120 assert(undoable_action->is_active());
122 // Perform the action
123 try { action->perform(); }
124 catch(Action::Error err)
126 uim->task(action->get_name()+' '+_("Failed"));
129 if(err.get_type()!=Action::Error::TYPE_UNABLE)
131 if(err.get_desc().empty())
132 uim->error(action->get_name()+": "+strprintf("%d",err.get_type()));
134 uim->error(action->get_name()+": "+err.get_desc());
137 // If action failed for whatever reason, just return false and do
138 // not add the action onto the list
141 catch(std::exception err)
143 uim->task(action->get_name()+' '+_("Failed"));
146 uim->error(action->get_name()+": "+err.what());
148 // If action failed for whatever reason, just return false and do
149 // not add the action onto the list
154 uim->task(action->get_name()+' '+_("Failed"));
157 // If action failed for whatever reason, just return false and do
158 // not add the action onto the list
162 // Clear the redo stack
163 if(clear_redo_stack_on_new_action_)
166 if(!group_stack_.empty())
167 group_stack_.front()->inc_depth();
171 // Push this action onto the action list if we can undo it
174 // If necessary, signal the change in status of undo
175 if(undo_action_stack_.empty()) signal_undo_status_(true);
177 // Add it to the list
178 undo_action_stack_.push_front(undoable_action);
180 // Signal that a new action has been added
181 if(group_stack_.empty())
182 signal_new_action()(undoable_action);
187 uim->task(action->get_name()+' '+_("Successful"));
189 // If the action has "dirtied" the preview, signal it.
190 if(0)if(canvas_specific && canvas_specific->is_dirty())
192 Canvas::Handle canvas=canvas_specific->get_canvas();
193 if(!group_stack_.empty())
194 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
197 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
198 assert(canvas_interface);
200 //canvas_interface->signal_dirty_preview()();
204 }catch(...) { inuse=false; throw; }
210 synfigapp::Action::System::undo_(handle<UIInterface> uim)
212 handle<Action::Undoable> action(undo_action_stack().front());
213 most_recent_action_=action;
215 try { if(action->is_active()) action->undo(); }
216 catch(Action::Error err)
218 if(err.get_type()!=Action::Error::TYPE_UNABLE)
220 if(err.get_desc().empty())
221 uim->error(action->get_name()+_(" (Undo): ")+strprintf("%d",err.get_type()));
223 uim->error(action->get_name()+_(" (Undo): ")+err.get_desc());
228 catch(std::runtime_error x)
230 uim->error(x.what());
240 if(redo_action_stack_.empty()) signal_redo_status()(true);
242 redo_action_stack_.push_front(undo_action_stack_.front());
243 undo_action_stack_.pop_front();
245 if(undo_action_stack_.empty()) signal_undo_status()(false);
247 if(!group_stack_.empty())
248 group_stack_.front()->dec_depth();
256 synfigapp::Action::System::undo()
258 //! \todo This function is not exception safe!
259 static bool inuse=false;
261 // If there is nothing on the action list, there is nothing to undo
262 if(undo_action_stack().empty() || inuse)
265 handle<Action::Undoable> action=undo_action_stack().front();
266 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
268 handle<UIInterface> uim;
269 if(canvas_specific && canvas_specific->get_canvas())
271 Canvas::Handle canvas=canvas_specific->get_canvas();
272 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
273 assert(canvas_interface);
274 uim=canvas_interface->get_ui_interface();
277 uim=get_ui_interface();
283 uim->error(undo_action_stack_.front()->get_name()+": "+_("Failed to undo."));
290 // If the action has "dirtied" the preview, signal it.
291 if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
293 Canvas::Handle canvas=canvas_specific->get_canvas();
294 if(!group_stack_.empty())
295 group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
298 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
299 assert(canvas_interface);
301 //canvas_interface->signal_dirty_preview()();
309 Action::System::redo_(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);
400 //canvas_interface->signal_dirty_preview()();
408 Action::System::inc_action_count()const
412 signal_unsaved_status_changed_(true);
414 signal_unsaved_status_changed_(false);
418 Action::System::dec_action_count()const
421 if(action_count_==-1)
422 signal_unsaved_status_changed_(true);
424 signal_unsaved_status_changed_(false);
428 Action::System::reset_action_count()const
434 signal_unsaved_status_changed_(false);
438 Action::System::clear_undo_stack()
440 if(undo_action_stack_.empty()) return;
441 undo_action_stack_.clear();
442 signal_undo_status_(false);
443 signal_undo_stack_cleared_();
447 Action::System::clear_redo_stack()
449 if(redo_action_stack_.empty()) return;
450 redo_action_stack_.clear();
451 signal_redo_status_(false);
452 signal_redo_stack_cleared_();
456 Action::System::set_action_status(etl::handle<Action::Undoable> action, bool x)
458 Stack::iterator iter;
461 if(action->is_active()==x)
464 handle<Action::Undoable> cur_pos=undo_action_stack_.front();
466 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
468 handle<UIInterface> uim=new ConfidentUIInterface();
470 iter=find(undo_action_stack_.begin(),undo_action_stack_.end(),action);
471 if(iter!=undo_action_stack_.end())
473 while(undo_action_stack_.front()!=action)
485 action->set_active(x);
487 if(redo_(get_ui_interface()))
489 signal_action_status_changed_(action);
493 action->set_active(!x);
498 while(undo_action_stack_.front()!=cur_pos)
502 redo_action_stack_.front()->set_active(false);
503 signal_action_status_changed_(redo_action_stack_.front());
507 if(!failed && canvas_specific && canvas_specific->is_dirty())
509 Canvas::Handle canvas=canvas_specific->get_canvas();
510 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
511 assert(canvas_interface);
513 //canvas_interface->signal_dirty_preview()();
519 iter=find(redo_action_stack_.begin(),redo_action_stack_.end(),action);
520 if(iter!=redo_action_stack_.end())
522 action->set_active(x);
523 signal_action_status_changed_(action);
528 if(canvas_specific && canvas_specific->is_dirty())
530 Canvas::Handle canvas=canvas_specific->get_canvas();
531 handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
532 assert(canvas_interface);
534 //canvas_interface->signal_dirty_preview()();
543 Action::PassiveGrouper::PassiveGrouper(etl::loose_handle<Action::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(handle<CanvasInterface> x)
557 if(instance_->group_stack_.empty())
559 if(x!=canvas_interface_)
562 x->signal_dirty_preview()();
565 redraw_requested_=false;
570 if(instance_->group_stack_.back()==this)
573 redraw_requested_=true;
578 instance_->group_stack_.back()->request_redraw(x);
579 redraw_requested_=false;
587 redraw_requested_=true;
592 Action::PassiveGrouper::~PassiveGrouper()
594 assert(instance_->group_stack_.front()==this);
596 // Remove this group from the group stack
597 instance_->group_stack_.pop_front();
599 handle<Action::Group> group;
603 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
605 group=handle<Action::Group>::cast_dynamic(action);
609 // If the only action inside of us is a group,
610 // then we should rename the group to our name.
611 group->set_name(name_);
615 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
617 if(0)if(canvas_specific && canvas_specific->is_dirty() && canvas_specific->get_canvas_interface())
619 if(instance_->group_stack_.empty())
620 request_redraw(canvas_specific->get_canvas_interface());
624 if(instance_->group_stack_.empty())
626 instance_->inc_action_count();
627 instance_->signal_new_action()(instance_->undo_action_stack_.front());
630 instance_->group_stack_.front()->inc_depth();
636 group=new Action::Group(name_);
638 for(int i=0;i<depth_;i++)
639 // for(;depth_;depth_--)
641 handle<Action::Undoable> action(instance_->undo_action_stack_.front());
642 Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
644 if(0)if(canvas_specific && canvas_specific->is_dirty())
646 group->set_dirty(true);
647 group->set_canvas(canvas_specific->get_canvas());
648 group->set_canvas_interface(canvas_specific->get_canvas_interface());
651 // Copy the action from the undo stack to the group
652 group->add_action_front(action);
654 // Remove the action from the undo stack
655 instance_->undo_action_stack_.pop_front();
658 // Push the group onto the stack
659 instance_->undo_action_stack_.push_front(group);
661 if(0)if(group->is_dirty())
662 request_redraw(group->get_canvas_interface());
663 // group->get_canvas_interface()->signal_dirty_preview()();
665 if(instance_->group_stack_.empty())
667 instance_->inc_action_count();
668 instance_->signal_new_action()(instance_->undo_action_stack_.front());
671 instance_->group_stack_.front()->inc_depth();
674 if(0)if(redraw_requested_)
676 if(instance_->group_stack_.empty())
678 assert(canvas_interface_);
680 canvas_interface_->signal_dirty_preview()();
684 instance_->group_stack_.front()->request_redraw(canvas_interface_);
685 redraw_requested_=false;
691 Action::PassiveGrouper::cancel()
695 // Cancel any groupers that may be on top of us first
696 //while(instance_->group_stack_.front()!=this)
697 // instance_->group_stack_.front()->cancel();
699 synfig::warning("Cancel depth: %d",depth_);
702 if(!instance_->undo())
709 instance_->get_ui_interface()->error(_("State restore failure"));
711 redraw_requested_=false;