+++ /dev/null
-/* === S Y N F I G ========================================================= */
-/*! \file action_system.cpp
-** \brief Template File
-**
-** $Id: action_system.cpp,v 1.1.1.1 2005/01/07 03:34:37 darco Exp $
-**
-** \legal
-** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-**
-** This package is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License as
-** published by the Free Software Foundation; either version 2 of
-** the License, or (at your option) any later version.
-**
-** This package is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** General Public License for more details.
-** \endlegal
-*/
-/* ========================================================================= */
-
-/* === H E A D E R S ======================================================= */
-
-#ifdef USING_PCH
-# include "pch.h"
-#else
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "action_system.h"
-#include "instance.h"
-#include "canvasinterface.h"
-
-#endif
-
-/* === U S I N G =========================================================== */
-
-using namespace std;
-using namespace etl;
-using namespace synfigapp;
-using namespace synfig;
-
-/* === M A C R O S ========================================================= */
-
-/* === G L O B A L S ======================================================= */
-
-/* === P R O C E D U R E S ================================================= */
-
-/* === M E T H O D S ======================================================= */
-
-
-
-Action::System::System():
- action_count_(0)
-{
- unset_ui_interface();
- clear_redo_stack_on_new_action_=false;
-}
-
-Action::System::~System()
-{
-}
-
-bool
-Action::System::perform_action(handle<Action::Base> action)
-{
- handle<UIInterface> uim(get_ui_interface());
-
- assert(action);
-
- if(!action->is_ready())
- {
- uim->error(action->get_name()+": "+_("Action is not ready."));
- return false;
- }
-
- most_recent_action_=action;
-
- static bool inuse=false;
-
- if(inuse) return false;
-
- inuse=true;
- try {
-
- assert(action);
-
- Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
-
- if(canvas_specific && canvas_specific->get_canvas())
- {
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas_specific->get_canvas());
- assert(canvas_interface);
- uim=canvas_interface->get_ui_interface();
- }
-
- handle<Action::Undoable> undoable_action=handle<Action::Undoable>::cast_dynamic(action);
-
- // If we cannot undo this action, make sure
- // that the user knows this.
- if(!undoable_action)
- {
- if(uim->yes_no(
- action->get_name(),
- _("This action cannot be undone! Are you sure you want to continue?"),
- UIInterface::RESPONSE_NO
- ) == UIInterface::RESPONSE_NO
- )
- return false;
- else
- {
- // Because this action cannot be undone,
- // we need to clear the undo stack
- clear_undo_stack();
- }
- }
- else
- assert(undoable_action->is_active());
-
- // Perform the action
- try { action->perform(); }
- catch(Action::Error err)
- {
- uim->task(action->get_name()+' '+_("Failed"));
- inuse=false;
-
- if(err.get_type()!=Action::Error::TYPE_UNABLE)
- {
- if(err.get_desc().empty())
- uim->error(action->get_name()+": "+strprintf("%d",err.get_type()));
- else
- uim->error(action->get_name()+": "+err.get_desc());
- }
-
- // If action failed for whatever reason, just return false and do
- // not add the action onto the list
- return false;
- }
- catch(std::exception err)
- {
- uim->task(action->get_name()+' '+_("Failed"));
- inuse=false;
-
- uim->error(action->get_name()+": "+err.what());
-
- // If action failed for whatever reason, just return false and do
- // not add the action onto the list
- return false;
- }
- catch(...)
- {
- uim->task(action->get_name()+' '+_("Failed"));
- inuse=false;
-
- // If action failed for whatever reason, just return false and do
- // not add the action onto the list
- return false;
- }
-
- // Clear the redo stack
- if(clear_redo_stack_on_new_action_)
- clear_redo_stack();
-
- if(!group_stack_.empty())
- group_stack_.front()->inc_depth();
- else
- inc_action_count();
-
- // Push this action onto the action list if we can undo it
- if(undoable_action)
- {
- // If necessary, signal the change in status of undo
- if(undo_action_stack_.empty()) signal_undo_status_(true);
-
- // Add it to the list
- undo_action_stack_.push_front(undoable_action);
-
- // Signal that a new action has been added
- if(group_stack_.empty())
- signal_new_action()(undoable_action);
- }
-
- inuse=false;
-
- uim->task(action->get_name()+' '+_("Successful"));
-
- // If the action has "dirtied" the preview, signal it.
- if(0)if(canvas_specific && canvas_specific->is_dirty())
- {
- Canvas::Handle canvas=canvas_specific->get_canvas();
- if(!group_stack_.empty())
- group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
- else
- {
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
- assert(canvas_interface);
- DEBUGPOINT();
- //canvas_interface->signal_dirty_preview()();
- }
- }
-
- }catch(...) { inuse=false; throw; }
-
- return true;
-}
-
-bool
-synfigapp::Action::System::undo_(handle<UIInterface> uim)
-{
- handle<Action::Undoable> action(undo_action_stack().front());
- most_recent_action_=action;
-
- try { if(action->is_active()) action->undo(); }
- catch(Action::Error err)
- {
- if(err.get_type()!=Action::Error::TYPE_UNABLE)
- {
- if(err.get_desc().empty())
- uim->error(action->get_name()+_(" (Undo): ")+strprintf("%d",err.get_type()));
- else
- uim->error(action->get_name()+_(" (Undo): ")+err.get_desc());
- }
-
- return false;
- }
- catch(std::runtime_error x)
- {
- uim->error(x.what());
- return false;
- }
- catch(...)
- {
- return false;
- }
-
- dec_action_count();
-
- if(redo_action_stack_.empty()) signal_redo_status()(true);
-
- redo_action_stack_.push_front(undo_action_stack_.front());
- undo_action_stack_.pop_front();
-
- if(undo_action_stack_.empty()) signal_undo_status()(false);
-
- if(!group_stack_.empty())
- group_stack_.front()->dec_depth();
-
- signal_undo_();
-
- return true;
-}
-
-bool
-synfigapp::Action::System::undo()
-{
- //! \todo This function is not exception safe!
- static bool inuse=false;
-
- // If there is nothing on the action list, there is nothing to undo
- if(undo_action_stack().empty() || inuse)
- return false;
-
- handle<Action::Undoable> action=undo_action_stack().front();
- Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
-
- handle<UIInterface> uim;
- if(canvas_specific && canvas_specific->get_canvas())
- {
- Canvas::Handle canvas=canvas_specific->get_canvas();
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
- assert(canvas_interface);
- uim=canvas_interface->get_ui_interface();
- }
- else
- uim=get_ui_interface();
-
- inuse=true;
-
- if(!undo_(uim))
- {
- uim->error(undo_action_stack_.front()->get_name()+": "+_("Failed to undo."));
- inuse=false;
- return false;
- }
-
- inuse=false;
-
- // If the action has "dirtied" the preview, signal it.
- if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
- {
- Canvas::Handle canvas=canvas_specific->get_canvas();
- if(!group_stack_.empty())
- group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
- else
- {
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
- assert(canvas_interface);
- //DEBUGPOINT();
- //canvas_interface->signal_dirty_preview()();
- }
- }
-
- return true;
-}
-
-bool
-Action::System::redo_(handle<UIInterface> uim)
-{
- handle<Action::Undoable> action(redo_action_stack().front());
- most_recent_action_=action;
-
- try { if(action->is_active()) action->perform(); }
- catch(Action::Error err)
- {
- if(err.get_type()!=Action::Error::TYPE_UNABLE)
- {
- if(err.get_desc().empty())
- uim->error(action->get_name()+_(" (Redo): ")+strprintf("%d",err.get_type()));
- else
- uim->error(action->get_name()+_(" (Redo): ")+err.get_desc());
- }
-
- return false;
- }
- catch(std::runtime_error x)
- {
- uim->error(x.what());
- return false;
- }
- catch(...)
- {
- return false;
- }
-
- inc_action_count();
-
- if(undo_action_stack_.empty()) signal_undo_status()(true);
-
- undo_action_stack_.push_front(redo_action_stack_.front());
- redo_action_stack_.pop_front();
-
- if(redo_action_stack_.empty()) signal_redo_status()(false);
-
- if(!group_stack_.empty())
- group_stack_.front()->inc_depth();
-
- signal_redo_();
-
- return true;
-}
-
-bool
-Action::System::redo()
-{
- //! \todo This function is not exception safe!
- static bool inuse=false;
-
- // If there is nothing on the action list, there is nothing to undo
- if(redo_action_stack_.empty() || inuse)
- return false;
-
- inuse=true;
-
- handle<Action::Undoable> action=redo_action_stack().front();
- Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
-
- handle<UIInterface> uim;
- if(canvas_specific && canvas_specific->get_canvas())
- {
- Canvas::Handle canvas=canvas_specific->get_canvas();
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
- assert(canvas_interface);
- uim=canvas_interface->get_ui_interface();
- }
- else
- uim=get_ui_interface();
-
- if(!redo_(uim))
- {
- uim->error(redo_action_stack_.front()->get_name()+": "+_("Failed to redo."));
- inuse=false;
- return false;
- }
-
- inuse=false;
-
- // If the action has "dirtied" the preview, signal it.
- if(0)if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
- {
- Canvas::Handle canvas=canvas_specific->get_canvas();
- if(!group_stack_.empty())
- group_stack_.front()->request_redraw(canvas_specific->get_canvas_interface());
- else
- {
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
- assert(canvas_interface);
- //DEBUGPOINT();
- //canvas_interface->signal_dirty_preview()();
- }
- }
-
- return true;
-}
-
-void
-Action::System::inc_action_count()const
-{
- action_count_++;
- if(action_count_==1)
- signal_unsaved_status_changed_(true);
- if(!action_count_)
- signal_unsaved_status_changed_(false);
-}
-
-void
-Action::System::dec_action_count()const
-{
- action_count_--;
- if(action_count_==-1)
- signal_unsaved_status_changed_(true);
- if(!action_count_)
- signal_unsaved_status_changed_(false);
-}
-
-void
-Action::System::reset_action_count()const
-{
- if(!action_count_)
- return;
-
- action_count_=0;
- signal_unsaved_status_changed_(false);
-}
-
-void
-Action::System::clear_undo_stack()
-{
- if(undo_action_stack_.empty()) return;
- undo_action_stack_.clear();
- signal_undo_status_(false);
- signal_undo_stack_cleared_();
-}
-
-void
-Action::System::clear_redo_stack()
-{
- if(redo_action_stack_.empty()) return;
- redo_action_stack_.clear();
- signal_redo_status_(false);
- signal_redo_stack_cleared_();
-}
-
-bool
-Action::System::set_action_status(etl::handle<Action::Undoable> action, bool x)
-{
- Stack::iterator iter;
- int failed=false;
-
- if(action->is_active()==x)
- return true;
-
- handle<Action::Undoable> cur_pos=undo_action_stack_.front();
-
- Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
-
- handle<UIInterface> uim=new ConfidentUIInterface();
-
- iter=find(undo_action_stack_.begin(),undo_action_stack_.end(),action);
- if(iter!=undo_action_stack_.end())
- {
- while(undo_action_stack_.front()!=action)
- {
- if(!undo_(uim))
- {
- return false;
- }
- }
- if(!undo_(uim))
- {
- return false;
- }
-
- action->set_active(x);
-
- if(redo_(get_ui_interface()))
- {
- signal_action_status_changed_(action);
- }
- else
- {
- action->set_active(!x);
- failed=true;
- }
-
-
- while(undo_action_stack_.front()!=cur_pos)
- {
- if(!redo_(uim))
- {
- redo_action_stack_.front()->set_active(false);
- signal_action_status_changed_(redo_action_stack_.front());
- }
- }
-
- if(!failed && canvas_specific && canvas_specific->is_dirty())
- {
- Canvas::Handle canvas=canvas_specific->get_canvas();
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
- assert(canvas_interface);
- //DEBUGPOINT();
- //canvas_interface->signal_dirty_preview()();
- }
-
- return true;
- }
-
- iter=find(redo_action_stack_.begin(),redo_action_stack_.end(),action);
- if(iter!=redo_action_stack_.end())
- {
- action->set_active(x);
- signal_action_status_changed_(action);
-
-
-
-
- if(canvas_specific && canvas_specific->is_dirty())
- {
- Canvas::Handle canvas=canvas_specific->get_canvas();
- handle<CanvasInterface> canvas_interface=static_cast<Instance*>(this)->find_canvas_interface(canvas);
- assert(canvas_interface);
- DEBUGPOINT();
- //canvas_interface->signal_dirty_preview()();
- }
-
- return true;
- }
-
- return false;
-}
-
-Action::PassiveGrouper::PassiveGrouper(etl::loose_handle<Action::System> instance_,synfig::String name_):
- instance_(instance_),
- name_(name_),
- redraw_requested_(false),
- depth_(0)
-{
- // Add this group onto the group stack
- instance_->group_stack_.push_front(this);
-}
-
-void
-Action::PassiveGrouper::request_redraw(handle<CanvasInterface> x)
-{
-/* DEBUGPOINT();
- if(instance_->group_stack_.empty())
- {
- if(x!=canvas_interface_)
- {
- DEBUGPOINT();
- x->signal_dirty_preview()();
- }
-
- redraw_requested_=false;
- }
- else
- {
- DEBUGPOINT();
- if(instance_->group_stack_.back()==this)
- {
- DEBUGPOINT();
- redraw_requested_=true;
- }
- else
- {
- DEBUGPOINT();
- instance_->group_stack_.back()->request_redraw(x);
- redraw_requested_=false;
- }
- DEBUGPOINT();
- }
- DEBUGPOINT();
-*/
- if(x)
- {
- redraw_requested_=true;
- canvas_interface_=x;
- }
-}
-
-Action::PassiveGrouper::~PassiveGrouper()
-{
- assert(instance_->group_stack_.front()==this);
-
- // Remove this group from the group stack
- instance_->group_stack_.pop_front();
-
- handle<Action::Group> group;
-
- if(depth_==1)
- {
- handle<Action::Undoable> action(instance_->undo_action_stack_.front());
-
- group=handle<Action::Group>::cast_dynamic(action);
-
- if(group)
- {
- // If the only action inside of us is a group,
- // then we should rename the group to our name.
- group->set_name(name_);
- }
- else
- {
- Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
-
- if(0)if(canvas_specific && canvas_specific->is_dirty() && canvas_specific->get_canvas_interface())
- {
- if(instance_->group_stack_.empty())
- request_redraw(canvas_specific->get_canvas_interface());
- }
- }
-
- if(instance_->group_stack_.empty())
- {
- instance_->inc_action_count();
- instance_->signal_new_action()(instance_->undo_action_stack_.front());
- }
- else
- instance_->group_stack_.front()->inc_depth();
-
- }
- else
- if(depth_>0)
- {
- group=new Action::Group(name_);
-
- for(int i=0;i<depth_;i++)
- // for(;depth_;depth_--)
- {
- handle<Action::Undoable> action(instance_->undo_action_stack_.front());
- Action::CanvasSpecific* canvas_specific(dynamic_cast<Action::CanvasSpecific*>(action.get()));
-
- if(0)if(canvas_specific && canvas_specific->is_dirty())
- {
- group->set_dirty(true);
- group->set_canvas(canvas_specific->get_canvas());
- group->set_canvas_interface(canvas_specific->get_canvas_interface());
- }
-
- // Copy the action from the undo stack to the group
- group->add_action_front(action);
-
- // Remove the action from the undo stack
- instance_->undo_action_stack_.pop_front();
- }
-
- // Push the group onto the stack
- instance_->undo_action_stack_.push_front(group);
-
- if(0)if(group->is_dirty())
- request_redraw(group->get_canvas_interface());
- // group->get_canvas_interface()->signal_dirty_preview()();
-
- if(instance_->group_stack_.empty())
- {
- instance_->inc_action_count();
- instance_->signal_new_action()(instance_->undo_action_stack_.front());
- }
- else
- instance_->group_stack_.front()->inc_depth();
- }
-
- if(0)if(redraw_requested_)
- {
- if(instance_->group_stack_.empty())
- {
- assert(canvas_interface_);
- DEBUGPOINT();
- canvas_interface_->signal_dirty_preview()();
- }
- else
- {
- instance_->group_stack_.front()->request_redraw(canvas_interface_);
- redraw_requested_=false;
- }
- }
-}
-
-void
-Action::PassiveGrouper::cancel()
-{
- bool error=false;
-
- // Cancel any groupers that may be on top of us first
- //while(instance_->group_stack_.front()!=this)
- // instance_->group_stack_.front()->cancel();
-
- synfig::warning("Cancel depth: %d",depth_);
-
- while(depth_)
- if(!instance_->undo())
- {
- error=true;
- break;
- }
-
- if(error)
- instance_->get_ui_interface()->error(_("State restore failure"));
- else
- redraw_requested_=false;
-}