/src/libreoffice/sw/inc/pam.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | #ifndef INCLUDED_SW_INC_PAM_HXX |
20 | | #define INCLUDED_SW_INC_PAM_HXX |
21 | | |
22 | | #include <sal/types.h> |
23 | | #include "ring.hxx" |
24 | | #include "contentindex.hxx" |
25 | | #include "ndindex.hxx" |
26 | | #include "swdllapi.h" |
27 | | #include "nodeoffset.hxx" |
28 | | |
29 | | #include <iostream> |
30 | | #include <utility> |
31 | | |
32 | | class SwDoc; |
33 | | class SwPaM; |
34 | | class Point; |
35 | | |
36 | | /// Marks a position in the document model. |
37 | | struct SAL_WARN_UNUSED SW_DLLPUBLIC SwPosition |
38 | | { |
39 | | SwNodeIndex nNode; |
40 | | SwContentIndex nContent; |
41 | | |
42 | | SwPosition( const SwNodeIndex &rNode, const SwContentIndex &rContent ); |
43 | | SwPosition( const SwNode &rNode, const SwContentIndex &rContent ); |
44 | | explicit SwPosition( const SwNodes& rNodes, SwNodeOffset nIndex = SwNodeOffset(0) ); |
45 | | explicit SwPosition( const SwNodeIndex &rNode, SwNodeOffset nDiff = SwNodeOffset(0) ); |
46 | | explicit SwPosition( const SwNode& rNode, SwNodeOffset nDiff = SwNodeOffset(0) ); |
47 | | explicit SwPosition( const SwContentNode& rNode, sal_Int32 nContentOffset = 0 ); |
48 | | SwPosition( const SwNodeIndex &rNode, const SwContentNode*, sal_Int32 nContentOffset ); |
49 | | SwPosition( const SwNode &rNode, const SwContentNode*, sal_Int32 nContentOffset ); |
50 | | SwPosition( const SwNodeIndex &rNode, SwNodeOffset nDiff, const SwContentNode*, sal_Int32 nContentOffset ); |
51 | | SwPosition( const SwNode &rNode, SwNodeOffset nDiff, const SwContentNode*, sal_Int32 nContentOffset ); |
52 | | SwPosition( const SwContentIndex &, short nDiff ); |
53 | | |
54 | | // callers should be using one of the other constructors to avoid creating a temporary |
55 | | SwPosition( SwNodeIndex && ) = delete; |
56 | | SwPosition( const SwNodeIndex &, SwContentIndex && ) = delete; |
57 | | SwPosition( SwNodeIndex &&, SwContentIndex && ) = delete; |
58 | | SwPosition( SwNodeIndex &&, const SwContentNode*, sal_Int32 ) = delete; |
59 | | SwPosition( SwNodeIndex &&, SwNodeOffset ) = delete; |
60 | | SwPosition( SwContentIndex &&, short ) = delete; |
61 | | |
62 | | /** |
63 | | Returns the document this position is in. |
64 | | |
65 | | @return the document this position is in. |
66 | | */ |
67 | | SwDoc& GetDoc() const; |
68 | | |
69 | | bool operator < (const SwPosition &) const; |
70 | | bool operator > (const SwPosition &) const; |
71 | | bool operator <=(const SwPosition &) const; |
72 | | bool operator >=(const SwPosition &) const; |
73 | | bool operator ==(const SwPosition &) const; |
74 | | bool operator !=(const SwPosition &) const; |
75 | | void dumpAsXml(xmlTextWriterPtr pWriter) const; |
76 | | |
77 | | |
78 | 174M | SwNodeOffset GetNodeIndex() const { return nNode.GetIndex(); } |
79 | 3.51M | const SwNodes& GetNodes() const { return nNode.GetNodes(); } |
80 | 1.59M | SwNodes& GetNodes() { return nNode.GetNodes(); } |
81 | 417M | SwNode& GetNode() const { return nNode.GetNode(); } |
82 | | |
83 | | |
84 | 75.1M | const SwContentNode* GetContentNode() const { return nContent.GetContentNode(); } |
85 | 268M | sal_Int32 GetContentIndex() const { return nContent.GetIndex(); } |
86 | 1.99M | void SetOwner(ISwContentIndexOwner* pOwner) { nContent.SetOwner(pOwner); } |
87 | | |
88 | | /// These all set both nNode and nContent |
89 | | void Assign( const SwNode& rNd, SwNodeOffset nDelta, sal_Int32 nContentOffset = 0 ); |
90 | | void Assign( SwNodeOffset nNodeOffset, sal_Int32 nContentOffset = 0 ); |
91 | | void Assign( const SwContentNode& rNode, sal_Int32 nContentOffset = 0 ); |
92 | | void Assign( const SwNode& rNd, sal_Int32 nContentOffset = 0 ); |
93 | | void Assign( const SwNodeIndex& rNdIdx, sal_Int32 nContentOffset = 0 ); |
94 | | /// Set nNode to rNd, and nContent to the beginning of rNd |
95 | | void AssignStartIndex( const SwContentNode& rNd ); |
96 | | /// Set nNode to rNd, and nContent to the end of rNd |
97 | | void AssignEndIndex( const SwContentNode& rNd ); |
98 | | /// Adjust node position, and resets content position to zero |
99 | | void Adjust( SwNodeOffset nDelta ); |
100 | | /// Adjust content index, only valid to call this if the position points to a SwContentNode subclass |
101 | | void AdjustContent( sal_Int32 nDelta ); |
102 | | /// Set content index, only valid to call this if the position points to a SwContentNode subclass |
103 | | void SetContent( sal_Int32 nContentIndex ); |
104 | | }; |
105 | | |
106 | | SW_DLLPUBLIC std::ostream &operator <<(std::ostream& s, const SwPosition& position); |
107 | | |
108 | | // Result of comparing positions. |
109 | | enum class SwComparePosition { |
110 | | Before, ///< Pos1 before Pos2. |
111 | | Behind, ///< Pos1 behind Pos2. |
112 | | Inside, ///< Pos1 completely contained in Pos2. |
113 | | Outside, ///< Pos2 completely contained in Pos1. |
114 | | Equal, ///< Pos1 is as large as Pos2. |
115 | | OverlapBefore, ///< Pos1 overlaps Pos2 at the beginning. |
116 | | OverlapBehind, ///< Pos1 overlaps Pos2 at the end. |
117 | | CollideStart, ///< Pos1 start touches at Pos2 end. |
118 | | CollideEnd ///< Pos1 end touches at Pos2 start. |
119 | | }; |
120 | | |
121 | | template<typename T> |
122 | | SwComparePosition ComparePosition( |
123 | | const T& rStt1, const T& rEnd1, |
124 | | const T& rStt2, const T& rEnd2 ) |
125 | 884k | { |
126 | 884k | SwComparePosition nRet; |
127 | 884k | if( rStt1 < rStt2 ) |
128 | 67.2k | { |
129 | 67.2k | if( rEnd1 > rStt2 ) |
130 | 8.03k | { |
131 | 8.03k | if( rEnd1 >= rEnd2 ) |
132 | 5.15k | nRet = SwComparePosition::Outside; |
133 | 2.88k | else |
134 | 2.88k | nRet = SwComparePosition::OverlapBefore; |
135 | | |
136 | 8.03k | } |
137 | 59.2k | else if( rEnd1 == rStt2 ) |
138 | 33.3k | nRet = SwComparePosition::CollideEnd; |
139 | 25.8k | else |
140 | 25.8k | nRet = SwComparePosition::Before; |
141 | 67.2k | } |
142 | 816k | else if( rEnd2 > rStt1 ) |
143 | 330k | { |
144 | 330k | if( rEnd2 >= rEnd1 ) |
145 | 313k | { |
146 | 313k | if( rEnd2 == rEnd1 && rStt2 == rStt1 ) |
147 | 215k | nRet = SwComparePosition::Equal; |
148 | 98.0k | else |
149 | 98.0k | nRet = SwComparePosition::Inside; |
150 | 313k | } |
151 | 16.9k | else |
152 | 16.9k | { |
153 | 16.9k | if (rStt1 == rStt2) |
154 | 12.5k | nRet = SwComparePosition::Outside; |
155 | 4.41k | else |
156 | 4.41k | nRet = SwComparePosition::OverlapBehind; |
157 | 16.9k | } |
158 | 330k | } |
159 | 486k | else if( rEnd2 == rStt1 ) |
160 | 23.6k | nRet = SwComparePosition::CollideStart; |
161 | 463k | else |
162 | 463k | nRet = SwComparePosition::Behind; |
163 | 884k | return nRet; |
164 | 884k | } SwComparePosition ComparePosition<SwPosition>(SwPosition const&, SwPosition const&, SwPosition const&, SwPosition const&) Line | Count | Source | 125 | 884k | { | 126 | 884k | SwComparePosition nRet; | 127 | 884k | if( rStt1 < rStt2 ) | 128 | 67.2k | { | 129 | 67.2k | if( rEnd1 > rStt2 ) | 130 | 8.03k | { | 131 | 8.03k | if( rEnd1 >= rEnd2 ) | 132 | 5.15k | nRet = SwComparePosition::Outside; | 133 | 2.88k | else | 134 | 2.88k | nRet = SwComparePosition::OverlapBefore; | 135 | | | 136 | 8.03k | } | 137 | 59.2k | else if( rEnd1 == rStt2 ) | 138 | 33.3k | nRet = SwComparePosition::CollideEnd; | 139 | 25.8k | else | 140 | 25.8k | nRet = SwComparePosition::Before; | 141 | 67.2k | } | 142 | 816k | else if( rEnd2 > rStt1 ) | 143 | 330k | { | 144 | 330k | if( rEnd2 >= rEnd1 ) | 145 | 313k | { | 146 | 313k | if( rEnd2 == rEnd1 && rStt2 == rStt1 ) | 147 | 215k | nRet = SwComparePosition::Equal; | 148 | 98.0k | else | 149 | 98.0k | nRet = SwComparePosition::Inside; | 150 | 313k | } | 151 | 16.9k | else | 152 | 16.9k | { | 153 | 16.9k | if (rStt1 == rStt2) | 154 | 12.5k | nRet = SwComparePosition::Outside; | 155 | 4.39k | else | 156 | 4.39k | nRet = SwComparePosition::OverlapBehind; | 157 | 16.9k | } | 158 | 330k | } | 159 | 486k | else if( rEnd2 == rStt1 ) | 160 | 23.6k | nRet = SwComparePosition::CollideStart; | 161 | 463k | else | 162 | 463k | nRet = SwComparePosition::Behind; | 163 | 884k | return nRet; | 164 | 884k | } |
SwComparePosition ComparePosition<int>(int const&, int const&, int const&, int const&) Line | Count | Source | 125 | 21 | { | 126 | 21 | SwComparePosition nRet; | 127 | 21 | if( rStt1 < rStt2 ) | 128 | 0 | { | 129 | 0 | if( rEnd1 > rStt2 ) | 130 | 0 | { | 131 | 0 | if( rEnd1 >= rEnd2 ) | 132 | 0 | nRet = SwComparePosition::Outside; | 133 | 0 | else | 134 | 0 | nRet = SwComparePosition::OverlapBefore; | 135 | |
| 136 | 0 | } | 137 | 0 | else if( rEnd1 == rStt2 ) | 138 | 0 | nRet = SwComparePosition::CollideEnd; | 139 | 0 | else | 140 | 0 | nRet = SwComparePosition::Before; | 141 | 0 | } | 142 | 21 | else if( rEnd2 > rStt1 ) | 143 | 21 | { | 144 | 21 | if( rEnd2 >= rEnd1 ) | 145 | 0 | { | 146 | 0 | if( rEnd2 == rEnd1 && rStt2 == rStt1 ) | 147 | 0 | nRet = SwComparePosition::Equal; | 148 | 0 | else | 149 | 0 | nRet = SwComparePosition::Inside; | 150 | 0 | } | 151 | 21 | else | 152 | 21 | { | 153 | 21 | if (rStt1 == rStt2) | 154 | 0 | nRet = SwComparePosition::Outside; | 155 | 21 | else | 156 | 21 | nRet = SwComparePosition::OverlapBehind; | 157 | 21 | } | 158 | 21 | } | 159 | 0 | else if( rEnd2 == rStt1 ) | 160 | 0 | nRet = SwComparePosition::CollideStart; | 161 | 0 | else | 162 | 0 | nRet = SwComparePosition::Behind; | 163 | 21 | return nRet; | 164 | 21 | } |
|
165 | | |
166 | | /// SwPointAndMark / SwPaM |
167 | | struct SwMoveFnCollection; |
168 | | SW_DLLPUBLIC extern SwMoveFnCollection const & fnMoveForward; ///< SwPam::Move()/Find() default argument. |
169 | | SW_DLLPUBLIC extern SwMoveFnCollection const & fnMoveBackward; |
170 | | |
171 | | using SwGoInDoc = auto (*)(SwPaM& rPam, SwMoveFnCollection const & fnMove) -> bool; |
172 | | SW_DLLPUBLIC bool GoInDoc( SwPaM&, SwMoveFnCollection const &); |
173 | | bool GoInSection( SwPaM&, SwMoveFnCollection const &); |
174 | | SW_DLLPUBLIC bool GoInNode( SwPaM&, SwMoveFnCollection const &); |
175 | | SW_DLLPUBLIC bool GoInContent( SwPaM&, SwMoveFnCollection const &); |
176 | | bool GoInContentCells( SwPaM&, SwMoveFnCollection const &); |
177 | | bool GoInContentSkipHidden( SwPaM&, SwMoveFnCollection const &); |
178 | | bool GoInContentCellsSkipHidden( SwPaM&, SwMoveFnCollection const &); |
179 | | |
180 | | /** |
181 | | * PaM is Point and Mark: a selection of the document model. |
182 | | * |
183 | | * The reason for the distinction is that the point moves around during adjusting the selection with |
184 | | * shift-arrow keys, while the mark remains where it is. |
185 | | */ |
186 | | class SAL_WARN_UNUSED SW_DLLPUBLIC SwPaM : public sw::Ring<SwPaM> |
187 | | { |
188 | | SwPosition m_Bound1; |
189 | | SwPosition m_Bound2; |
190 | | SwPosition * m_pPoint; ///< points at either m_Bound1 or m_Bound2 |
191 | | SwPosition * m_pMark; ///< points at either m_Bound1 or m_Bound2 |
192 | | bool m_bIsInFrontOfLabel; |
193 | | |
194 | | SwPaM(SwPaM const& rPaM) = delete; |
195 | | |
196 | | public: |
197 | | explicit SwPaM( const SwPosition& rPos, SwPaM* pRing = nullptr ); |
198 | | SwPaM( const SwPosition& rMk, const SwPosition& rPt, SwPaM* pRing = nullptr ); |
199 | | SwPaM( const SwNodeIndex& rMk, const SwNodeIndex& rPt, |
200 | | SwNodeOffset nMkOffset = SwNodeOffset(0), SwNodeOffset nPtOffset = SwNodeOffset(0), SwPaM* pRing = nullptr ); |
201 | | SwPaM( const SwNode& rMk, const SwNode& rPt, |
202 | | SwNodeOffset nMkOffset = SwNodeOffset(0), SwNodeOffset nPtOffset = SwNodeOffset(0), SwPaM* pRing = nullptr ); |
203 | | SwPaM( const SwNodeIndex& rMk, sal_Int32 nMkContent, |
204 | | const SwNodeIndex& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr ); |
205 | | SwPaM( const SwNode& rMk, sal_Int32 nMkContent, |
206 | | const SwNode& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr ); |
207 | | SwPaM( const SwNode& rMk, SwNodeOffset nMkOffset, sal_Int32 nMkContent, |
208 | | const SwNode& rPt, SwNodeOffset nPtOffset, sal_Int32 nPtContent, SwPaM* pRing = nullptr ); |
209 | | SwPaM( const SwNode& rNd, SwNodeOffset nNdOffset, sal_Int32 nContent = 0, SwPaM* pRing = nullptr ); |
210 | | explicit SwPaM( const SwNode& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr ); |
211 | | explicit SwPaM( const SwNodeIndex& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr ); |
212 | | explicit SwPaM( const SwNodes& rNds, SwNodeOffset nMkOffset = SwNodeOffset(0), SwPaM* pRing = nullptr ); |
213 | | virtual ~SwPaM() override; |
214 | | |
215 | | /// this takes a second parameter, which indicates the Ring that |
216 | | /// the new PaM should be part of (may be null) |
217 | | SwPaM(SwPaM const& rPaM, SwPaM * pRing); |
218 | | /// @@@ semantic: no copy assignment for super class Ring. |
219 | | SwPaM& operator=( const SwPaM & ); |
220 | | |
221 | | /// Movement of cursor. |
222 | | bool Move( SwMoveFnCollection const & fnMove = fnMoveForward, |
223 | | SwGoInDoc fnGo = GoInContent ); |
224 | | |
225 | 4.59M | bool IsInFrontOfLabel() const { return m_bIsInFrontOfLabel; } |
226 | 0 | void SetInFrontOfLabel_( bool bNew ) { m_bIsInFrontOfLabel = bNew; } |
227 | | |
228 | | /// Unless this is called, the getter method of Mark will return Point. |
229 | | virtual void SetMark(); |
230 | | |
231 | | void DeleteMark() |
232 | 3.93M | { |
233 | 3.93M | if (HasMark()) |
234 | 2.54M | { |
235 | | /** clear the mark position; this helps if mark's SwContentIndex is |
236 | | registered at some node, and that node is then deleted */ |
237 | 2.54M | m_pMark->Assign( *GetPointNode().GetNodes()[SwNodeOffset(0)] ); |
238 | 2.54M | m_pMark = m_pPoint; |
239 | 2.54M | } |
240 | 3.93M | } |
241 | | void Exchange() |
242 | 27.8k | { |
243 | 27.8k | if (HasMark()) |
244 | 7.17k | std::swap(m_pPoint, m_pMark); |
245 | 27.8k | } |
246 | | |
247 | | /** A PaM marks a selection if Point and Mark are distinct positions. |
248 | | @return true if the PaM spans a selection |
249 | | */ |
250 | 13.1M | bool HasMark() const { return m_pPoint != m_pMark; } |
251 | | |
252 | 81.3M | const SwPosition *GetPoint() const { return m_pPoint; } |
253 | 130M | SwPosition *GetPoint() { return m_pPoint; } |
254 | 3.93M | const SwPosition *GetMark() const { return m_pMark; } |
255 | 3.19M | SwPosition *GetMark() { return m_pMark; } |
256 | | |
257 | | const SwPosition *Start() const |
258 | 13.5M | { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; } |
259 | | SwPosition *Start() |
260 | 5.33M | { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; } |
261 | | |
262 | | const SwPosition *End() const |
263 | 23.7M | { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; } |
264 | | SwPosition *End() |
265 | 4.43M | { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; } |
266 | | |
267 | | /// Because sometimes the cost of the operator<= can add up |
268 | | std::pair<const SwPosition *, const SwPosition *> StartEnd() const |
269 | 3.08M | { if ((*m_pPoint) <= (*m_pMark)) return { m_pPoint, m_pMark }; else return { m_pMark, m_pPoint }; } |
270 | | std::pair<SwPosition *, SwPosition *> StartEnd() |
271 | 29.0M | { if ((*m_pPoint) <= (*m_pMark)) return { m_pPoint, m_pMark }; else return { m_pMark, m_pPoint }; } |
272 | | |
273 | | /// @return current Node at Point/Mark |
274 | 10.1M | SwNode& GetPointNode() const { return m_pPoint->nNode.GetNode(); } |
275 | 19 | SwNode& GetMarkNode() const { return m_pMark->nNode.GetNode(); } |
276 | | |
277 | | /// @return current ContentNode at Point/Mark |
278 | 33.4M | SwContentNode* GetPointContentNode() const { return m_pPoint->nNode.GetNode().GetContentNode(); } |
279 | 0 | SwContentNode* GetMarkContentNode() const { return m_pMark->nNode.GetNode().GetContentNode(); } |
280 | | |
281 | | /** |
282 | | Normalizes PaM, i.e. sort point and mark. |
283 | | |
284 | | @param bPointFirst true: If the point is behind the mark then swap. |
285 | | false: If the mark is behind the point then swap. |
286 | | */ |
287 | | void Normalize(bool bPointFirst = true); |
288 | | |
289 | | /// @return the document (SwDoc) at which the PaM is registered |
290 | 48.1M | SwDoc& GetDoc() const { return m_pPoint->nNode.GetNode().GetDoc(); } |
291 | | |
292 | | SwPosition& GetBound( bool bOne = true ) |
293 | 2.83M | { return bOne ? m_Bound1 : m_Bound2; } |
294 | | const SwPosition& GetBound( bool bOne = true ) const |
295 | 0 | { return bOne ? m_Bound1 : m_Bound2; } |
296 | | |
297 | | /// Get number of page which contains cursor. |
298 | | sal_uInt16 GetPageNum( bool bAtPoint = true, const Point* pLayPos = nullptr ); |
299 | | |
300 | | /** Is in something protected (readonly) or selection contains |
301 | | something protected. */ |
302 | | bool HasReadonlySel(bool bFormView, bool isReplace) const; |
303 | | /** Is there hidden sections in the selected area. */ |
304 | | bool HasHiddenSections() const; |
305 | | |
306 | | bool ContainsPosition(const SwPosition & rPos) const |
307 | 4.97M | { |
308 | 4.97M | return *Start() <= rPos && rPos <= *End(); |
309 | 4.97M | } |
310 | | |
311 | | OUString GetText() const; |
312 | | // copy text into buffer |
313 | | void AppendTextTo(rtl::OUStringBuffer& rBuffer) const; |
314 | | void InvalidatePaM(); |
315 | | SwPaM* GetNext() |
316 | 1.67M | { return GetNextInRing(); } |
317 | | const SwPaM* GetNext() const |
318 | 36 | { return GetNextInRing(); } |
319 | | SwPaM* GetPrev() |
320 | 0 | { return GetPrevInRing(); } |
321 | | const SwPaM* GetPrev() const |
322 | 0 | { return GetPrevInRing(); } |
323 | | bool IsMultiSelection() const |
324 | 0 | { return !unique(); } |
325 | | |
326 | | void dumpAsXml(xmlTextWriterPtr pWriter) const; |
327 | | }; |
328 | | |
329 | | SW_DLLPUBLIC std::ostream &operator <<(std::ostream& s, const SwPaM& pam); |
330 | | |
331 | | bool CheckNodesRange(const SwNode&, const SwNode&, bool bChkSection); |
332 | | |
333 | | #endif // INCLUDED_SW_INC_PAM_HXX |
334 | | |
335 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |