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 <osl/mutex.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/window.hxx>
26 #include <frmfmt.hxx>
27 #include <ndnotxt.hxx>
28 #include <flyfrm.hxx>
29 #include <cntfrm.hxx>
30 #include <fmtcntnt.hxx>
31 #include <ndindex.hxx>
32 #include <fesh.hxx>
33 #include <hints.hxx>
34 #include <accmap.hxx>
35 #include "accframebase.hxx"
36 
37 #include <crsrsh.hxx>
38 #include <txtfrm.hxx>
39 #include <notxtfrm.hxx>
40 #include <ndtxt.hxx>
41 #include <undobj.hxx>
42 #include <dcontact.hxx>
43 #include <fmtanchr.hxx>
44 
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::accessibility;
47 
49 {
50  bool bRet = false;
51 
52  assert(GetMap());
53  const SwViewShell *pVSh = GetMap()->GetShell();
54  assert(pVSh);
55  if( auto pFESh = dynamic_cast<const SwFEShell*>(pVSh) )
56  {
57  const SwFrame *pFlyFrame = pFESh->GetSelectedFlyFrame();
58  if( pFlyFrame == GetFrame() )
59  bRet = true;
60  }
61 
62  return bRet;
63 }
64 
66  ::utl::AccessibleStateSetHelper& rStateSet )
67 {
68  SwAccessibleContext::GetStates( rStateSet );
69 
70  const SwViewShell *pVSh = GetMap()->GetShell();
71  assert(pVSh);
72 
73  if (dynamic_cast<const SwFEShell*>(pVSh))
74  {
75  // SELECTABLE
76  rStateSet.AddState(AccessibleStateType::SELECTABLE);
77  // FOCUSABLE
78  rStateSet.AddState(AccessibleStateType::FOCUSABLE);
79  }
80 
81  // SELECTED and FOCUSED
82  if( IsSelected() )
83  {
84  rStateSet.AddState( AccessibleStateType::SELECTED );
85  SAL_WARN_IF(!m_bIsSelected, "sw.a11y", "bSelected out of sync");
87  GetMap()->SetCursorContext( xThis );
88 
89  vcl::Window *pWin = GetWindow();
90  if( pWin && pWin->HasFocus() )
91  rStateSet.AddState( AccessibleStateType::FOCUSED );
92  }
93  if( GetSelectedState() )
94  rStateSet.AddState( AccessibleStateType::SELECTED );
95 }
96 
98 {
100  if( pFlyFrame->Lower() )
101  {
102  if( pFlyFrame->Lower()->IsNoTextFrame() )
103  {
104  const SwNoTextFrame *const pContentFrame =
105  static_cast<const SwNoTextFrame *>(pFlyFrame->Lower());
106  nType = pContentFrame->GetNode()->GetNodeType();
107  }
108  }
109  else
110  {
111  const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
112  const SwFormatContent& rContent = pFrameFormat->GetContent();
113  const SwNodeIndex *pNdIdx = rContent.GetContentIdx();
114  if( pNdIdx )
115  {
116  const SwContentNode *pCNd =
117  (pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetContentNode();
118  if( pCNd )
119  nType = pCNd->GetNodeType();
120  }
121  }
122 
123  return nType;
124 }
125 
127  std::shared_ptr<SwAccessibleMap> const& pInitMap,
128  sal_Int16 nInitRole,
129  const SwFlyFrame* pFlyFrame ) :
130  SwAccessibleContext( pInitMap, nInitRole, pFlyFrame ),
131  m_bIsSelected( false )
132 {
133  const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
134  const_cast< SwFrameFormat * >( pFrameFormat )->Add( this );
135 
136  SetName( pFrameFormat->GetName() );
137 
139 }
140 
142 {
143  bool bNewSelected = IsSelected();
144  bool bOldSelected;
145 
146  {
147  osl::MutexGuard aGuard( m_Mutex );
148  bOldSelected = m_bIsSelected;
149  m_bIsSelected = bNewSelected;
150  }
151 
152  if( bNewSelected )
153  {
154  // remember that object as the one that has the caret. This is
155  // necessary to notify that object if the cursor leaves it.
157  GetMap()->SetCursorContext( xThis );
158  }
159 
160  if( bOldSelected != bNewSelected )
161  {
162  vcl::Window *pWin = GetWindow();
163  if( pWin && pWin->HasFocus() && bNewSelected )
164  FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
165  if( pWin && pWin->HasFocus() && !bNewSelected )
166  FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
167  if(bNewSelected)
168  {
169  uno::Reference< XAccessible > xParent( GetWeakParent() );
170  if( xParent.is() )
171  {
172  SwAccessibleContext *pAcc =
173  static_cast <SwAccessibleContext *>( xParent.get() );
174 
175  AccessibleEventObject aEvent;
176  aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
177  uno::Reference< XAccessible > xChild(this);
178  aEvent.NewValue <<= xChild;
179  pAcc->FireAccessibleEvent( aEvent );
180  }
181  }
182  }
183 }
184 
186 {
187  vcl::Window *pWin = GetWindow();
188  if( pWin )
189  {
190  bool bSelected;
191 
192  {
193  osl::MutexGuard aGuard( m_Mutex );
194  bSelected = m_bIsSelected;
195  }
196  assert(bSelected && "focus object should be selected");
197 
198  FireStateChangedEvent( AccessibleStateType::FOCUSED,
199  pWin->HasFocus() && bSelected );
200  }
201 }
202 
204 {
205  osl::MutexGuard aGuard( m_Mutex );
206  return m_bIsSelected;
207 }
208 
210 {
211 }
212 
214 {
215  sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ;
216  switch( nWhich )
217  {
218  case RES_NAME_CHANGED:
219  {
220  const SwFlyFrame *pFlyFrame = static_cast< const SwFlyFrame * >( GetFrame() );
221  if( pFlyFrame )
222  {
223  const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
224  assert(pFrameFormat == GetRegisteredIn() && "invalid frame");
225 
226  const OUString sOldName( GetName() );
227  assert( !pOld ||
228  static_cast<const SwStringMsgPoolItem *>(pOld)->GetString() == GetName());
229 
230  SetName( pFrameFormat->GetName() );
231  assert( !pNew ||
232  static_cast<const SwStringMsgPoolItem *>(pNew)->GetString() == GetName());
233 
234  if( sOldName != GetName() )
235  {
236  AccessibleEventObject aEvent;
237  aEvent.EventId = AccessibleEventId::NAME_CHANGED;
238  aEvent.OldValue <<= sOldName;
239  aEvent.NewValue <<= GetName();
240  FireAccessibleEvent( aEvent );
241  }
242  }
243  break;
244  }
245  case RES_OBJECTDYING:
246  // mba: it seems that this class intentionally does not call code in base class SwClient
247  if( pOld && ( GetRegisteredIn() == static_cast< SwModify *>( static_cast< const SwPtrMsgPoolItem * >( pOld )->pObject ) ) )
248  EndListeningAll();
249  break;
250 
251  case RES_FMT_CHG:
252  if( pOld &&
253  static_cast< const SwFormatChg * >(pNew)->pChangedFormat == GetRegisteredIn() &&
254  static_cast< const SwFormatChg * >(pOld)->pChangedFormat->IsFormatInDTOR() )
255  EndListeningAll();
256  break;
257 
258  default:
259  // mba: former call to base class method removed as it is meant to handle only RES_OBJECTDYING
260  break;
261  }
262 }
263 
264 void SwAccessibleFrameBase::Dispose(bool bRecursive, bool bCanSkipInvisible)
265 {
266  SolarMutexGuard aGuard;
267  EndListeningAll();
268  SwAccessibleContext::Dispose(bRecursive, bCanSkipInvisible);
269 }
270 
271 //Get the selection cursor of the document.
273 {
274  // get the cursor shell; if we don't have any, we don't have a
275  // cursor/selection either
276  SwPaM* pCursor = nullptr;
277  SwCursorShell* pCursorShell = GetCursorShell();
278  if( pCursorShell != nullptr && !pCursorShell->IsTableMode() )
279  {
280  SwFEShell *pFESh = dynamic_cast<const SwFEShell*>( pCursorShell) != nullptr
281  ? static_cast< SwFEShell * >( pCursorShell ) : nullptr;
282  if( !pFESh ||
283  !(pFESh->IsFrameSelected() || pFESh->IsObjSelected() > 0) )
284  {
285  // get the selection, and test whether it affects our text node
286  pCursor = pCursorShell->GetCursor( false /* ??? */ );
287  }
288  }
289 
290  return pCursor;
291 }
292 
293 //Return the selected state of the object.
294 //when the object's anchor are in the selection cursor, we should return true.
296 {
297  SolarMutexGuard aGuard;
298 
299  if(GetMap()->IsDocumentSelAll())
300  {
301  return true;
302  }
303 
304  // SELECTED.
305  SwFlyFrame* pFlyFrame = getFlyFrame();
306  const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
307  const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
308  const SwPosition *pPos = rAnchor.GetContentAnchor();
309  if( !pPos )
310  return false;
311  int nIndex = pPos->nContent.GetIndex();
312  if( pPos->nNode.GetNode().GetTextNode() )
313  {
314  SwPaM* pCursor = GetCursor();
315  if( pCursor != nullptr )
316  {
317  const SwTextNode* pNode = pPos->nNode.GetNode().GetTextNode();
318  sal_uLong nHere = pNode->GetIndex();
319 
320  // iterate over ring
321  SwPaM* pRingStart = pCursor;
322  do
323  {
324  // ignore, if no mark
325  if( pCursor->HasMark() )
326  {
327  // check whether nHere is 'inside' pCursor
328  SwPosition* pStart = pCursor->Start();
329  sal_uLong nStartIndex = pStart->nNode.GetIndex();
330  SwPosition* pEnd = pCursor->End();
331  sal_uLong nEndIndex = pEnd->nNode.GetIndex();
332  if( ( nHere >= nStartIndex ) && (nHere <= nEndIndex) )
333  {
334  if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
335  {
336  if( ((nHere == nStartIndex) && (nIndex >= pStart->nContent.GetIndex())) || (nHere > nStartIndex) )
337  if( ((nHere == nEndIndex) && (nIndex < pEnd->nContent.GetIndex())) || (nHere < nEndIndex) )
338  return true;
339  }
340  else if( rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA )
341  {
342  if( ((nHere > nStartIndex) || pStart->nContent.GetIndex() ==0 )
343  && (nHere < nEndIndex ) )
344  return true;
345  }
346  else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
347  {
348  if (IsDestroyFrameAnchoredAtChar(*pPos, *pStart, *pEnd))
349  {
350  return true;
351  }
352  }
353  break;
354  }
355  // else: this PaM doesn't point to this paragraph
356  }
357  // else: this PaM is collapsed and doesn't select anything
358 
359  // next PaM in ring
360  pCursor = pCursor->GetNext();
361  }
362  while( pCursor != pRingStart );
363  }
364  }
365  return false;
366 }
367 
369 {
370  SwFlyFrame* pFlyFrame = nullptr;
371 
372  const SwFrame* pFrame = GetFrame();
373  assert(pFrame);
374  if( pFrame->IsFlyFrame() )
375  {
376  pFlyFrame = static_cast<SwFlyFrame*>( const_cast<SwFrame*>( pFrame ) );
377  }
378 
379  return pFlyFrame;
380 }
381 
383 {
384  bool bParaSelected = GetSelectedState() || IsSelected();
385 
386  if (m_isSelectedInDoc != bParaSelected)
387  {
388  m_isSelectedInDoc = bParaSelected;
389  FireStateChangedEvent( AccessibleStateType::SELECTED, bParaSelected );
390  return true;
391  }
392  return false;
393 }
394 
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Base class of the Writer layout elements.
Definition: frame.hxx:295
sal_uLong GetIndex() const
Definition: node.hxx:282
void FireAccessibleEvent(css::accessibility::AccessibleEventObject &rEvent)
Definition: acccontext.cxx:443
virtual const SwFlyFrameFormat * GetFormat() const override
Definition: fly.cxx:2816
virtual void Modify(const SfxPoolItem *pOld, const SfxPoolItem *pNew) override
Marks a position in the document model.
Definition: pam.hxx:35
SwPaM * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:188
virtual void GetStates(::utl::AccessibleStateSetHelper &rStateSet) override
virtual void InvalidateFocus_() override
SwNodeIndex nNode
Definition: pam.hxx:37
bool IsTableMode() const
Definition: crsrsh.hxx:646
SwAccessibleFrameBase(std::shared_ptr< SwAccessibleMap > const &pInitMap, sal_Int16 nInitRole, const SwFlyFrame *pFlyFrame)
sal_uIntPtr sal_uLong
vcl::Window * GetWindow()
Definition: acccontext.cxx:86
SwNode & GetNode() const
Definition: ndindex.hxx:118
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:1546
OUString GetString(int nId)
SwCursorShell * GetCursorShell()
convenience method to get SwCursorShell through accessibility map
Definition: acccontext.cxx:104
bool IsFlyFrame() const
Definition: frame.hxx:1186
SwViewShell * GetShell() const
Definition: accmap.hxx:169
FUNC_TYPE const nType
SwNodeType GetNodeType() const
Definition: node.hxx:144
SwIndex nContent
Definition: pam.hxx:38
const SwFrame * GetFrame() const
Definition: accframe.hxx:103
const OUString & GetName() const
Definition: format.hxx:111
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
virtual bool HasCursor() override
SwPaM * GetNext()
Definition: pam.hxx:264
void EndListeningAll()
Definition: calbck.cxx:124
SwFlyFrame * getFlyFrame() const
void FireStateChangedEvent(sal_Int16 nState, bool bNewState)
Definition: acccontext.cxx:467
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
Style of a layout element.
Definition: frmfmt.hxx:57
SwNodeType
Definition: ndtyp.hxx:28
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
const OUString & GetName() const
Definition: acccontext.hxx:333
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
const SwFrame * Lower() const
Definition: layfrm.hxx:100
SwContentNode * GetContentNode()
Definition: node.hxx:615
FlyAnchors.
Definition: fmtanchr.hxx:34
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
Marks a node in the document model.
Definition: ndindex.hxx:31
#define RES_FMT_CHG
Definition: hintids.hxx:284
static SwNodeType GetNodeType(const SwFlyFrame *pFlyFrame)
const SwPosition * Start() const
Definition: pam.hxx:212
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:60
general base class for all free-flowing frames
Definition: flyfrm.hxx:60
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:155
virtual void GetStates(::utl::AccessibleStateSetHelper &rStateSet)
Definition: acccontext.cxx:481
sal_Int32 GetIndex() const
Definition: index.hxx:95
bool IsNoTextFrame() const
Definition: frame.hxx:1214
const SwPosition * End() const
Definition: pam.hxx:217
const SwModify * GetRegisteredIn() const
Definition: calbck.hxx:157
#define RES_NAME_CHANGED
Definition: hintids.hxx:310
size_t IsObjSelected() const
Definition: feshview.cxx:1167
css::uno::Reference< css::accessibility::XAccessible > GetWeakParent() const
Definition: acccontext.cxx:78
SwAccessibleMap * GetMap()
Definition: acccontext.hxx:112
const SwFormatContent & GetContent(bool=true) const
Definition: fmtcntnt.hxx:55
virtual bool SetSelectedState(bool bSeleted) override
#define RES_OBJECTDYING
Definition: hintids.hxx:283
mutable::osl::Mutex m_Mutex
Definition: acccontext.hxx:64
void SetCursorContext(const ::rtl::Reference< SwAccessibleContext > &rCursorContext)
Definition: accmap.cxx:2754
bool HasFocus() const
void AddState(sal_Int16 aState)
void SetName(const OUString &rName)
Definition: acccontext.hxx:99
bool IsFrameSelected() const
Definition: feshview.cxx:1175
sal_uInt16 Which() const
virtual void Dispose(bool bRecursive, bool bCanSkipInvisible=true) override
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:843