Blame synfig-studio/src/synfigapp/action_system.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file action_system.cpp
Carlos Lopez a09598
**	\brief Template File
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
*/
Carlos Lopez a09598
/* ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
bw 94d8a6
#include <synfig general.h=""></synfig>
bw 94d8a6
Carlos Lopez a09598
#include "action_system.h"
Carlos Lopez a09598
#include "instance.h"
Carlos Lopez a09598
#include "canvasinterface.h"
Carlos Lopez a09598
abdbf2
#include <synfigapp localization.h=""></synfigapp>
Carlos Lopez a09598
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
/* === U S I N G =========================================================== */
Carlos Lopez a09598
Carlos Lopez a09598
using namespace synfig;
65f7fd
using namespace synfigapp;
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === P R O C E D U R E S ================================================= */
Carlos Lopez a09598
65f7fd
namespace {
65f7fd
	class Lock {
65f7fd
	private:
65f7fd
		int &counter;
65f7fd
	public:
65f7fd
		Lock(int &counter): counter(counter) { ++counter; }
65f7fd
		~Lock() { --counter; }
65f7fd
	};
65f7fd
}
Carlos Lopez a09598
65f7fd
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Action::System::System():
Carlos Lopez a09598
	action_count_(0)
Carlos Lopez a09598
{
Carlos Lopez a09598
	unset_ui_interface();
Carlos Lopez a09598
	clear_redo_stack_on_new_action_=false;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Action::System::~System()
65f7fd
	{ }
65f7fd
65f7fd
void
65f7fd
Action::System::request_redraw(etl::handle<canvasinterface> x)</canvasinterface>
Carlos Lopez a09598
{
65f7fd
	if (!x) return;
65f7fd
	if (!group_stack_.empty())
65f7fd
		{ group_stack_.front()->request_redraw(x); return; }
65f7fd
	x->signal_dirty_preview()();
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
Action::System::perform_action(etl::handle<action::base> action)</action::base>
Carlos Lopez a09598
{
65f7fd
	assert(action);
Nikita Kitaev dc5e35
	if (getenv("SYNFIG_DEBUG_ACTIONS"))
Nikita Kitaev dc5e35
		synfig::info("%s:%d perform_action: '%s'", __FILE__, __LINE__, action->get_name().c_str());
Carlos Lopez a09598
65f7fd
	etl::handle<uiinterface> uim = get_ui_interface();</uiinterface>
65f7fd
	if (!action->is_ready()) {
Carlos Lopez a09598
		uim->error(action->get_local_name()+": "+_("Action is not ready."));
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
65f7fd
	most_recent_action_name_ = action->get_name();
Carlos Lopez a09598
65f7fd
	static int inuse = 0;
65f7fd
	if (inuse) return false;
65f7fd
	Lock lock(inuse);
Carlos Lopez a09598
65f7fd
	Action::CanvasSpecific *canvas_specific = dynamic_cast<action::canvasspecific*>(action.get());</action::canvasspecific*>
Carlos Lopez a09598
65f7fd
	if (canvas_specific && canvas_specific->get_canvas())
65f7fd
		uim = static_cast<instance*>(this)->find_canvas_interface(canvas_specific->get_canvas())->get_ui_interface();</instance*>
Carlos Lopez a09598
Carlos Lopez a09598
	// If we cannot undo this action, make sure
Carlos Lopez a09598
	// that the user knows this.
65f7fd
	etl::handle<action::undoable> undoable_action = etl::handle<action::undoable>::cast_dynamic(action);</action::undoable></action::undoable>
65f7fd
	assert(!undoable_action || undoable_action->is_active());
65f7fd
	if (!undoable_action) {
65f7fd
		String message = etl::strprintf(_("Do you want to do action \"%s\"?"), action->get_local_name().c_str());
65f7fd
		String details = _("This action cannot be undone.");
65f7fd
		UIInterface::Response response = uim->confirmation(
Yu Chen 4ca051
			message,
Yu Chen 4ca051
			details,
Yu Chen 4ca051
			_("Cancel"),
Yu Chen 4ca051
			_("Continue"),
65f7fd
			UIInterface::RESPONSE_CANCEL );
65f7fd
		if (response == UIInterface::RESPONSE_CANCEL)
Carlos Lopez a09598
			return false;
65f7fd
		// Because this action cannot be undone,
65f7fd
		// we need to clear the undo stack
65f7fd
		clear_undo_stack();
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	// Perform the action
Carlos Lopez a09598
	try { action->perform(); }
b1afd8
	catch (const Action::Error& err) {
Carlos Lopez a09598
		uim->task(action->get_local_name()+' '+_("Failed"));
65f7fd
		if (err.get_type() != Action::Error::TYPE_UNABLE) {
65f7fd
			if (err.get_desc().empty())
65f7fd
				uim->error(action->get_local_name() + ": " + etl::strprintf("%d", err.get_type()));
Carlos Lopez a09598
			else
65f7fd
				uim->error(action->get_local_name() + ": " + err.get_desc());
Carlos Lopez a09598
		}
Carlos Lopez a09598
		// If action failed for whatever reason, just return false and do
Carlos Lopez a09598
		// not add the action onto the list
Carlos Lopez a09598
		return false;
b1afd8
	} catch (std::exception& err) {
4a958f
		uim->task(action->get_local_name() + ' ' + _("Failed"));
4a958f
		uim->error(action->get_local_name() + ": " + err.what());
Carlos Lopez a09598
		// If action failed for whatever reason, just return false and do
Carlos Lopez a09598
		// not add the action onto the list
Carlos Lopez a09598
		return false;
65f7fd
	} catch(...) {
4a958f
		uim->task(action->get_local_name() + ' ' + _("Failed"));
Carlos Lopez a09598
		// If action failed for whatever reason, just return false and do
Carlos Lopez a09598
		// not add the action onto the list
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	// Clear the redo stack
65f7fd
	if (clear_redo_stack_on_new_action_)
Carlos Lopez a09598
		clear_redo_stack();
Carlos Lopez a09598
65f7fd
	if (!group_stack_.empty())
Carlos Lopez a09598
		group_stack_.front()->inc_depth();
Carlos Lopez a09598
	else
Carlos Lopez a09598
		inc_action_count();
Carlos Lopez a09598
Carlos Lopez a09598
	// Push this action onto the action list if we can undo it
65f7fd
	if (undoable_action) {
Carlos Lopez a09598
		// If necessary, signal the change in status of undo
Carlos Lopez a09598
		if(undo_action_stack_.empty()) signal_undo_status_(true);
Carlos Lopez a09598
Carlos Lopez a09598
		// Add it to the list
Carlos Lopez a09598
		undo_action_stack_.push_front(undoable_action);
Carlos Lopez a09598
Carlos Lopez a09598
		// Signal that a new action has been added
Carlos Lopez a09598
		if(group_stack_.empty())
Carlos Lopez a09598
			signal_new_action()(undoable_action);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	uim->task(action->get_local_name()+' '+_("Successful"));
Carlos Lopez a09598
Carlos Lopez a09598
	// If the action has "dirtied" the preview, signal it.
65f7fd
	if (canvas_specific && canvas_specific->is_dirty())
65f7fd
		request_redraw(canvas_specific->get_canvas_interface());
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
synfigapp::Action::System::undo_(etl::handle<uiinterface> uim)</uiinterface>
Carlos Lopez a09598
{
65f7fd
	etl::handle<action::undoable> action = undo_action_stack().front();</action::undoable>
65f7fd
	most_recent_action_name_ = action->get_name();
65f7fd
65f7fd
	try { if (action->is_active()) action->undo(); }
65f7fd
	catch (Action::Error &err) {
65f7fd
		if(err.get_type() != Action::Error::TYPE_UNABLE) {
Carlos Lopez a09598
			if(err.get_desc().empty())
65f7fd
				uim->error(action->get_local_name() + _(" (Undo): ") + etl::strprintf("%d",err.get_type()));
Carlos Lopez a09598
			else
65f7fd
				uim->error(action->get_local_name() + _(" (Undo): ") + err.get_desc());
Carlos Lopez a09598
		}
Carlos Lopez a09598
		return false;
65f7fd
	} catch (std::runtime_error &x) {
Carlos Lopez a09598
		uim->error(x.what());
Carlos Lopez a09598
		return false;
65f7fd
	} catch (...) {
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	dec_action_count();
Carlos Lopez a09598
65f7fd
	if (redo_action_stack_.empty()) signal_redo_status()(true);
Carlos Lopez a09598
Carlos Lopez a09598
	redo_action_stack_.push_front(undo_action_stack_.front());
Carlos Lopez a09598
	undo_action_stack_.pop_front();
Carlos Lopez a09598
65f7fd
	if (undo_action_stack_.empty()) signal_undo_status()(false);
Carlos Lopez a09598
65f7fd
	if (!group_stack_.empty())
Carlos Lopez a09598
		group_stack_.front()->dec_depth();
Carlos Lopez a09598
Carlos Lopez a09598
	signal_undo_();
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
synfigapp::Action::System::undo()
Carlos Lopez a09598
{
65f7fd
	static int inuse = 0;
65f7fd
	if (inuse) return false;
65f7fd
	Lock lock(inuse);
Carlos Lopez a09598
Carlos Lopez a09598
	// If there is nothing on the action list, there is nothing to undo
65f7fd
	if (undo_action_stack().empty())
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
65f7fd
	etl::handle<action::undoable> action = undo_action_stack().front();</action::undoable>
65f7fd
	Action::CanvasSpecific *canvas_specific = dynamic_cast<action::canvasspecific*>(action.get());</action::canvasspecific*>
Carlos Lopez a09598
65f7fd
	etl::handle<uiinterface> uim = get_ui_interface();</uiinterface>
65f7fd
	if (canvas_specific && canvas_specific->get_canvas())
65f7fd
		uim = static_cast<instance*>(this)->find_canvas_interface(canvas_specific->get_canvas())->get_ui_interface();</instance*>
Carlos Lopez a09598
65f7fd
	if (!undo_(uim)) {
Carlos Lopez a09598
		uim->error(undo_action_stack_.front()->get_local_name()+": "+_("Failed to undo."));
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	// If the action has "dirtied" the preview, signal it.
65f7fd
	if(action->is_active() && canvas_specific && canvas_specific->is_dirty())
65f7fd
		request_redraw(canvas_specific->get_canvas_interface());
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
Action::System::redo_(etl::handle<uiinterface> uim)</uiinterface>
Carlos Lopez a09598
{
65f7fd
	etl::handle<action::undoable> action = redo_action_stack().front();</action::undoable>
65f7fd
	most_recent_action_name_ = action->get_name();
Carlos Lopez a09598
Carlos Lopez a09598
	try { if(action->is_active()) action->perform(); }
b1afd8
	catch (const Action::Error& err) {
65f7fd
		if (err.get_type() != Action::Error::TYPE_UNABLE) {
Carlos Lopez a09598
			if(err.get_desc().empty())
65f7fd
				uim->error(action->get_local_name() + _(" (Redo): ") + etl::strprintf("%d", err.get_type()));
Carlos Lopez a09598
			else
65f7fd
				uim->error(action->get_local_name() + _(" (Redo): ") + err.get_desc());
Carlos Lopez a09598
		}
Carlos Lopez a09598
		return false;
b1afd8
	} catch (const std::runtime_error &x) {
Carlos Lopez a09598
		uim->error(x.what());
Carlos Lopez a09598
		return false;
65f7fd
	} catch(...) {
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	inc_action_count();
Carlos Lopez a09598
65f7fd
	if (undo_action_stack_.empty()) signal_undo_status()(true);
Carlos Lopez a09598
Carlos Lopez a09598
	undo_action_stack_.push_front(redo_action_stack_.front());
Carlos Lopez a09598
	redo_action_stack_.pop_front();
Carlos Lopez a09598
65f7fd
	if (redo_action_stack_.empty()) signal_redo_status()(false);
Carlos Lopez a09598
Carlos Lopez a09598
	if(!group_stack_.empty())
Carlos Lopez a09598
		group_stack_.front()->inc_depth();
Carlos Lopez a09598
Carlos Lopez a09598
	signal_redo_();
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
Action::System::redo()
Carlos Lopez a09598
{
65f7fd
	static int inuse = 0;
65f7fd
	if (inuse) return false;
65f7fd
	Lock lock(inuse);
Carlos Lopez a09598
Carlos Lopez a09598
	// If there is nothing on the action list, there is nothing to undo
65f7fd
	if (redo_action_stack_.empty())
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
65f7fd
	etl::handle<action::undoable> action = redo_action_stack().front();</action::undoable>
65f7fd
	Action::CanvasSpecific *canvas_specific = dynamic_cast<action::canvasspecific*>(action.get());</action::canvasspecific*>
Carlos Lopez a09598
65f7fd
	etl::handle<uiinterface> uim = get_ui_interface();</uiinterface>
65f7fd
	if (canvas_specific && canvas_specific->get_canvas())
65f7fd
		uim = static_cast<instance*>(this)->find_canvas_interface(canvas_specific->get_canvas())->get_ui_interface();</instance*>
Carlos Lopez a09598
65f7fd
	if (!redo_(uim)) {
Carlos Lopez a09598
		uim->error(redo_action_stack_.front()->get_local_name()+": "+_("Failed to redo."));
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	// If the action has "dirtied" the preview, signal it.
65f7fd
	if (action->is_active() && canvas_specific && canvas_specific->is_dirty())
65f7fd
		request_redraw(canvas_specific->get_canvas_interface());
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
65f7fd
Action::System::inc_action_count() const
Carlos Lopez a09598
{
Carlos Lopez a09598
	action_count_++;
65f7fd
	if (action_count_ == 1)
Carlos Lopez a09598
		signal_unsaved_status_changed_(true);
65f7fd
	if (!action_count_)
Carlos Lopez a09598
		signal_unsaved_status_changed_(false);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
65f7fd
Action::System::dec_action_count() const
Carlos Lopez a09598
{
Carlos Lopez a09598
	action_count_--;
Carlos Lopez a09598
	if(action_count_==-1)
Carlos Lopez a09598
		signal_unsaved_status_changed_(true);
Carlos Lopez a09598
	if(!action_count_)
Carlos Lopez a09598
		signal_unsaved_status_changed_(false);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
65f7fd
Action::System::reset_action_count() const
Carlos Lopez a09598
{
65f7fd
	if (!action_count_)
Carlos Lopez a09598
		return;
65f7fd
	action_count_ = 0;
Carlos Lopez a09598
	signal_unsaved_status_changed_(false);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Action::System::clear_undo_stack()
Carlos Lopez a09598
{
65f7fd
	if (undo_action_stack_.empty()) return;
Carlos Lopez a09598
	undo_action_stack_.clear();
Carlos Lopez a09598
	signal_undo_status_(false);
Carlos Lopez a09598
	signal_undo_stack_cleared_();
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Action::System::clear_redo_stack()
Carlos Lopez a09598
{
65f7fd
	if (redo_action_stack_.empty()) return;
Carlos Lopez a09598
	redo_action_stack_.clear();
Carlos Lopez a09598
	signal_redo_status_(false);
Carlos Lopez a09598
	signal_redo_stack_cleared_();
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
Action::System::set_action_status(etl::handle<action::undoable> action, bool x)</action::undoable>
Carlos Lopez a09598
{
65f7fd
	if (action->is_active() == x)
Carlos Lopez a09598
		return true;
Carlos Lopez a09598
65f7fd
	etl::handle<action::undoable> cur_pos = undo_action_stack_.front();</action::undoable>
65f7fd
	Action::CanvasSpecific *canvas_specific = dynamic_cast<action::canvasspecific*>(action.get());</action::canvasspecific*>
Carlos Lopez a09598
65f7fd
	etl::handle<uiinterface> uim = new ConfidentUIInterface();</uiinterface>
Carlos Lopez a09598
65f7fd
	Stack::iterator iter = std::find(undo_action_stack_.begin(), undo_action_stack_.end(), action);
65f7fd
	if (iter != undo_action_stack_.end()) {
65f7fd
		while(undo_action_stack_.front() != action)
65f7fd
			if (!undo_(uim)) return false;
65f7fd
		if (!undo_(uim)) return false;
Carlos Lopez a09598
Carlos Lopez a09598
		action->set_active(x);
Carlos Lopez a09598
65f7fd
		bool success = redo_(get_ui_interface());
65f7fd
		if (success)
Carlos Lopez a09598
			signal_action_status_changed_(action);
Carlos Lopez a09598
		else
Carlos Lopez a09598
			action->set_active(!x);
Carlos Lopez a09598
65f7fd
		while(undo_action_stack_.front() != cur_pos)
65f7fd
			if (!redo_(uim)) {
Carlos Lopez a09598
				redo_action_stack_.front()->set_active(false);
Carlos Lopez a09598
				signal_action_status_changed_(redo_action_stack_.front());
Carlos Lopez a09598
			}
Carlos Lopez a09598
65f7fd
		if (success && canvas_specific && canvas_specific->is_dirty())
65f7fd
			request_redraw(canvas_specific->get_canvas_interface());
Carlos Lopez a09598
Carlos Lopez a09598
		return true;
Carlos Lopez a09598
	}
Carlos Lopez a09598
65f7fd
	iter = std::find(redo_action_stack_.begin(), redo_action_stack_.end(), action);
65f7fd
	if (iter!=redo_action_stack_.end()) {
Carlos Lopez a09598
		action->set_active(x);
Carlos Lopez a09598
		signal_action_status_changed_(action);
65f7fd
		if (canvas_specific && canvas_specific->is_dirty())
65f7fd
			request_redraw(canvas_specific->get_canvas_interface());
Carlos Lopez a09598
		return true;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	return false;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Action::PassiveGrouper::PassiveGrouper(etl::loose_handle<system> instance_,synfig::String name_):</system>
Carlos Lopez a09598
	instance_(instance_),
Carlos Lopez a09598
	name_(name_),
0bd937
	depth_(0),
0bd937
	finished_(false)
Carlos Lopez a09598
{
Carlos Lopez a09598
	// Add this group onto the group stack
Carlos Lopez a09598
	instance_->group_stack_.push_front(this);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Action::PassiveGrouper::request_redraw(etl::handle<canvasinterface> x)</canvasinterface>
65f7fd
	{ if (x) redraw_set_.insert(x); }
Carlos Lopez a09598
Carlos Lopez a09598
Action::PassiveGrouper::~PassiveGrouper()
0bd937
	{ if (!finished_) finish(); }
0bd937
0bd937
etl::handle<action::group></action::group>
0bd937
Action::PassiveGrouper::finish()
Carlos Lopez a09598
{
0bd937
	assert(!finished_);
0bd937
	if (finished_) return etl::handle<action::group>();</action::group>
0bd937
	finished_ = true;
0bd937
Carlos Lopez a09598
	// Remove this group from the group stack
65f7fd
	assert(instance_->group_stack_.front() == this);
Carlos Lopez a09598
	instance_->group_stack_.pop_front();
Carlos Lopez a09598
65f7fd
	etl::handle<action::group> group;</action::group>
65f7fd
	if (depth_ == 1) {
65f7fd
		etl::handle<action::undoable> action = instance_->undo_action_stack_.front();</action::undoable>
65f7fd
		group = etl::handle<action::group>::cast_dynamic(action);</action::group>
65f7fd
		if (group) {
Carlos Lopez a09598
			// If the only action inside of us is a group,
Carlos Lopez a09598
			// then we should rename the group to our name.
Carlos Lopez a09598
			group->set_name(name_);
65f7fd
		} else
65f7fd
		if (Action::CanvasSpecific* canvas_specific = dynamic_cast<action::canvasspecific*>(action.get()))</action::canvasspecific*>
65f7fd
			if (canvas_specific->is_dirty() && canvas_specific->get_canvas_interface())
65f7fd
				if (instance_->group_stack_.empty())
Carlos Lopez a09598
					request_redraw(canvas_specific->get_canvas_interface());
Carlos Lopez a09598
65f7fd
		if (instance_->group_stack_.empty()) {
Carlos Lopez a09598
			instance_->inc_action_count();
Carlos Lopez a09598
			instance_->signal_new_action()(instance_->undo_action_stack_.front());
65f7fd
		} else
Carlos Lopez a09598
			instance_->group_stack_.front()->inc_depth();
65f7fd
	} else
65f7fd
	if (depth_ > 1) {
65f7fd
		group = new Action::Group(name_);
Carlos Lopez a09598
65f7fd
		for(int i=0; i < depth_; i++) {
65f7fd
			etl::handle<action::undoable> action = instance_->undo_action_stack_.front();</action::undoable>
65f7fd
65f7fd
			if (Action::CanvasSpecific* canvas_specific = dynamic_cast<action::canvasspecific*>(action.get()))</action::canvasspecific*>
65f7fd
				if (canvas_specific->is_dirty()) {
65f7fd
					group->set_dirty(true);
65f7fd
					group->set_canvas(canvas_specific->get_canvas());
65f7fd
					group->set_canvas_interface(canvas_specific->get_canvas_interface());
65f7fd
				}
Carlos Lopez a09598
Carlos Lopez a09598
			// Copy the action from the undo stack to the group
Carlos Lopez a09598
			group->add_action_front(action);
Carlos Lopez a09598
Carlos Lopez a09598
			// Remove the action from the undo stack
Carlos Lopez a09598
			instance_->undo_action_stack_.pop_front();
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
		// Push the group onto the stack
Carlos Lopez a09598
		instance_->undo_action_stack_.push_front(group);
Carlos Lopez a09598
65f7fd
		if(group->is_dirty())
Carlos Lopez a09598
			request_redraw(group->get_canvas_interface());
Carlos Lopez a09598
65f7fd
		if(instance_->group_stack_.empty()) {
Carlos Lopez a09598
			instance_->inc_action_count();
Carlos Lopez a09598
			instance_->signal_new_action()(instance_->undo_action_stack_.front());
65f7fd
		} else
Carlos Lopez a09598
			instance_->group_stack_.front()->inc_depth();
Carlos Lopez a09598
	}
Carlos Lopez a09598
65f7fd
	// redraw request
65f7fd
	for(RedrawSet::const_iterator i = redraw_set_.begin(); i != redraw_set_.end(); ++i)
65f7fd
		instance_->request_redraw(*i);
65f7fd
	redraw_set_.clear();
0bd937
0bd937
	return group;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Action::PassiveGrouper::cancel()
Carlos Lopez a09598
{
0bd937
	assert(!finished_);
0bd937
	if (finished_) return;
0bd937
Carlos Lopez a09598
	// Cancel any groupers that may be on top of us first
Carlos Lopez a09598
	//while(instance_->group_stack_.front()!=this)
Carlos Lopez a09598
	//	instance_->group_stack_.front()->cancel();
Carlos Lopez a09598
	synfig::warning("Cancel depth: %d",depth_);
Carlos Lopez a09598
65f7fd
	bool success = true;
65f7fd
	while(success && depth_)
65f7fd
		if (!instance_->undo())
65f7fd
			success = false;
Carlos Lopez a09598
65f7fd
	if (success)
65f7fd
		redraw_set_.clear();
Carlos Lopez a09598
	else
65f7fd
		instance_->get_ui_interface()->error(_("State restore failure"));
Carlos Lopez a09598
}