Opera 12.15 Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

OpDocumentEditUndoRedo.h 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
  2. *
  3. * Copyright (C) 1995-2004 Opera Software AS. All rights reserved.
  4. *
  5. * This file is part of the Opera web browser. It may not be distributed
  6. * under any circumstances.
  7. */
  8. #ifndef DOCUMENTEDIT_UNDOREDO_H
  9. #define DOCUMENTEDIT_UNDOREDO_H
  10. #ifdef DOCUMENT_EDIT_SUPPORT
  11. #include "modules/logdoc/htm_elm.h"
  12. class OpDocumentEdit;
  13. class OpDocumentEditUndoRedoStack;
  14. /** A object that simply calls stack->BeginGroup in the constructor and stack->EndGroup in the destructor.
  15. Used for automatic errorhandling in grouped functions. */
  16. class OpDocumentEditUndoRedoAutoGroup
  17. {
  18. public:
  19. OpDocumentEditUndoRedoAutoGroup(OpDocumentEditUndoRedoStack* stack);
  20. ~OpDocumentEditUndoRedoAutoGroup();
  21. private:
  22. OpDocumentEditUndoRedoStack* stack;
  23. };
  24. /** An object for temporarily disabling OpDocumentEditUndoRedoStack's change registration.
  25. *
  26. * Create this object on stack and undo-redo mechanism will not register the
  27. * changes performed on the document till the object is destroyed.
  28. */
  29. class OpDocumentEditDisableUndoRegistrationAuto
  30. {
  31. public:
  32. OpDocumentEditDisableUndoRegistrationAuto(OpDocumentEditUndoRedoStack* stack);
  33. ~OpDocumentEditDisableUndoRegistrationAuto();
  34. private:
  35. OpDocumentEditUndoRedoStack* stack;
  36. };
  37. // == OpDocumentEditUndoRedoEvent ==================================================
  38. class OpDocumentEditUndoRedoEvent : public Link, public Head
  39. #ifdef _DOCEDIT_DEBUG
  40. , public OpDocumentEditDebugCheckerObject
  41. #endif
  42. {
  43. public:
  44. OpDocumentEditUndoRedoEvent(
  45. OpDocumentEdit *edit
  46. );
  47. virtual ~OpDocumentEditUndoRedoEvent();
  48. /**
  49. * Registers UNDO/REDO event begin.
  50. *
  51. * @param containing_elm - an element containing the element to be changed
  52. * @param element_changed - the element to be changed
  53. * @param type - Type of an event (@see UndoRedoEventType)
  54. *
  55. */
  56. OP_STATUS BeginChange(HTML_Element* containing_elm, HTML_Element* element_changed, int type);
  57. /**
  58. * Registers UNDO/REDO event end.
  59. *
  60. * @param containing_elm - an element containing the element to be changed (the same as passed to BeginChange())
  61. *
  62. */
  63. OP_STATUS EndChange(HTML_Element* containing_elm);
  64. void Undo();
  65. void Redo();
  66. OP_STATUS Protect(HTML_Element* element);
  67. void Unprotect(HTML_Element* element);
  68. /** Returns if this event can be appended to the previous_event. (If it is the same type of event following the previous one) */
  69. BOOL IsAppending(OpDocumentEditUndoRedoEvent* previous_event);
  70. BOOL IsInsertEvent();
  71. /** Merges this event (and all events merged to it) to the given event */
  72. BOOL MergeTo(OpDocumentEditUndoRedoEvent *evt)
  73. {
  74. if (evt)
  75. {
  76. OP_ASSERT(!InList() || !"This element is currently in a list and it's tried to be merged to some other. Remove it from the list first!");
  77. Into(evt);
  78. while (OpDocumentEditUndoRedoEvent* merged = static_cast<OpDocumentEditUndoRedoEvent*>(First()))
  79. {
  80. merged->Out();
  81. merged->Into(evt);
  82. }
  83. return TRUE;
  84. }
  85. return FALSE;
  86. }
  87. void SetUserInvisible() { user_invisible = TRUE; }
  88. BOOL IsUserInvisible() const { return user_invisible; }
  89. /**
  90. * Updates the used memory counter in a event
  91. */
  92. void UpdateBytesUsed();
  93. /**
  94. * Updates the used memory counter in the passed in event and all events merged to it
  95. */
  96. static void UpdateAllBytesUsed(OpDocumentEditUndoRedoEvent *evt);
  97. /**
  98. * Returns an event's used memory counter value
  99. */
  100. UINT32 BytesUsed() const { return bytes_used; }
  101. /**
  102. * Returns sum of the used memory counter values of the passed in event and all events merged to it
  103. */
  104. static UINT32 AllBytesUsed(OpDocumentEditUndoRedoEvent *evt);
  105. /**
  106. * Returns a type of an event (@see UndoRedoEventType)
  107. */
  108. int Type() const { return type; }
  109. private:
  110. INT32 caret_elm_nr_before;
  111. INT32 caret_ofs_before;
  112. INT32 caret_elm_nr_after;
  113. INT32 caret_ofs_after;
  114. INT32 elm_nr;
  115. INT32 changed_elm_nr_before;
  116. INT32 changed_elm_nr_after;
  117. INT32 bytes_used;
  118. HTML_Element* element_changed;
  119. /**
  120. * Class responsible for a proper element insertion (to a proper place in a tree).
  121. * It's used e.g. for undoing REMOVE operation.
  122. */
  123. class UndoRedoTreeInserter
  124. {
  125. public:
  126. UndoRedoTreeInserter(OpDocumentEditUndoRedoEvent* e) : evt(e), mark(-1), type(ELEMENT_MARK_NONE)
  127. {
  128. OP_ASSERT(evt);
  129. }
  130. /** Finds a marker element for the passed in element. The marker element is later used to identify a place where the element must be inserted
  131. *
  132. * @param elm the element the marker element should be found for.
  133. */
  134. void FindPlaceMarker(HTML_Element* elm);
  135. /**
  136. * Inserts element to a proper place where it should be (i.e. a plece where it was before REMOVE operation)
  137. *
  138. * @param element - an element to be inserted
  139. * @param context - Document Context needed by [Under|Follow|Procede]Safe functions
  140. * @param pos - position where the element should be inserted on
  141. * @param mark_dirty - whether the element should eb marked as dirty
  142. *
  143. */
  144. void Insert(HTML_Element* element, const HTML_Element::DocumentContext& context, INT32 pos, BOOL mark_dirty = TRUE);
  145. private:
  146. OpDocumentEditUndoRedoEvent* evt;
  147. /** Position of the mark element - the element which will be used to insert a given element (@see ElementMarkType) */
  148. INT32 mark;
  149. /** A type of the mark element */
  150. enum ElementMarkType
  151. {
  152. ELEMENT_MARK_NONE,
  153. /** A element used as a mark is a parent of the element to be inserted (so UnderSafe() will be used to insert the element) */
  154. ELEMENT_MARK_PARENT,
  155. /** A element used as a mark is a predecessor of the element to be inserted (so FollowSafe() will be used to insert the element) */
  156. ELEMENT_MARK_PRED,
  157. /** A element used as a mark is a successor of the element to be inserted (so PrecedeSafe() will be used to insert the element) */
  158. ELEMENT_MARK_SUC
  159. };
  160. ElementMarkType type;
  161. /** Finds succesor of the elm suitable to be marker of place where the element is.
  162. * @return TRUE if any was found.
  163. */
  164. BOOL FindSucMark(HTML_Element* elm);
  165. /** Finds predecessor of the elm suitable to be marker of place where the element is.
  166. * @return TRUE if any was found.
  167. */
  168. BOOL FindPredMark(HTML_Element* elm);
  169. /** Finds parent of the elm suitable to be marker of place where the element is.
  170. * Note: if elm is not the last nor the only child of the parent ELEMENT_MARK_SUC or ELEMENT_MARK_PRED are found
  171. * within the parent instead.
  172. * @return TRUE if any was found.
  173. */
  174. BOOL FindParentMark(HTML_Element* elm);
  175. };
  176. UndoRedoTreeInserter tree_inserter;
  177. friend class UndoRedoTreeInserter;
  178. int type;
  179. BOOL user_invisible;
  180. BOOL is_ended;
  181. OpDocumentEdit* m_edit;
  182. /** A stage an event is currently before (if the stage is UNDO the next possible operation is UNDO) */
  183. enum Stage
  184. {
  185. UNDO,
  186. REDO
  187. };
  188. Stage stage;
  189. ES_Runtime *runtime;
  190. HTML_Element* GetElementOfNumber(INT32 nr);
  191. INT32 GetNumberOfElement(HTML_Element* elm);
  192. HTML_Element* CreateClone(HTML_Element* elm, BOOL deep);
  193. OP_STATUS Clone(HTML_Element* target, HTML_Element* source, BOOL deep);
  194. void Action(int type);
  195. };
  196. // == OpDocumentEditUndoRedoStack ==================================================
  197. class OpDocumentEditUndoRedoStack
  198. : public OpDocumentEditInternalEventListener
  199. #ifdef _DOCEDIT_DEBUG
  200. , public OpDocumentEditDebugCheckerObject
  201. #endif
  202. {
  203. friend class OpDocumentEditDisableUndoRegistrationAuto;
  204. public:
  205. OpDocumentEditUndoRedoStack(OpDocumentEdit* edit);
  206. virtual ~OpDocumentEditUndoRedoStack();
  207. void Clear(BOOL clear_undos = TRUE, BOOL clear_redos = TRUE);
  208. /**
  209. * Registers UNDO/REDO change(s) begin.
  210. *
  211. * @param containing_elm - an element containing the element to be changed
  212. * @param flags - the change flags (@see ChangeFlags)
  213. *
  214. */
  215. OP_STATUS BeginChange(HTML_Element* containing_elm, int flags);
  216. /**
  217. * Registers UNDO/REDO change(s) end.
  218. *
  219. * @param containing_elm - an element containing the element to be changed - the same as passed to BeginChange()
  220. *
  221. */
  222. OP_STATUS EndChange(HTML_Element* containing_elm);
  223. void AbortChange();
  224. /** The events made between BeginGroup and EndGroup will be merged and handled as one event, even if they aren't appended. */
  225. void BeginGroup();
  226. void EndGroup();
  227. BOOL CanUndo() const { return !!m_undos.Last(); }
  228. BOOL CanRedo() const { return !!m_redos.First(); }
  229. INT32 GetBeginCount() const { return m_begin_count; }
  230. INT32 GetBeginCountCalls() const { return m_begin_count_calls; }
  231. HTML_Element *GetCurrentContainingElm() const { return m_current_containing_elm; }
  232. BOOL IsValidAsChangeElm(HTML_Element *helm) const { return helm && (!m_begin_count || !m_current_containing_elm || m_current_containing_elm == helm ||m_current_containing_elm->IsAncestorOf(helm)); }
  233. void Undo();
  234. void Redo();
  235. /** The last change should be merged to the change (or chain of changes) before that */
  236. void MergeLastChanges();
  237. #ifdef _DOCEDIT_DEBUG // OpDocumentEditDebugCheckerObject
  238. virtual BOOL CheckBeginCount() { return FALSE; }
  239. #endif
  240. // OpDocumentEditInternalEventListener interface
  241. void OnElementOut(HTML_Element *elm);
  242. void OnElementInserted(HTML_Element* elm);
  243. void OnElementChange(HTML_Element *elm);
  244. void OnElementChanged(HTML_Element *elm);
  245. void SetFlags(int flags) { m_flags = flags; }
  246. int GetFlags() const { return m_flags; }
  247. private:
  248. UINT32 m_mem_used;
  249. Head m_undos;
  250. Head m_redos;
  251. OpDocumentEdit* m_edit;
  252. OpDocumentEditUndoRedoEvent* m_current_event;
  253. INT32 m_begin_count;
  254. INT32 m_begin_count_calls;
  255. INT32 m_group_begin_count;
  256. INT32 m_group_event_count;
  257. HTML_Element* m_current_containing_elm;
  258. int m_flags;
  259. unsigned int m_disabled_count;
  260. OP_STATUS BeginChange(HTML_Element* containing_elm, HTML_Element* element_changed, int type, int flags);
  261. OP_STATUS EndLastChange(HTML_Element* containing_elm);
  262. void DisableChangeRegistration() { ++m_disabled_count; }
  263. void EnableChangeRegistration() { OP_ASSERT(m_disabled_count > 0); --m_disabled_count; }
  264. };
  265. #endif // DOCUMENT_EDIT_SUPPORT
  266. #endif // DOCUMENTEDIT_UNDOREDO_H