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
20 #include <postithelper.hxx>
21 #include <PostItMgr.hxx>
22 #include <AnnotationWin.hxx>
23
24 #include <fmtfld.hxx>
25 #include <txtfld.hxx>
26 #include <ndtxt.hxx>
27 #include <pagefrm.hxx>
28 #include <rootfrm.hxx>
29 #include <txtfrm.hxx>
30 #include <IDocumentRedlineAccess.hxx>
31 #include <IDocumentFieldsAccess.hxx>
32 #include <IDocumentMarkAccess.hxx>
33 #include <redline.hxx>
34 #include <scriptinfo.hxx>
35 #include <calbck.hxx>
36 #include <IMark.hxx>
37 #include <sortedobjs.hxx>
38 #include <anchoredobject.hxx>
39 #include <fmtanchr.hxx>
40
41 class Point;
42
43 namespace
44 {
45 /// Checks if pAnnotationMark covers exactly rAnchorPos (the comment anchor).
AnnotationMarkCoversCommentAnchor(const sw::mark::IMark * pAnnotationMark,const SwPosition & rAnchorPos)46 bool AnnotationMarkCoversCommentAnchor(const sw::mark::IMark* pAnnotationMark,
47 const SwPosition& rAnchorPos)
48 {
49 if (!pAnnotationMark)
50 {
51 return false;
52 }
53
54 const SwPosition& rMarkStart = pAnnotationMark->GetMarkStart();
55 const SwPosition& rMarkEnd = pAnnotationMark->GetMarkEnd();
56
57 if (rMarkStart != rAnchorPos)
58 {
59 // This can be the as-char case: the comment placeholder character is exactly between the
60 // annotation mark start and end.
61 SwPosition aPosition(rMarkStart);
62 ++aPosition.nContent;
63 if (aPosition != rAnchorPos)
64 {
65 return false;
66 }
67
68 ++aPosition.nContent;
69 if (aPosition != rMarkEnd)
70 {
71 return false;
72 }
73
74 return true;
75 }
76
77 if (rMarkStart.nNode != rMarkEnd.nNode)
78 {
79 return false;
80 }
81
82 return rMarkEnd.nContent.GetIndex() == rMarkStart.nContent.GetIndex() + 1;
83 }
84
85 /**
86 * Finds the first draw object of rTextFrame which has the same anchor position as the start of
87 * rAnnotationMark.
88 */
GetAnchoredObjectOfAnnotationMark(const sw::mark::IMark & rAnnotationMark,const SwTextFrame & rTextFrame)89 SwAnchoredObject* GetAnchoredObjectOfAnnotationMark(const sw::mark::IMark& rAnnotationMark,
90 const SwTextFrame& rTextFrame)
91 {
92 const SwSortedObjs* pAnchored = rTextFrame.GetDrawObjs();
93 if (!pAnchored)
94 {
95 return nullptr;
96 }
97
98 for (SwAnchoredObject* pObject : *pAnchored)
99 {
100 SwFrameFormat& rFrameFormat = pObject->GetFrameFormat();
101 const SwPosition* pFrameAnchor = rFrameFormat.GetAnchor().GetContentAnchor();
102 if (!pFrameAnchor)
103 {
104 continue;
105 }
106
107 if (rAnnotationMark.GetMarkStart() == *pFrameAnchor)
108 {
109 return pObject;
110 }
111 }
112
113 return nullptr;
114 }
115 }
116
SwSidebarItem(const bool aFocus)117 SwSidebarItem::SwSidebarItem(const bool aFocus)
118 : mpPostIt(nullptr)
119 , mbShow(true)
120 , mbFocus(aFocus)
121 , mbPendingLayout(false)
122 , mLayoutStatus(SwPostItHelper::INVISIBLE)
123 , maLayoutInfo()
124 {
125 }
126
~SwSidebarItem()127 SwSidebarItem::~SwSidebarItem() {}
128
getLayoutInfos(SwLayoutInfo & o_rInfo,const SwPosition & rAnchorPos,const sw::mark::IMark * pAnnotationMark)129 SwPostItHelper::SwLayoutStatus SwPostItHelper::getLayoutInfos(
130 SwLayoutInfo& o_rInfo,
131 const SwPosition& rAnchorPos,
132 const sw::mark::IMark* pAnnotationMark )
133 {
134 SwLayoutStatus aRet = INVISIBLE;
135 SwTextNode* pTextNode = rAnchorPos.nNode.GetNode().GetTextNode();
136 if ( pTextNode == nullptr )
137 return aRet;
138
139 SwIterator<SwTextFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pTextNode);
140 for( SwTextFrame* pTextFrame = aIter.First(); pTextFrame != nullptr; pTextFrame = aIter.Next() )
141 {
142 if( !pTextFrame->IsFollow() )
143 {
144 pTextFrame = pTextFrame->GetFrameAtPos( rAnchorPos );
145 SwPageFrame *pPage = pTextFrame ? pTextFrame->FindPageFrame() : nullptr;
146 if ( pPage != nullptr && !pPage->IsInvalid() && !pPage->IsInvalidFly() )
147 {
148 aRet = VISIBLE;
149
150 o_rInfo.mpAnchorFrame = pTextFrame;
151 {
152 DisableCallbackAction a(*pTextFrame->getRootFrame());
153 bool bPositionFromCommentAnchor = true;
154 if (AnnotationMarkCoversCommentAnchor(pAnnotationMark, rAnchorPos))
155 {
156 SwAnchoredObject* pFrame
157 = GetAnchoredObjectOfAnnotationMark(*pAnnotationMark, *pTextFrame);
158 if (pFrame)
159 {
160 o_rInfo.mPosition = pFrame->GetObjRect();
161 bPositionFromCommentAnchor = false;
162 }
163 }
164 if (bPositionFromCommentAnchor)
165 {
166 pTextFrame->GetCharRect(o_rInfo.mPosition, rAnchorPos, nullptr, false);
167 }
168 o_rInfo.mPositionFromCommentAnchor = bPositionFromCommentAnchor;
169 }
170 if (pAnnotationMark != nullptr)
171 {
172 const SwPosition& rAnnotationStartPos = pAnnotationMark->GetMarkStart();
173 o_rInfo.mnStartNodeIdx = rAnnotationStartPos.nNode.GetIndex();
174 o_rInfo.mnStartContent = rAnnotationStartPos.nContent.GetIndex();
175 }
176 else
177 {
178 o_rInfo.mnStartNodeIdx = 0;
179 o_rInfo.mnStartContent = -1;
180 }
181 o_rInfo.mPageFrame = pPage->getFrameArea();
182 o_rInfo.mPagePrtArea = pPage->getFramePrintArea();
183 o_rInfo.mPagePrtArea.Pos() += o_rInfo.mPageFrame.Pos();
184 o_rInfo.mnPageNumber = pPage->GetPhyPageNum();
185 o_rInfo.meSidebarPosition = pPage->SidebarPosition();
186 o_rInfo.mRedlineAuthor = 0;
187
188 const IDocumentRedlineAccess& rIDRA = pTextNode->getIDocumentRedlineAccess();
189 if( IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() ) )
190 {
191 const SwRangeRedline* pRedline = rIDRA.GetRedline( rAnchorPos, nullptr );
192 if( pRedline )
193 {
194 if( RedlineType::Insert == pRedline->GetType() )
195 aRet = INSERTED;
196 else if( RedlineType::Delete == pRedline->GetType() )
197 {
198 bool bDeleted = pAnnotationMark == nullptr;
199 if( !bDeleted )
200 {
201 IDocumentMarkAccess& rDMA(*pTextNode->GetDoc().getIDocumentMarkAccess());
202 IDocumentMarkAccess::const_iterator_t pAnnotationBookmark =
203 rDMA.findAnnotationBookmark(pAnnotationMark->GetName());
204 // tdf#140980 only really deleted, if there is no helper bookmark
205 // in ChangesInMargin mode
206 if ( pAnnotationBookmark == rDMA.getBookmarksEnd() )
207 bDeleted = true;
208 }
209 if ( bDeleted )
210 aRet = DELETED;
211 }
212 o_rInfo.mRedlineAuthor = pRedline->GetAuthor();
213 }
214 }
215 }
216 }
217 }
218
219 return ( (aRet==VISIBLE) && SwScriptInfo::IsInHiddenRange( *pTextNode , rAnchorPos.nContent.GetIndex()) )
220 ? HIDDEN
221 : aRet;
222 }
223
getLayoutHeight(const SwRootFrame * pRoot)224 tools::Long SwPostItHelper::getLayoutHeight( const SwRootFrame* pRoot )
225 {
226 tools::Long nRet = pRoot ? pRoot->getFrameArea().Height() : 0;
227 return nRet;
228 }
229
setSidebarChanged(SwRootFrame * pRoot,bool bBrowseMode)230 void SwPostItHelper::setSidebarChanged( SwRootFrame* pRoot, bool bBrowseMode )
231 {
232 if( pRoot )
233 {
234 pRoot->SetSidebarChanged();
235 if( bBrowseMode )
236 pRoot->InvalidateBrowseWidth();
237 }
238 }
239
getPageInfo(SwRect & rPageFrame,const SwRootFrame * pRoot,const Point & rPoint)240 tools::ULong SwPostItHelper::getPageInfo( SwRect& rPageFrame, const SwRootFrame* pRoot, const Point& rPoint )
241 {
242 tools::ULong nRet = 0;
243 const SwFrame* pPage = pRoot->GetPageAtPos( rPoint, nullptr, true );
244 if( pPage )
245 {
246 nRet = pPage->GetPhyPageNum();
247 rPageFrame = pPage->getFrameArea();
248 }
249 return nRet;
250 }
251
GetAnchorPosition() const252 SwPosition SwAnnotationItem::GetAnchorPosition() const
253 {
254 SwTextField* pTextField = mrFormatField.GetTextField();
255 SwTextNode* pTextNode = pTextField->GetpTextNode();
256
257 SwPosition aPos( *pTextNode );
258 aPos.nContent.Assign( pTextNode, pTextField->GetStart() );
259 return aPos;
260 }
261
UseElement(SwRootFrame const & rLayout,IDocumentRedlineAccess const & rIDRA)262 bool SwAnnotationItem::UseElement(SwRootFrame const& rLayout,
263 IDocumentRedlineAccess const& rIDRA)
264 {
265 return mrFormatField.IsFieldInDoc()
266 && (!rLayout.IsHideRedlines()
267 || !sw::IsFieldDeletedInModel(rIDRA, *mrFormatField.GetTextField()));
268 }
269
GetSidebarWindow(SwEditWin & rEditWin,SwPostItMgr & aMgr)270 VclPtr<sw::annotation::SwAnnotationWin> SwAnnotationItem::GetSidebarWindow(
271 SwEditWin& rEditWin,
272 SwPostItMgr& aMgr)
273 {
274 return VclPtr<sw::annotation::SwAnnotationWin>::Create( rEditWin,
275 aMgr,
276 *this,
277 &mrFormatField );
278 }
279
280 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
281