App: transaction related API changes

Introduce a new concept of transaction ID. Each transaction must be
unique inside the document. Multiple transactions from different
documents can be grouped together with the same transaction ID.
This makes it possible to undo/redo single operation that contains
changes from multiple documents due to external linking.

Application:

* get/set/closeActiveTransaction() is used to setup potential
  transactions with a given name. The transaction is only created when
  there is actual changes. If objects from multiple documents are
  changed under the same active transaction, they will have the same
  trasnaction ID, and can be undo/redo togtether later.

* signalUndo/signalRedo, new signals triggered once after an undo/redo
  operation. Unlike signalUndo/RedoDocument, these signals will only be
  triggered once even if there may be multiple documents involved during
  undo/redo.

* signal(Before)CloseTransaction, new signals triggered before/after an
  actual transaction is created or aborted.

AutoTransaction:

* Helper class to enable automatic management of transactions. See class
  document for more details. This class will be used by Gui::Command
  in later patches to allow better automation of transactions in
  command.

Document:

* open/commit/abortTransaction() are now redirected to call
  Application::get/set/closeActiveTransaction() instead.

* _openTransaction() is added to do the real creation of transaction.

* _checkTransaction() is modified to create transaction on actual change
  of any property.

* getTransactionID() is used to find out the position of a transaction
  with a given ID. When triggering undo in external document, it may be
  necessary to perform multi-step undo/redo in order to match for the
  transaction ID.

Transaction/TransactionObject:

* Various changes for the new transaction ID concept.

* Support undo/redo add/remove dynamic property
This commit is contained in:
Zheng, Lei
2019-06-28 17:45:27 +08:00
committed by wmayer
parent f4205130ae
commit 1cb2e190b4
11 changed files with 835 additions and 173 deletions

View File

@@ -151,6 +151,19 @@ PyMethodDef Application::Methods[] = {
"getLinksTo(obj,options=0,maxCount=0) -- return the objects linked to 'obj'\n\n"
"options: 1: recursive, 2: check link array. Options can combine.\n"
"maxCount: to limit the number of links returned\n"},
{"setActiveTransaction", (PyCFunction) Application::sSetActiveTransaction, METH_VARARGS,
"setActiveTransaction(name, persist=False) -- setup active transaction with the given name\n\n"
"name: the transaction name\n"
"persist(False): by default, if the calling code is inside any invokation of a command, it\n"
" will be auto closed once all command within the current stack exists. To\n"
" disable auto closing, set persist=True\n"
"Returns the transaction ID for the active transaction. An application-wide\n"
"active transaction causes any document changes to open a transaction with\n"
"the given name and ID."},
{"getActiveTransaction", (PyCFunction) Application::sGetActiveTransaction, METH_VARARGS,
"getActiveTransaction() -> (name,id) return the current active transaction name and ID"},
{"closeActiveTransaction", (PyCFunction) Application::sCloseActiveTransaction, METH_VARARGS,
"closeActiveTransaction(abort=False) -- commit or abort current active transaction"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
@@ -806,3 +819,46 @@ PyObject *Application::sGetLinksTo(PyObject * /*self*/, PyObject *args)
}PY_CATCH;
}
PyObject *Application::sSetActiveTransaction(PyObject * /*self*/, PyObject *args)
{
char *name;
PyObject *persist = Py_False;
if (!PyArg_ParseTuple(args, "s|O", &name,&persist))
return 0;
PY_TRY {
Py::Int ret(GetApplication().setActiveTransaction(name,PyObject_IsTrue(persist)));
return Py::new_reference_to(ret);
}PY_CATCH;
}
PyObject *Application::sGetActiveTransaction(PyObject * /*self*/, PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return 0;
PY_TRY {
int id = 0;
const char *name = GetApplication().getActiveTransaction(&id);
if(!name || id<=0)
Py_Return;
Py::Tuple ret(2);
ret.setItem(0,Py::String(name));
ret.setItem(1,Py::Int(id));
return Py::new_reference_to(ret);
}PY_CATCH;
}
PyObject *Application::sCloseActiveTransaction(PyObject * /*self*/, PyObject *args)
{
PyObject *abort = Py_False;
int id = 0;
if (!PyArg_ParseTuple(args, "|Oi", &abort,&id))
return 0;
PY_TRY {
GetApplication().closeActiveTransaction(PyObject_IsTrue(abort),id);
Py_Return;
} PY_CATCH;
}