1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #ifndef R2_ACTION_HISTORIC_H
18 #define R2_ACTION_HISTORIC_H
20 #include "nel/misc/historic.h"
21 #include "nel/misc/smart_ptr.h"
22 #include "nel/misc/ucstring.h"
24 #include "game_share/object.h"
25 #include "game_share/scenario.h"
30 class IDynamicMapClient
;
32 // An undo / redo historic
38 void setDMC(IDynamicMapClient
*dmc
) { _DMC
= dmc
; }
39 /** Signal the beginning of a new action. Calling this twice in a row will not create
42 void newSingleAction(const ucstring
&name
);
43 /** Begin a new action composed of several subactions. 'numSubActions' calls to 'newAction' will be expected
44 * before the merge of the subactions is pushed
46 void newMultiAction(const ucstring
&name
, uint actionCount
);
47 /** Begin a new action composed of several subactions. 'numSubActions' calls to 'newAction' will be expected
48 * before the merge of the subactions is pushed
50 void newPendingMultiAction(const ucstring
&name
, uint actionCount
);
51 /** Begin a new 'pending' action
52 * Unlike 'newAction', requests of the actions are sent at each call
53 * to the 'request' commands, not when the action is finished.
54 * Use this if you can't issue an action in a single row (may happen
55 * if some requests in the action depends on notifications sent by previous requests)
57 void newPendingAction(const ucstring
&name
);
59 // force to end a multi action, event if the action count hasnt been reached
60 void forceEndMultiAction();
62 // End last action / pending action
64 // cancel any action, including multi action
66 // If there's a pending action for this frame, flush its content
67 void flushPendingAction();
68 // Test if a pending action has been begun
69 bool isPendingActionInProgress() const { return _NewActionIsPending
; }
70 // get number of completed actions (do not include the new action being built)
71 uint
getNumActions() const { return _Actions
.getSize(); }
72 bool isNewActionBeingRecorded() const { return _NewAction
!= NULL
; }
73 uint
getMaxNumActions() const { return _Actions
.getMaxSize(); }
74 void setMaxNumActions(uint count
);
76 void clear(CObject
*newScenario
= NULL
);
77 // get name of next action that can be redone
78 const ucstring
*getNextActionName() const;
79 // get name of previous action that can be undone
80 const ucstring
*getPreviousActionName() const;
81 // Test if an action can be undone
83 // Test if an action can be redo
85 // undo last action, if possible (return true on success)
87 // redo last action, if possible (return true on success)
89 // push requests into current action
90 void requestInsertNode(const std::string
& instanceId
, const std::string
& name
, sint32 position
, const std::string
& key
, CObject
* value
);
91 void requestSetNode(const std::string
& instanceId
, const std::string
& attrName
, CObject
* value
);
92 void requestEraseNode(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
);
93 void requestMoveNode(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
, const std::string
& destInstanceId
, const std::string
& destAttrName
, sint32 destPosition
);
94 //Uundo supported only if 'clear' was called with a scenario pointer
95 //Only 'redo' supported else
96 bool isUndoSupported() const { return _Scenario
.getHighLevel() != NULL
; }
98 // base for all requests
99 class CRequestBase
: public NLMISC::CRefCount
102 typedef NLMISC::CSmartPtr
<CRequestBase
> TSmartPtr
;
103 virtual ~CRequestBase() {}
104 virtual void redo(IDynamicMapClient
*dmc
, CScenario
&scenario
) = 0;
105 virtual void undo(IDynamicMapClient
*dmc
, CScenario
&scenario
) = 0;
107 // clone an object, and disable its refids objects (these object would send
108 // creation notifications otherwise)
110 static CObject
*cloneObject(const CObject
*src
);
112 /** An atomic list of requests.
113 * Once redo / undo have been called, no other requests can be pushed into this action,
114 * so calls to 'pushRequest' will assert.
116 class CAction
: public NLMISC::CRefCount
119 typedef NLMISC::CSmartPtr
<CAction
> TSmartPtr
;
120 CAction(const ucstring
&name
);
122 void setCompleted() { _Completed
= true; }
123 void pushRequest(CRequestBase
*req
);
124 // For pending action : flush the content that has already been pushed using 'pushRequest'
125 // This should be called before 'setCompleted'
126 void flush(IDynamicMapClient
*dmc
, CScenario
&scenario
);
127 // If content has been flushed, rollback the modifications
128 void rollback(IDynamicMapClient
*dmc
, CScenario
&scenario
);
130 void redo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
131 void undo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
132 const ucstring
&getName() const { return _Name
; }
135 std::vector
<CRequestBase::TSmartPtr
> _Requests
;
143 class CRequestSetNode
: public CRequestBase
146 CRequestSetNode(const std::string
& instanceId
, const std::string
& attrName
, CObject
* value
);
148 virtual void redo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
149 virtual void undo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
151 std::string _InstanceId
;
152 std::string _AttrName
;
153 CObject::TSmartPtr _NewValue
;
154 CObject::TSmartPtr _OldValue
;
157 class CRequestEraseNode
: public CRequestBase
160 CRequestEraseNode(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
);
162 virtual void redo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
163 virtual void undo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
166 std::string _InstanceId
;
167 std::string _AttrName
;
169 CObject::TSmartPtr _OldValue
;
171 std::string _ParentInstanceId
;
172 std::string _AttrNameInParent
;
173 sint32 _PositionInParent
;
176 class CRequestInsertNode
: public CRequestBase
179 CRequestInsertNode(const std::string
& instanceId
, const std::string
& attrName
, sint32 position
, const std::string
& key
, CObject
* value
);
181 virtual void redo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
182 virtual void undo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
184 std::string _InstanceId
;
185 std::string _AttrName
;
188 CObject::TSmartPtr _Value
;
191 class CRequestMoveNode
: public CRequestBase
194 CRequestMoveNode(const std::string
& srcInstanceId
,
195 const std::string
& srcAttrName
,
197 const std::string
& destInstanceId
,
198 const std::string
& destAttrName
,
199 sint32 destPosition
);
201 virtual void redo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
202 virtual void undo(IDynamicMapClient
*dmc
, CScenario
&scenario
);
204 std::string _SrcInstanceId
;
205 std::string _SrcAttrName
;
207 // name of source in parent for reciprocal move
208 std::string _SrcInstanceIdInParent
;
209 std::string _SrcAttrNameInParent
;
210 sint32 _SrcPositionInParent
;
212 std::string _DestInstanceId
;
213 std::string _DestAttrName
;
214 sint32 _DestPosition
;
216 std::string _DestInstanceIdAfterMove
;
217 std::string _DestAttrNameAfterMove
;
218 sint32 _DestPositionAfterMove
;
221 IDynamicMapClient
*_DMC
;
222 NLMISC::CHistoric
<CAction::TSmartPtr
> _Actions
;
223 /** Index of current action relative to the end of the stack (-1 for the last action)
224 * Undo applies to this action, redo applies to the next action
226 sint _CurrActionIndex
;
227 CAction::TSmartPtr _NewAction
;
228 ucstring _NewActionName
;
229 uint _SubActionCount
;
230 bool _NewActionIsPending
;
231 // anticipated scenario state,
235 // return previous action absolute index, or -1 if there's no previous action that can be undone.
236 sint
getPreviousActionIndex() const;
237 // return next action absolute index, or -1 if there's no next action that can be undone.
238 sint
getNextActionIndex() const;