GlobalHistoryContext with multiple EditingContext on same DomNode
Closed this issue · 7 comments
I'm currently running into an issue collapsing all of the HistoryContext for our tool into one GlobalHistoryContext. Our Schema loading looks like this:
Schema.parentNodeType.Type.Define(new ExtensionInfo<GlobalHistoryContext>());
Schema.childNodeType.Type.Define(new ExtensionInfo<EditingContext1>());
Schema.childNodeType.Type.Define(new ExtensionInfo<EditingContext2>());
The problem is that during GlobalHistoryContext.AddNode(DomNode node)
the child HistoryContext get put into a HashSet<HistoryContext>
. This means that m_childHistoryContexts
only contains EditingContext1
.
If EditingContext2
happens to be the active context when the user tries to Undo certain operations in our tool, a new Transaction is added to the CommandHistory in HistoryContext.OnEnded()
due to m_undoingOrRedoing
not being set to true during GlobalHistoryContext.SynchronizeUndoRedoStatus(bool newStatus)
.
I tried to derive from GlobalHistoryContext to implement our own version that can handle multiple EditingContext on a single DomNode, but that does not work because the set for HistoryContext.UndoingOrRedoing
is set to internal
access level.
Do we need to change the structure of our schema or is this something that can be supported in ATF?
I will look into this issue as soon as I get a chance.
Though, I think a simpler approach is to use one EditingContext and registered it on parentNode instead of having multiple history contexts.
Schema.parentNodeType.Type.Define(new ExtensionInfo());
Then make EditingContext to work on the entire tree.
For another way to solve the problem look at GameContext.cs in LevelEditor project
GameContext.cs deals with multiple history contexts. Because each sublevel is a separate document so it needs to have its own History Context.
But if the entire DomTree in project is stored in one document then one history context at the root node is sufficient and simpler.
Thanks
Alan
Thanks for the quick reply! I will take a look at what LevelEditor does and see if that can be adapted.
The reason we have multiple EditingContext on that one node, is that they are ITreeView editors for different sets of data on the childNodeType (we use the DomNode property as the Root of the tree and return specific children from the childNodeType in GetChildren()). Is there a better way to implement that type of behavior?
You are welcome
if each set of data needs to have its own history context (undo/redo stack) then your are dong the right thing to use GlobalHistoryContext. (Currently I am busy but I will take look to make required changes to work for you case).
But if your use case allows to have one undo/redo stack for all the data sets.
The root node can listen to any changes from any descendent nodes.
All the DomNode events bubble up to the root node you can hook subscriber at any level up to the root node.
Regarding LevelEditor's approach.
It might not work for you because it address different issue.
The main Level (Root Node) can have N number of sublevels each of them is separate document stored in its own file. But all of them are rendered into one viewport.
Each sublevel has its own history context but they are synchronized to have same undo depth.
Alan
You are correct that the LevelEditor's approach is not what we are looking for.
Any idea on what your solution will look like for modifying GlobalHistoryContext?
I pushed some changes to ATF from our internal main branch.
Sync and look at the release note located at root folder for detail.
Regarding multi history contexts, I suggest not to use GlobalHistoryContext instead implement your own multi-history context without derive from the global one.
In your case you need to register your MultiHistoryContext on parentNode.
and register EditingContext on each child node.
When user activates an editor that is bound particular child then set child's editing context to be active context. You can do this by using ContextRegistry.ActiveContext.
In this case each editor will have its own undo/redo history.
You need to tackle few issues to make it work.
For example the logic that determines if the document is dirty needs to aggregate dirty flags for all the sub-contexts. you can do using your MultiHistoryContext.
Note that dealing with multiple contexts is challenging for experienced ATF programmer.
So it might take time to get it right.
Good luck
Alan
Sorry for the delay in replying, but I was out on a business trip.
Looking at your change, I'm not sure if making GlobalHistoryContext.SynchronizeUndoRedoStatus
public virtual will help me implement MultiHistoryContext correctly. The member that I was having issues with was HistoryContext.UndoingOrRedoing
. If I can not set that in my own history context, Transactions will still be added during undo/redo.
Is it possible to make HistoryContext.UndoingOrRedoing
more accessible?
Yes, for now make a local change.
I will change the setter to public for next update.