LibreOffice Module sw (master)  1
accframebase.cxx
Go to the documentation of this file.
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 <com/sun/star/accessibility/AccessibleStateType.hpp>
21 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
23 #include <vcl/svapp.hxx>
24 #include <vcl/window.hxx>
25 #include <frmfmt.hxx>
26 #include <flyfrm.hxx>
27 #include <fmtcntnt.hxx>
28 #include <ndindex.hxx>
29 #include <fesh.hxx>
30 #include <hints.hxx>
31 #include <accmap.hxx>
32 #include "accframebase.hxx"
33 
34 #include <crsrsh.hxx>
35 #include <notxtfrm.hxx>
36 #include <ndtxt.hxx>
37 #include <undobj.hxx>
38 #include <fmtanchr.hxx>
39 
40 using namespace ::com::sun::star;
41 using namespace ::com::sun::star::accessibility;
42 
44 {
45  bool bRet = false;
46 
47  assert(GetMap());
48  const SwViewShell *pVSh = GetMap()->GetShell();
49  assert(pVSh);
50  if( auto pFESh = dynamic_cast<const SwFEShell*>(pVSh) )
51  {
52  const SwFrame *pFlyFrame = pFESh->GetSelectedFlyFrame();
53  if( pFlyFrame == GetFrame() )
54  bRet = true;
55  }
56 
57  return bRet;
58 }
59 
61  ::utl::AccessibleStateSetHelper& rStateSet )
62 {
63  SwAccessibleContext::GetStates( rStateSet );
64 
65  const SwViewShell *pVSh = GetMap()->GetShell();
66  assert(pVSh);
67 
68  if (dynamic_cast<const SwFEShell*>(pVSh))
69  {
70  // SELECTABLE
71  rStateSet.AddState(AccessibleStateType::SELECTABLE);
72  // FOCUSABLE
73  rStateSet.AddState(AccessibleStateType::FOCUSABLE);
74  }
75 
76  // SELECTED and FOCUSED
77  if( IsSelected() )
78  {
79  rStateSet.AddState( AccessibleStateType::SELECTED );
80  SAL_WARN_IF(!m_bIsSelected, "sw.a11y", "bSelected out of sync");
82  GetMap()->SetCursorContext( xThis );
83 
84  vcl::Window *pWin = GetWindow();
85  if( pWin && pWin->HasFocus() )
86  rStateSet.AddState( AccessibleStateType::FOCUSED );
87  }
88  if( GetSelectedState() )
89  rStateSet.AddState( AccessibleStateType::SELECTED );
90 }
91 
93 {
95  if( pFlyFrame->Lower() )
96  {
97  if( pFlyFrame->Lower()->IsNoTextFrame() )
98  {
99  const SwNoTextFrame *const pContentFrame =
100  static_cast<const SwNoTextFrame *>(pFlyFrame->Lower());
101  nType = pContentFrame->GetNode()->GetNodeType();
102  }
103  }
104  else
105  {
106  const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
107  const SwFormatContent& rContent = pFrameFormat->GetContent();
108  const SwNodeIndex *pNdIdx = rContent.GetContentIdx();
109  if( pNdIdx )
110  {
111  const SwContentNode *pCNd =
112  (pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetContentNode();
113  if( pCNd )
114  nType = pCNd->GetNodeType();
115  }
116  }
117 
118  return nType;
119 }
120 
122  std::shared_ptr<SwAccessibleMap> const& pInitMap,
123  sal_Int16 nInitRole,
124  const SwFlyFrame* pFlyFrame ) :
125  SwAccessibleContext( pInitMap, nInitRole, pFlyFrame ),
126  m_bIsSelected( false )
127 {
128  const SwFrameFormat* pFrameFormat = pFlyFrame->GetFormat();
129  if(pFrameFormat)
130  StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
131 
132  SetName( pFrameFormat->GetName() );
133 
135 }
136 
138 {
139  bool bNewSelected = IsSelected();
140  bool bOldSelected;
141 
142  {
143  std::scoped_lock aGuard( m_Mutex );
144  bOldSelected = m_bIsSelected;
145  m_bIsSelected = bNewSelected;
146  }
147 
148  if( bNewSelected )
149  {
150  // remember that object as the one that has the caret. This is
151  // necessary to notify that object if the cursor leaves it.
153  GetMap()->SetCursorContext( xThis );
154  }
155 
156  if( bOldSelected == bNewSelected )
157  return;
158 
159  vcl::Window *pWin = GetWindow();
160  if( pWin && pWin->HasFocus() && bNewSelected )
161  FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
162  if( pWin && pWin->HasFocus() && !bNewSelected )
163  FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
164  if(!bNewSelected)
165  return;
166 
167  uno::Reference< XAccessible > xParent( GetWeakParent() );
168  if( xParent.is() )
169  {
170  SwAccessibleContext *pAcc =
171  static_cast <SwAccessibleContext *>( xParent.get() );
172 
173  AccessibleEventObject aEvent;
174  aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
175  uno::Reference< XAccessible > xChild(this);
176  aEvent.NewValue <<= xChild;
177  pAcc->FireAccessibleEvent( aEvent );
178  }
179 }
180 
182 {
183  vcl::Window *pWin = GetWindow();
184  if( !pWin )
185  return;
186 
187  bool bSelected;
188 
189  {
190  std::scoped_lock aGuard( m_Mutex );
191  bSelected = m_bIsSelected;
192  }
193  assert(bSelected && "focus object should be selected");
194 
195  FireStateChangedEvent( AccessibleStateType::FOCUSED,
196  pWin->HasFocus() && bSelected );
197 }
198 
200 {
201  std::scoped_lock aGuard( m_Mutex );
202  return m_bIsSelected;
203 }
204 
206 {
207 }
208 
210 {
211  if(rHint.GetId() == SfxHintId::Dying)
212  {
213  EndListeningAll();
214  }
215  else if (rHint.GetId() == SfxHintId::SwLegacyModify)
216  {
217  auto pLegacyModifyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
218  const sal_uInt16 nWhich = pLegacyModifyHint->GetWhich();
219  const SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrame*>(GetFrame());
220  if(nWhich == RES_NAME_CHANGED && pFlyFrame)
221  {
222  const SwFrameFormat* pFrameFormat = pFlyFrame->GetFormat();
223 
224  const OUString sOldName( GetName() );
225  assert( !pLegacyModifyHint->m_pOld ||
226  static_cast<const SwStringMsgPoolItem *>(pLegacyModifyHint->m_pOld)->GetString() == GetName());
227 
228  SetName( pFrameFormat->GetName() );
229  assert( !pLegacyModifyHint->m_pNew ||
230  static_cast<const SwStringMsgPoolItem *>(pLegacyModifyHint->m_pNew)->GetString() == GetName());
231 
232  if( sOldName != GetName() )
233  {
234  AccessibleEventObject aEvent;
235  aEvent.EventId = AccessibleEventId::NAME_CHANGED;
236  aEvent.OldValue <<= sOldName;
237  aEvent.NewValue <<= GetName();
238  FireAccessibleEvent( aEvent );
239  }
240  }
241  }
242 }
243 
244 void SwAccessibleFrameBase::Dispose(bool bRecursive, bool bCanSkipInvisible)
245 {
246  SolarMutexGuard aGuard;
247  EndListeningAll();
248  SwAccessibleContext::Dispose(bRecursive, bCanSkipInvisible);
249 }
250 
251 //Get the selection cursor of the document.
253 {
254  // get the cursor shell; if we don't have any, we don't have a
255  // cursor/selection either
256  SwPaM* pCursor = nullptr;
257  SwCursorShell* pCursorShell = GetCursorShell();
258  if( pCursorShell != nullptr && !pCursorShell->IsTableMode() )
259  {
260  SwFEShell *pFESh = dynamic_cast<SwFEShell*>( pCursorShell);
261  if( !pFESh ||
262  !(pFESh->IsFrameSelected() || pFESh->IsObjSelected() > 0) )
263  {
264  // get the selection, and test whether it affects our text node
265  pCursor = pCursorShell->GetCursor( false /* ??? */ );
266  }
267  }
268 
269  return pCursor;
270 }
271 
272 //Return the selected state of the object.
273 //when the object's anchor are in the selection cursor, we should return true.
275 {
276  SolarMutexGuard aGuard;
277 
278  if(GetMap()->IsDocumentSelAll())
279  {
280  return true;
281  }
282 
283  // SELECTED.
284  SwFlyFrame* pFlyFrame = getFlyFrame();
285  const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
286  const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
287  const SwPosition *pPos = rAnchor.GetContentAnchor();
288  if( !pPos )
289  return false;
290  int nIndex = pPos->nContent.GetIndex();
291  if( pPos->nNode.GetNode().GetTextNode() )
292  {
293  SwPaM* pCursor = GetCursor();
294  if( pCursor != nullptr )
295  {
296  const SwTextNode* pNode = pPos->nNode.GetNode().GetTextNode();
297  SwNodeOffset nHere = pNode->GetIndex();
298 
299  // iterate over ring
300  SwPaM* pRingStart = pCursor;
301  do
302  {
303  // ignore, if no mark
304  if( pCursor->HasMark() )
305  {
306  // check whether nHere is 'inside' pCursor
307  SwPosition* pStart = pCursor->Start();
308  SwNodeOffset nStartIndex = pStart->nNode.GetIndex();
309  SwPosition* pEnd = pCursor->End();
310  SwNodeOffset nEndIndex = pEnd->nNode.GetIndex();
311  if( ( nHere >= nStartIndex ) && (nHere <= nEndIndex) )
312  {
313  if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
314  {
315  if( ((nHere == nStartIndex) && (nIndex >= pStart->nContent.GetIndex())) || (nHere > nStartIndex) )
316  if( ((nHere == nEndIndex) && (nIndex < pEnd->nContent.GetIndex())) || (nHere < nEndIndex) )
317  return true;
318  }
319  else if( rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA )
320  {
321  if (IsSelectFrameAnchoredAtPara(*pPos, *pStart, *pEnd))
322  return true;
323  }
324  else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
325  {
326  if (IsDestroyFrameAnchoredAtChar(*pPos, *pStart, *pEnd))
327  {
328  return true;
329  }
330  }
331  break;
332  }
333  // else: this PaM doesn't point to this paragraph
334  }
335  // else: this PaM is collapsed and doesn't select anything
336 
337  // next PaM in ring
338  pCursor = pCursor->GetNext();
339  }
340  while( pCursor != pRingStart );
341  }
342  }
343  return false;
344 }
345 
347 {
348  SwFlyFrame* pFlyFrame = nullptr;
349 
350  const SwFrame* pFrame = GetFrame();
351  assert(pFrame);
352  if( pFrame->IsFlyFrame() )
353  {
354  pFlyFrame = static_cast<SwFlyFrame*>( const_cast<SwFrame*>( pFrame ) );
355  }
356 
357  return pFlyFrame;
358 }
359 
361 {
362  bool bParaSelected = GetSelectedState() || IsSelected();
363 
364  if (m_isSelectedInDoc != bParaSelected)
365  {
366  m_isSelectedInDoc = bParaSelected;
367  FireStateChangedEvent( AccessibleStateType::SELECTED, bParaSelected );
368  return true;
369  }
370  return false;
371 }
372 
373 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Base class of the Writer layout elements.
Definition: frame.hxx:314
void FireAccessibleEvent(css::accessibility::AccessibleEventObject &rEvent)
Definition: acccontext.cxx:442
sal_Int32 nIndex
virtual const SwFlyFrameFormat * GetFormat() const override
Definition: fly.cxx:2893
Marks a position in the document model.
Definition: pam.hxx:36
sal_uInt16 GetWhich() const
Definition: calbck.hxx:74
virtual void GetStates(::utl::AccessibleStateSetHelper &rStateSet) override
virtual void InvalidateFocus_() override
SwNodeIndex nNode
Definition: pam.hxx:38
bool IsTableMode() const
Definition: crsrsh.hxx:648
SwAccessibleFrameBase(std::shared_ptr< SwAccessibleMap > const &pInitMap, sal_Int16 nInitRole, const SwFlyFrame *pFlyFrame)
vcl::Window * GetWindow()
Definition: acccontext.cxx:82
virtual void Notify(const SfxHint &) override
SwNode & GetNode() const
Definition: ndindex.hxx:119
bool IsSelectFrameAnchoredAtPara(SwPosition const &rAnchorPos, SwPosition const &rStart, SwPosition const &rEnd, DelContentType const nDelContentType)
is a fly anchored at paragraph at rAnchorPos selected?
Definition: undobj.cxx:1643
Content, content of frame (header, footer, fly).
Definition: fmtcntnt.hxx:31
bool IsDestroyFrameAnchoredAtChar(SwPosition const &rAnchorPos, SwPosition const &rStart, SwPosition const &rEnd, DelContentType const nDelContentType)
will DelContentIndex destroy a frame anchored at character at rAnchorPos?
Definition: undobj.cxx:1602
virtual bool SetSelectedState(bool bSelected) override
SfxHintId GetId() const
SwCursorShell * GetCursorShell()
convenience method to get SwCursorShell through accessibility map
Definition: acccontext.cxx:100
bool IsFlyFrame() const
Definition: frame.hxx:1210
SwViewShell * GetShell() const
Definition: accmap.hxx:174
SwNodeType GetNodeType() const
Definition: node.hxx:146
SwIndex nContent
Definition: pam.hxx:39
const SwFrame * GetFrame() const
Definition: accframe.hxx:103
const OUString & GetName() const
Definition: format.hxx:131
virtual bool HasCursor() override
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:152
SwPaM * GetNext()
Definition: pam.hxx:265
SwFlyFrame * getFlyFrame() const
void FireStateChangedEvent(sal_Int16 nState, bool bNewState)
Definition: acccontext.cxx:466
void EndListeningAll()
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
Style of a layout element.
Definition: frmfmt.hxx:59
SwNodeType
Definition: ndtyp.hxx:28
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
const OUString & GetName() const
Definition: acccontext.hxx:339
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
const SwFrame * Lower() const
Definition: layfrm.hxx:101
SwContentNode * GetContentNode()
Definition: node.hxx:625
SwNodeOffset GetIndex() const
Definition: node.hxx:292
FlyAnchors.
Definition: fmtanchr.hxx:34
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:206
Marks a node in the document model.
Definition: ndindex.hxx:30
bool StartListening(SvtBroadcaster &rBroadcaster)
static SwNodeType GetNodeType(const SwFlyFrame *pFlyFrame)
const SwPosition * Start() const
Definition: pam.hxx:213
const SwNodeIndex * GetContentIdx() const
Definition: fmtcntnt.hxx:46
virtual void InvalidateCursorPos_() override
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
const SwContentNode * GetNode() const
Definition: notxtfrm.hxx:66
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:195
general base class for all free-flowing frames
Definition: flyfrm.hxx:78
std::mutex m_Mutex
Definition: acccontext.hxx:67
virtual ~SwAccessibleFrameBase() override
#define SAL_WARN_IF(condition, area, stream)
virtual void Dispose(bool bRecursive, bool bCanSkipInvisible=true)
const SwNodes & GetNodes() const
Definition: ndindex.hxx:156
virtual void GetStates(::utl::AccessibleStateSetHelper &rStateSet)
Definition: acccontext.cxx:480
sal_Int32 GetIndex() const
Definition: index.hxx:91
bool IsNoTextFrame() const
Definition: frame.hxx:1238
const SwPosition * End() const
Definition: pam.hxx:218
size_t IsObjSelected() const
Definition: feshview.cxx:1246
QPRO_FUNC_TYPE nType
css::uno::Reference< css::accessibility::XAccessible > GetWeakParent() const
Definition: acccontext.cxx:74
SwAccessibleMap * GetMap()
Definition: acccontext.hxx:115
const SwFormatContent & GetContent(bool=true) const
Definition: fmtcntnt.hxx:55
constexpr TypedWhichId< SwStringMsgPoolItem > RES_NAME_CHANGED(187)
void SetCursorContext(const ::rtl::Reference< SwAccessibleContext > &rCursorContext)
Definition: accmap.cxx:2728
bool HasFocus() const
void AddState(sal_Int16 aState)
void SetName(const OUString &rName)
Definition: acccontext.hxx:102
bool IsFrameSelected() const
Definition: feshview.cxx:1254
AnyEventRef aEvent
virtual void Dispose(bool bRecursive, bool bCanSkipInvisible=true) override
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:864
bool m_bDetectedRangeSegmentation false