MoveNodeTransaction.h (9286B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef MoveNodeTransaction_h 7 #define MoveNodeTransaction_h 8 9 #include "EditTransactionBase.h" // for EditTransactionBase, etc. 10 11 #include "EditorDOMPoint.h" 12 #include "EditorForwards.h" 13 #include "SelectionState.h" 14 15 #include "nsCOMPtr.h" // for nsCOMPtr 16 #include "nsCycleCollectionParticipant.h" 17 #include "nsIContent.h" // for nsIContent 18 #include "nsISupportsImpl.h" // for NS_DECL_ISUPPORTS_INHERITED 19 20 namespace mozilla { 21 22 class MoveNodeTransactionBase : public EditTransactionBase { 23 public: 24 NS_DECL_ISUPPORTS_INHERITED 25 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MoveNodeTransactionBase, 26 EditTransactionBase) 27 NS_DECL_EDITTRANSACTIONBASE_GETASMETHODS_OVERRIDE(MoveNodeTransactionBase) 28 29 virtual EditorRawDOMPoint SuggestPointToPutCaret() const = 0; 30 virtual EditorRawDOMPoint SuggestNextInsertionPoint() const = 0; 31 32 protected: 33 MoveNodeTransactionBase(HTMLEditor& aHTMLEditor, 34 nsIContent& aLastContentToMove, 35 const EditorRawDOMPoint& aPointToInsert); 36 37 virtual ~MoveNodeTransactionBase() = default; 38 39 [[nodiscard]] EditorRawDOMPoint SuggestPointToPutCaret( 40 nsIContent* aLastMoveContent) const { 41 if (MOZ_UNLIKELY(!mContainer || !aLastMoveContent)) { 42 return EditorRawDOMPoint(); 43 } 44 return EditorRawDOMPoint::After(*aLastMoveContent); 45 } 46 47 [[nodiscard]] EditorRawDOMPoint SuggestNextInsertionPoint( 48 nsIContent* aLastMoveContent) const { 49 if (MOZ_UNLIKELY(!mContainer)) { 50 return EditorRawDOMPoint(); 51 } 52 if (!mReference) { 53 return EditorRawDOMPoint::AtEndOf(*aLastMoveContent); 54 } 55 if (MOZ_UNLIKELY(mReference->GetParentNode() != mContainer)) { 56 if (MOZ_LIKELY(aLastMoveContent->GetParentNode() == mContainer)) { 57 return EditorRawDOMPoint(aLastMoveContent).NextPoint(); 58 } 59 return EditorRawDOMPoint::AtEndOf(mContainer); 60 } 61 return EditorRawDOMPoint(mReference); 62 } 63 64 // mContainer is new container of mContentToInsert after (re-)doing the 65 // transaction. 66 nsCOMPtr<nsINode> mContainer; 67 68 // mReference is the child content where mContentToMove should be or was 69 // inserted into the mContainer. This is typically the next sibling of 70 // mContentToMove after moving. 71 nsCOMPtr<nsIContent> mReference; 72 73 // mOldContainer is the original container of mContentToMove before moving. 74 nsCOMPtr<nsINode> mOldContainer; 75 76 // mOldNextSibling is the next sibling of mCOntentToMove before moving. 77 nsCOMPtr<nsIContent> mOldNextSibling; 78 79 // The editor for this transaction. 80 RefPtr<HTMLEditor> mHTMLEditor; 81 }; 82 83 /** 84 * A transaction that moves a content node to a specified point. 85 */ 86 class MoveNodeTransaction final : public MoveNodeTransactionBase { 87 protected: 88 template <typename PT, typename CT> 89 MoveNodeTransaction(HTMLEditor& aHTMLEditor, nsIContent& aContentToMove, 90 const EditorDOMPointBase<PT, CT>& aPointToInsert); 91 92 public: 93 /** 94 * Create a transaction for moving aContentToMove before the child at 95 * aPointToInsert. 96 * 97 * @param aHTMLEditor The editor which manages the transaction. 98 * @param aContentToMove The node to be moved. 99 * @param aPointToInsert The insertion point of aContentToMove. 100 * @return A MoveNodeTransaction which was initialized 101 * with the arguments. 102 */ 103 template <typename PT, typename CT> 104 static already_AddRefed<MoveNodeTransaction> MaybeCreate( 105 HTMLEditor& aHTMLEditor, nsIContent& aContentToMove, 106 const EditorDOMPointBase<PT, CT>& aPointToInsert); 107 108 NS_DECL_ISUPPORTS_INHERITED 109 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MoveNodeTransaction, 110 MoveNodeTransactionBase) 111 112 NS_DECL_EDITTRANSACTIONBASE 113 NS_DECL_EDITTRANSACTIONBASE_GETASMETHODS_OVERRIDE(MoveNodeTransaction) 114 115 MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() final; 116 117 /** 118 * SuggestPointToPutCaret() suggests a point after doing or redoing the 119 * transaction. 120 */ 121 EditorRawDOMPoint SuggestPointToPutCaret() const final { 122 return MoveNodeTransactionBase::SuggestPointToPutCaret(mContentToMove); 123 } 124 125 /** 126 * Suggest next insertion point if the caller wants to move another content 127 * node around the insertion point. 128 */ 129 EditorRawDOMPoint SuggestNextInsertionPoint() const final { 130 return MoveNodeTransactionBase::SuggestNextInsertionPoint(mContentToMove); 131 } 132 133 friend std::ostream& operator<<(std::ostream& aStream, 134 const MoveNodeTransaction& aTransaction); 135 136 protected: 137 virtual ~MoveNodeTransaction() = default; 138 139 MOZ_CAN_RUN_SCRIPT nsresult DoTransactionInternal(); 140 141 // The content which will be or was moved from mOldContainer to mContainer. 142 nsCOMPtr<nsIContent> mContentToMove; 143 }; 144 145 /** 146 * A transaction that moves multiple siblings once. 147 */ 148 class MoveSiblingsTransaction final : public MoveNodeTransactionBase { 149 protected: 150 template <typename PT, typename CT> 151 MoveSiblingsTransaction(HTMLEditor& aHTMLEditor, 152 nsIContent& aFirstContentToMove, 153 nsIContent& aLastContentToMove, 154 uint32_t aNumberOfSiblings, 155 const EditorDOMPointBase<PT, CT>& aPointToInsert); 156 157 public: 158 /** 159 * Create a transaction for moving aContentToMove before the child at 160 * aPointToInsert. 161 * 162 * @param aHTMLEditor The editor which manages the transaction. 163 * @param aFirstContentToMove The first node to be moved. 164 * @param aLastContentToMove The last node to be moved. Its parent node 165 * should be the parent of aFirstContentToMove and 166 * a following sibling of aFirstContentToMove. 167 * @param aNumberOfSiblings The number of siblings to move. 168 * @param aPointToInsert The insertion point of aContentToMove. 169 * @return A MoveSiblingsTransaction which was initialized 170 * with the arguments. 171 */ 172 template <typename PT, typename CT> 173 static already_AddRefed<MoveSiblingsTransaction> MaybeCreate( 174 HTMLEditor& aHTMLEditor, nsIContent& aFirstContentToMove, 175 nsIContent& aLastContentToMove, 176 const EditorDOMPointBase<PT, CT>& aPointToInsert); 177 178 NS_DECL_ISUPPORTS_INHERITED 179 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MoveSiblingsTransaction, 180 MoveNodeTransactionBase) 181 182 NS_DECL_EDITTRANSACTIONBASE 183 NS_DECL_EDITTRANSACTIONBASE_GETASMETHODS_OVERRIDE(MoveSiblingsTransaction) 184 185 MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override; 186 187 /** 188 * SuggestPointToPutCaret() suggests a point after doing or redoing the 189 * transaction. 190 */ 191 EditorRawDOMPoint SuggestPointToPutCaret() const final { 192 return MoveNodeTransactionBase::SuggestPointToPutCaret( 193 GetLastMovedContent()); 194 } 195 196 /** 197 * Suggest next insertion point if the caller wants to move another content 198 * node around the insertion point. 199 */ 200 EditorRawDOMPoint SuggestNextInsertionPoint() const final { 201 return MoveNodeTransactionBase::SuggestNextInsertionPoint( 202 GetLastMovedContent()); 203 } 204 205 const nsTArray<OwningNonNull<nsIContent>>& TargetSiblings() const { 206 return mSiblingsToMove; 207 } 208 209 [[nodiscard]] nsIContent* GetFirstMovedContent() const; 210 [[nodiscard]] nsIContent* GetLastMovedContent() const; 211 212 friend std::ostream& operator<<(std::ostream& aStream, 213 const MoveSiblingsTransaction& aTransaction); 214 215 protected: 216 virtual ~MoveSiblingsTransaction() = default; 217 218 MOZ_CAN_RUN_SCRIPT nsresult DoTransactionInternal(); 219 220 [[nodiscard]] bool IsSiblingsToMoveValid() const { 221 for (const auto& content : mSiblingsToMove) { 222 if (MOZ_UNLIKELY(!content.isInitialized())) { 223 return false; 224 } 225 } 226 return true; 227 } 228 229 /** 230 * Remove all aClonedSiblingsToMove from the DOM. aClonedSiblingsToMove must 231 * be a clone of mSiblingsToMove in the stack. 232 */ 233 MOZ_CAN_RUN_SCRIPT void RemoveAllSiblingsToMove( 234 HTMLEditor& aHTMLEditor, 235 const nsTArray<OwningNonNull<nsIContent>>& aClonedSiblingsToMove, 236 AutoMoveNodeSelNotify& aNotifier) const; 237 238 /** 239 * Insert all disconnected aClonedSiblingsToMove to before aReferenceNode or 240 * end of aParentNode. Before calling this, RemoveAllSiblingsToMove() 241 * should've already been called. 242 */ 243 MOZ_CAN_RUN_SCRIPT nsresult InsertAllSiblingsToMove( 244 HTMLEditor& aHTMLEditor, 245 const nsTArray<OwningNonNull<nsIContent>>& aClonedSiblingsToMove, 246 nsINode& aParentNode, nsIContent* aReferenceNode, 247 AutoMoveNodeSelNotify& aNotifier) const; 248 249 // The content which will be or was moved from mOldContainer to mContainer. 250 AutoTArray<OwningNonNull<nsIContent>, 2> mSiblingsToMove; 251 252 // At undoing, this is set to true and at redoing, this is set to false. 253 bool mDone = false; 254 }; 255 256 } // namespace mozilla 257 258 #endif // #ifndef MoveNodeTransaction_h