184 lines
5.2 KiB
C++
184 lines
5.2 KiB
C++
#include <string>
|
|
#include <vector>
|
|
|
|
#include "pbd/command.h"
|
|
#include "pbd/compose.h"
|
|
#include "pbd/debug.h"
|
|
#include "pbd/error.h"
|
|
#include "pbd/history_owner.h"
|
|
#include "pbd/stateful_diff_command.h"
|
|
#include "pbd/undo.h"
|
|
|
|
using namespace std;
|
|
using namespace PBD;
|
|
|
|
HistoryOwner::HistoryOwner (std::string const & str)
|
|
: _name (str)
|
|
, _current_trans (nullptr)
|
|
{
|
|
}
|
|
|
|
HistoryOwner::~HistoryOwner()
|
|
{
|
|
delete _current_trans;
|
|
}
|
|
|
|
void
|
|
HistoryOwner::add_commands (vector<Command*> const & cmds)
|
|
{
|
|
for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
|
|
add_command (*i);
|
|
}
|
|
}
|
|
|
|
void
|
|
HistoryOwner::add_command (Command* const cmd)
|
|
{
|
|
assert (_current_trans);
|
|
if (!_current_trans) {
|
|
error << "Attempted to add an UNDO command without a current transaction. ignoring command (" << cmd->name() << ")" << endl;
|
|
return;
|
|
}
|
|
DEBUG_TRACE (DEBUG::UndoHistory,
|
|
string_compose ("Current Undo Transaction %1, adding command: %2\n",
|
|
_current_trans->name (),
|
|
cmd->name ()));
|
|
_current_trans->add_command (cmd);
|
|
}
|
|
|
|
PBD::StatefulDiffCommand*
|
|
HistoryOwner::add_stateful_diff_command (std::shared_ptr<PBD::StatefulDestructible> sfd)
|
|
{
|
|
PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
|
|
add_command (cmd);
|
|
return cmd;
|
|
}
|
|
|
|
void
|
|
HistoryOwner::begin_reversible_command (const string& name)
|
|
{
|
|
begin_reversible_command (g_quark_from_string (name.c_str ()));
|
|
}
|
|
|
|
/** Begin a reversible command using a GQuark to identify it.
|
|
* begin_reversible_command() and commit_reversible_command() calls may be nested,
|
|
* but there must be as many begin...()s as there are commit...()s.
|
|
*/
|
|
void
|
|
HistoryOwner::begin_reversible_command (GQuark q)
|
|
{
|
|
if (_current_trans) {
|
|
#ifndef NDEBUG
|
|
cerr << "An UNDO transaction was started while a prior command was underway. Aborting command (" << g_quark_to_string (q) << ") and prior (" << _current_trans->name() << ")" << "\n";
|
|
#else
|
|
PBD::warning << "An UNDO transaction was started while a prior command was underway. Aborting command (" << g_quark_to_string (q) << ") and prior (" << _current_trans->name() << ")" << endmsg;
|
|
#endif
|
|
abort_reversible_command();
|
|
assert (false);
|
|
return;
|
|
}
|
|
|
|
/* If nested begin/commit pairs are used, we create just one UndoTransaction
|
|
to hold all the commands that are committed. This keeps the order of
|
|
commands correct in the history.
|
|
*/
|
|
|
|
if (_current_trans == 0) {
|
|
DEBUG_TRACE (DEBUG::UndoHistory, string_compose ("%2 Begin Reversible Command, new transaction: %1\n", g_quark_to_string (q), _name));
|
|
|
|
/* start a new transaction */
|
|
assert (_current_trans_quarks.empty ());
|
|
_current_trans = new UndoTransaction();
|
|
_current_trans->set_name (g_quark_to_string (q));
|
|
} else {
|
|
DEBUG_TRACE (DEBUG::UndoHistory, string_compose ("%2 Begin Reversible Command, current transaction: %1\n", _current_trans->name (), _name));
|
|
}
|
|
|
|
_current_trans_quarks.push_front (q);
|
|
}
|
|
|
|
void
|
|
HistoryOwner::abort_reversible_command ()
|
|
{
|
|
if (!_current_trans) {
|
|
return;
|
|
}
|
|
DEBUG_TRACE (DEBUG::UndoHistory, string_compose ("%2 Abort Reversible Command: %1\n", _current_trans->name (), _name));
|
|
_current_trans->clear();
|
|
delete _current_trans;
|
|
_current_trans = nullptr;
|
|
_current_trans_quarks.clear();
|
|
}
|
|
|
|
bool
|
|
HistoryOwner::abort_empty_reversible_command ()
|
|
{
|
|
if (!collected_undo_commands ()) {
|
|
abort_reversible_command ();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
HistoryOwner::commit_reversible_command (Command *cmd)
|
|
{
|
|
assert (_current_trans);
|
|
assert (!_current_trans_quarks.empty ());
|
|
if (!_current_trans) {
|
|
return;
|
|
}
|
|
|
|
struct timeval now;
|
|
|
|
if (cmd) {
|
|
DEBUG_TRACE (DEBUG::UndoHistory,
|
|
string_compose ("%3 Current Undo Transaction %1, adding command: %2\n",
|
|
_current_trans->name (),
|
|
cmd->name (), _name));
|
|
_current_trans->add_command (cmd);
|
|
}
|
|
|
|
DEBUG_TRACE (DEBUG::UndoHistory,
|
|
string_compose ("%2 Commit Reversible Command, current transaction: %1\n",
|
|
_current_trans->name (), _name));
|
|
|
|
_current_trans_quarks.pop_front ();
|
|
|
|
if (!_current_trans_quarks.empty ()) {
|
|
DEBUG_TRACE (DEBUG::UndoHistory,
|
|
string_compose ("%2 Commit Reversible Command, transaction is not "
|
|
"top-level, current transaction: %1\n",
|
|
_current_trans->name (), _name));
|
|
/* the transaction we're committing is not the top-level one */
|
|
return;
|
|
}
|
|
|
|
if (_current_trans->empty()) {
|
|
/* no commands were added to the transaction, so just get rid of it */
|
|
DEBUG_TRACE (DEBUG::UndoHistory,
|
|
string_compose ("%2 Commit Reversible Command, No commands were "
|
|
"added to current transaction: %1\n",
|
|
_current_trans->name (), _name));
|
|
delete _current_trans;
|
|
_current_trans = nullptr;
|
|
return;
|
|
}
|
|
|
|
gettimeofday (&now, 0);
|
|
_current_trans->set_timestamp (now);
|
|
|
|
DEBUG_TRACE (DEBUG::UndoHistory,
|
|
string_compose ("%2 Commit Reversible Command, add to history %1\n",
|
|
_current_trans->name (), _name));
|
|
_history.add (_current_trans);
|
|
_current_trans = nullptr;
|
|
}
|
|
|
|
bool
|
|
HistoryOwner::operation_in_progress (GQuark op) const
|
|
{
|
|
return (find (_current_trans_quarks.begin(), _current_trans_quarks.end(), op) != _current_trans_quarks.end());
|
|
}
|
|
|