1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/window.hxx>
21 #include <rootfrm.hxx>
23 #include <com/sun/star/accessibility/AccessibleRole.hpp>
24 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
25 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
26 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
27 #include <cppuhelper/typeprovider.hxx>
28 #include <vcl/svapp.hxx>
29 #include <cppuhelper/supportsservice.hxx>
34 #include <strings.hrc>
35 #include <pagefrm.hxx>
37 #include <swatrset.hxx>
41 #include <fmtclds.hxx>
44 #include <sectfrm.hxx>
45 #include <section.hxx>
46 #include <swmodule.hxx>
47 #include <svtools/colorcfg.hxx>
49 #include <fmtanchr.hxx>
50 #include <viewimp.hxx>
52 #include <dcontact.hxx>
53 #include <svx/svdmark.hxx>
54 constexpr OUString sServiceName
= u
"com.sun.star.text.AccessibleTextDocumentView"_ustr
;
56 using namespace ::com::sun::star
;
57 using namespace ::com::sun::star::accessibility
;
59 using lang::IndexOutOfBoundsException
;
61 // SwAccessibleDocumentBase: base class for SwAccessibleDocument and
62 // SwAccessiblePreview
64 SwAccessibleDocumentBase::SwAccessibleDocumentBase(
65 std::shared_ptr
<SwAccessibleMap
> const& pMap
)
66 : SwAccessibleContext(pMap
, AccessibleRole::DOCUMENT_TEXT
,
67 pMap
->GetShell()->GetLayout())
68 , mxParent(pMap
->GetShell()->GetWin()->GetAccessibleParentWindow()->GetAccessible())
73 SwAccessibleDocumentBase::~SwAccessibleDocumentBase()
77 void SwAccessibleDocumentBase::SetVisArea()
79 SolarMutexGuard aGuard
;
81 SwRect
aOldVisArea( GetVisArea() );
82 const SwRect
& rNewVisArea
= GetMap()->GetVisArea();
83 if( aOldVisArea
!= rNewVisArea
)
85 SwAccessibleFrame::SetVisArea( GetMap()->GetVisArea() );
86 // #i58139# - showing state of document view needs also be updated.
87 // Thus, call method <Scrolled(..)> instead of <ChildrenScrolled(..)>
88 // ChildrenScrolled( GetFrame(), aOldVisArea );
89 Scrolled( aOldVisArea
);
93 void SwAccessibleDocumentBase::AddChild( vcl::Window
*pWin
, bool bFireEvent
)
95 SolarMutexGuard aGuard
;
97 OSL_ENSURE( !mpChildWin
, "only one child window is supported" );
104 AccessibleEventObject aEvent
;
105 aEvent
.EventId
= AccessibleEventId::CHILD
;
106 aEvent
.NewValue
<<= mpChildWin
->GetAccessible();
107 aEvent
.IndexHint
= -1;
108 FireAccessibleEvent( aEvent
);
113 void SwAccessibleDocumentBase::RemoveChild( vcl::Window
*pWin
)
115 SolarMutexGuard aGuard
;
117 OSL_ENSURE( !mpChildWin
|| pWin
== mpChildWin
, "invalid child window to remove" );
118 if( mpChildWin
&& pWin
== mpChildWin
)
120 AccessibleEventObject aEvent
;
121 aEvent
.EventId
= AccessibleEventId::CHILD
;
122 aEvent
.OldValue
<<= mpChildWin
->GetAccessible();
123 aEvent
.IndexHint
= -1;
124 FireAccessibleEvent( aEvent
);
126 mpChildWin
= nullptr;
130 sal_Int64 SAL_CALL
SwAccessibleDocumentBase::getAccessibleChildCount()
132 SolarMutexGuard aGuard
;
134 // ThrowIfDisposed is called by parent
136 sal_Int64 nChildren
= SwAccessibleContext::getAccessibleChildCount();
137 if( !IsDisposing() && mpChildWin
)
143 uno::Reference
< XAccessible
> SAL_CALL
144 SwAccessibleDocumentBase::getAccessibleChild( sal_Int64 nIndex
)
146 SolarMutexGuard aGuard
;
152 if ( nIndex
== GetChildCount( *(GetMap()) ) )
154 return mpChildWin
->GetAccessible();
158 return SwAccessibleContext::getAccessibleChild( nIndex
);
161 uno::Reference
< XAccessible
> SAL_CALL
SwAccessibleDocumentBase::getAccessibleParent()
166 sal_Int64 SAL_CALL
SwAccessibleDocumentBase::getAccessibleIndexInParent()
168 SolarMutexGuard aGuard
;
170 uno::Reference
< XAccessibleContext
> xAcc( mxParent
->getAccessibleContext() );
171 uno::Reference
< XAccessible
> xThis( this );
172 sal_Int64 nCount
= xAcc
->getAccessibleChildCount();
174 for( sal_Int64 i
=0; i
< nCount
; i
++ )
178 if( xAcc
->getAccessibleChild( i
) == xThis
)
181 catch(const css::lang::IndexOutOfBoundsException
&)
189 OUString SAL_CALL
SwAccessibleDocumentBase::getAccessibleDescription()
191 return GetResource( STR_ACCESS_DOC_DESC
);
194 OUString SAL_CALL
SwAccessibleDocumentBase::getAccessibleName()
198 OUString sAccName
= GetResource( STR_ACCESS_DOC_WORDPROCESSING
);
199 SwDoc
*pDoc
= GetMap() ? GetShell()->GetDoc() : nullptr;
202 OUString sFileName
= pDoc
->getDocAccTitle();
203 if ( sFileName
.isEmpty() )
205 SwDocShell
* pDocSh
= pDoc
->GetDocShell();
208 sFileName
= pDocSh
->GetTitle( SFX_TITLE_APINAME
);
212 if ( !sFileName
.isEmpty() )
214 sAccName
= sFileName
+ " - " + sAccName
;
221 awt::Rectangle SAL_CALL
SwAccessibleDocumentBase::getBounds()
225 SolarMutexGuard aGuard
;
227 vcl::Window
*pWin
= GetWindow();
230 throw uno::RuntimeException(u
"no Window"_ustr
, getXWeak());
233 tools::Rectangle
aPixBounds( pWin
->GetWindowExtentsRelative( *pWin
->GetAccessibleParentWindow() ) );
234 awt::Rectangle
aBox( aPixBounds
.Left(), aPixBounds
.Top(),
235 aPixBounds
.GetWidth(), aPixBounds
.GetHeight() );
239 catch(const css::lang::IndexOutOfBoundsException
&)
241 return awt::Rectangle();
245 awt::Point SAL_CALL
SwAccessibleDocumentBase::getLocation()
247 SolarMutexGuard aGuard
;
249 vcl::Window
*pWin
= GetWindow();
252 throw uno::RuntimeException(u
"no Window"_ustr
, getXWeak());
255 Point
aPixPos( pWin
->GetWindowExtentsRelative( *pWin
->GetAccessibleParentWindow() ).TopLeft() );
256 awt::Point
aLoc( aPixPos
.getX(), aPixPos
.getY() );
261 css::awt::Point SAL_CALL
SwAccessibleDocumentBase::getLocationOnScreen()
263 SolarMutexGuard aGuard
;
265 vcl::Window
*pWin
= GetWindow();
268 throw uno::RuntimeException(u
"no Window"_ustr
, getXWeak());
271 Point
aPixPos( pWin
->GetWindowExtentsAbsolute().TopLeft() );
272 awt::Point
aLoc( aPixPos
.getX(), aPixPos
.getY() );
277 css::awt::Size SAL_CALL
SwAccessibleDocumentBase::getSize()
279 SolarMutexGuard aGuard
;
281 vcl::Window
*pWin
= GetWindow();
284 throw uno::RuntimeException(u
"no Window"_ustr
, getXWeak());
287 Size
aPixSize( pWin
->GetWindowExtentsAbsolute().GetSize() );
288 awt::Size
aSize( aPixSize
.Width(), aPixSize
.Height() );
293 sal_Bool SAL_CALL
SwAccessibleDocumentBase::containsPoint(
294 const awt::Point
& aPoint
)
296 SolarMutexGuard aGuard
;
298 vcl::Window
*pWin
= GetWindow();
301 throw uno::RuntimeException(u
"no Window"_ustr
, getXWeak());
304 tools::Rectangle
aPixBounds( pWin
->GetWindowExtentsAbsolute() );
305 aPixBounds
.Move(-aPixBounds
.Left(), -aPixBounds
.Top());
307 Point
aPixPoint( aPoint
.X
, aPoint
.Y
);
308 return aPixBounds
.Contains( aPixPoint
);
311 uno::Reference
< XAccessible
> SAL_CALL
SwAccessibleDocumentBase::getAccessibleAtPoint(
312 const awt::Point
& aPoint
)
314 SolarMutexGuard aGuard
;
320 vcl::Window
*pWin
= GetWindow();
323 throw uno::RuntimeException(u
"no Window"_ustr
, getXWeak());
325 if (pWin
->isDisposed()) // tdf#147967
328 Point
aPixPoint( aPoint
.X
, aPoint
.Y
); // px rel to window
329 if( mpChildWin
->GetWindowExtentsRelative( *pWin
).Contains( aPixPoint
) )
330 return mpChildWin
->GetAccessible();
333 return SwAccessibleContext::getAccessibleAtPoint( aPoint
);
336 // SwAccessibleDocument
338 void SwAccessibleDocument::GetStates( sal_Int64
& rStateSet
)
340 SwAccessibleContext::GetStates( rStateSet
);
343 rStateSet
|= AccessibleStateType::MULTI_SELECTABLE
;
344 rStateSet
|= AccessibleStateType::MANAGES_DESCENDANTS
;
347 SwAccessibleDocument::SwAccessibleDocument(
348 std::shared_ptr
<SwAccessibleMap
> const& pInitMap
)
349 : SwAccessibleDocument_BASE(pInitMap
)
350 , maSelectionHelper(*this)
352 SetName(pInitMap
->GetDocName());
353 vcl::Window
*pWin
= pInitMap
->GetShell()->GetWin();
356 pWin
->AddChildEventListener( LINK( this, SwAccessibleDocument
, WindowChildEventListener
));
357 sal_uInt16 nCount
= pWin
->GetChildCount();
358 for( sal_uInt16 i
=0; i
< nCount
; i
++ )
360 vcl::Window
* pChildWin
= pWin
->GetChild( i
);
362 AccessibleRole::EMBEDDED_OBJECT
== pChildWin
->GetAccessibleRole() )
363 AddChild( pChildWin
, false );
368 SwAccessibleDocument::~SwAccessibleDocument()
370 vcl::Window
*pWin
= GetMap() ? GetMap()->GetShell()->GetWin() : nullptr;
372 pWin
->RemoveChildEventListener( LINK( this, SwAccessibleDocument
, WindowChildEventListener
));
375 void SwAccessibleDocument::Dispose(bool bRecursive
, bool bCanSkipInvisible
)
377 OSL_ENSURE( GetFrame() && GetMap(), "already disposed" );
379 vcl::Window
*pWin
= GetMap() ? GetMap()->GetShell()->GetWin() : nullptr;
381 pWin
->RemoveChildEventListener( LINK( this, SwAccessibleDocument
, WindowChildEventListener
));
382 SwAccessibleContext::Dispose(bRecursive
, bCanSkipInvisible
);
385 IMPL_LINK( SwAccessibleDocument
, WindowChildEventListener
, VclWindowEvent
&, rEvent
, void )
387 OSL_ENSURE( rEvent
.GetWindow(), "Window???" );
388 switch ( rEvent
.GetId() )
390 case VclEventId::WindowShow
: // send create on show for direct accessible children
392 vcl::Window
* pChildWin
= static_cast< vcl::Window
* >( rEvent
.GetData() );
393 if( pChildWin
&& AccessibleRole::EMBEDDED_OBJECT
== pChildWin
->GetAccessibleRole() )
395 AddChild( pChildWin
);
399 case VclEventId::WindowHide
: // send destroy on hide for direct accessible children
401 vcl::Window
* pChildWin
= static_cast< vcl::Window
* >( rEvent
.GetData() );
402 if( pChildWin
&& AccessibleRole::EMBEDDED_OBJECT
== pChildWin
->GetAccessibleRole() )
404 RemoveChild( pChildWin
);
408 case VclEventId::ObjectDying
: // send destroy on hide for direct accessible children
410 vcl::Window
* pChildWin
= rEvent
.GetWindow();
411 if( pChildWin
&& AccessibleRole::EMBEDDED_OBJECT
== pChildWin
->GetAccessibleRole() )
413 RemoveChild( pChildWin
);
421 OUString SAL_CALL
SwAccessibleDocument::getImplementationName()
423 return u
"com.sun.star.comp.Writer.SwAccessibleDocumentView"_ustr
;
426 sal_Bool SAL_CALL
SwAccessibleDocument::supportsService(const OUString
& sTestServiceName
)
428 return cppu::supportsService(this, sTestServiceName
);
431 uno::Sequence
< OUString
> SAL_CALL
SwAccessibleDocument::getSupportedServiceNames()
433 return { sServiceName
, sAccessibleServiceName
};
436 // XAccessibleSelection
438 void SwAccessibleDocument::selectAccessibleChild(
439 sal_Int64 nChildIndex
)
441 maSelectionHelper
.selectAccessibleChild(nChildIndex
);
444 sal_Bool
SwAccessibleDocument::isAccessibleChildSelected(
445 sal_Int64 nChildIndex
)
447 return maSelectionHelper
.isAccessibleChildSelected(nChildIndex
);
450 void SwAccessibleDocument::clearAccessibleSelection( )
454 void SwAccessibleDocument::selectAllAccessibleChildren( )
456 maSelectionHelper
.selectAllAccessibleChildren();
459 sal_Int64
SwAccessibleDocument::getSelectedAccessibleChildCount( )
461 return maSelectionHelper
.getSelectedAccessibleChildCount();
464 uno::Reference
<XAccessible
> SwAccessibleDocument::getSelectedAccessibleChild(
465 sal_Int64 nSelectedChildIndex
)
467 return maSelectionHelper
.getSelectedAccessibleChild(nSelectedChildIndex
);
470 // index has to be treated as global child index.
471 void SwAccessibleDocument::deselectAccessibleChild(
472 sal_Int64 nChildIndex
)
474 maSelectionHelper
.deselectAccessibleChild( nChildIndex
);
477 uno::Any SAL_CALL
SwAccessibleDocument::getExtendedAttributes()
481 uno::Any anyAttribute
;
482 SwDoc
*pDoc
= GetMap() ? GetShell()->GetDoc() : nullptr;
486 SwCursorShell
* pCursorShell
= GetCursorShell();
490 SwFEShell
* pFEShell
= dynamic_cast<SwFEShell
*>(pCursorShell
);
494 sal_uInt16 nPage
, nLogPage
;
495 pFEShell
->GetPageNumber(-1,true,nPage
,nLogPage
,sDisplay
);
497 OUString sValue
= "page-name:" + sDisplay
+
499 OUString::number( nPage
) +
501 OUString::number( pCursorShell
->GetPageCnt() ) + ";";
503 // cursor position relative to the page
504 Point aCursorPagePos
= pFEShell
->GetCursorPagePos();
505 sValue
+= "cursor-position-in-page-horizontal:" + OUString::number(aCursorPagePos
.getX())
506 + ";cursor-position-in-page-vertical:" + OUString::number(aCursorPagePos
.getY()) + ";";
508 SwContentFrame
* pCurrFrame
= pCursorShell
->GetCurrFrame();
509 SwPageFrame
* pCurrPage
=static_cast<SwFrame
*>(pCurrFrame
)->FindPageFrame();
510 sal_Int32 nLineNum
= 0;
511 SwTextFrame
* pTextFrame
= nullptr;
512 SwTextFrame
* pCurrTextFrame
= nullptr;
513 pTextFrame
= static_cast< SwTextFrame
* >(pCurrPage
->ContainsContent());
514 if (pCurrFrame
->IsInFly())//such as, graphic,chart
516 SwFlyFrame
*pFlyFrame
= pCurrFrame
->FindFlyFrame();
517 const SwFormatAnchor
& rAnchor
= pFlyFrame
->GetFormat()->GetAnchor();
518 RndStdIds eAnchorId
= rAnchor
.GetAnchorId();
519 if(eAnchorId
== RndStdIds::FLY_AS_CHAR
)
521 const SwFrame
*pSwFrame
= pFlyFrame
->GetAnchorFrame();
522 if(pSwFrame
->IsTextFrame())
523 pCurrTextFrame
= const_cast<SwTextFrame
*>(static_cast<const SwTextFrame
*>(pSwFrame
));
528 assert(dynamic_cast<SwTextFrame
*>(pCurrFrame
));
529 pCurrTextFrame
= static_cast<SwTextFrame
* >(pCurrFrame
);
531 //check whether the text frame where the Graph/OLE/Frame anchored is in the Header/Footer
532 SwFrame
* pFrame
= pCurrTextFrame
;
533 while ( pFrame
&& !pFrame
->IsHeaderFrame() && !pFrame
->IsFooterFrame() )
534 pFrame
= pFrame
->GetUpper();
536 pCurrTextFrame
= nullptr;
538 if(pCursorShell
->Imp()->GetDrawView())
540 const SdrMarkList
&rMrkList
= pCursorShell
->Imp()->GetDrawView()->GetMarkedObjectList();
541 for ( size_t i
= 0; i
< rMrkList
.GetMarkCount(); ++i
)
543 SdrObject
*pObj
= rMrkList
.GetMark(i
)->GetMarkedSdrObj();
544 SwFrameFormat
* pFormat
= static_cast<SwDrawContact
*>(pObj
->GetUserCall())->GetFormat();
545 const SwFormatAnchor
& rAnchor
= pFormat
->GetAnchor();
546 if( RndStdIds::FLY_AS_CHAR
!= rAnchor
.GetAnchorId() )
547 pCurrTextFrame
= nullptr;
550 //calculate line number
551 if (pCurrTextFrame
&& pTextFrame
)
553 if (!(pCurrTextFrame
->IsInTab() || pCurrTextFrame
->IsInFootnote()))
555 while( pTextFrame
&& pTextFrame
!= pCurrTextFrame
)
557 //check header/footer
559 while ( pFrame
&& !pFrame
->IsHeaderFrame() && !pFrame
->IsFooterFrame() )
560 pFrame
= pFrame
->GetUpper();
563 pTextFrame
= static_cast< SwTextFrame
*>(pTextFrame
->GetNextContentFrame());
566 if (!(pTextFrame
->IsInTab() || pTextFrame
->IsInFootnote() || pTextFrame
->IsInFly()))
567 nLineNum
+= pTextFrame
->GetThisLines();
568 pTextFrame
= static_cast< SwTextFrame
* >(pTextFrame
->GetNextContentFrame());
570 SwPaM
* pCaret
= pCursorShell
->GetCursor();
571 if (!pCurrTextFrame
->IsEmpty() && pCaret
)
573 assert(pCurrTextFrame
->IsTextFrame());
574 const SwPosition
* pPoint
= nullptr;
575 if (pCurrTextFrame
->IsInFly())
577 SwFlyFrame
*pFlyFrame
= pCurrTextFrame
->FindFlyFrame();
578 const SwFormatAnchor
& rAnchor
= pFlyFrame
->GetFormat()->GetAnchor();
579 pPoint
= rAnchor
.GetContentAnchor();
580 SwContentNode
*const pNode(pPoint
->GetNode().GetContentNode());
581 pCurrTextFrame
= pNode
582 ? static_cast<SwTextFrame
*>(pNode
->getLayoutFrame(
583 pCurrTextFrame
->getRootFrame(), pPoint
))
587 pPoint
= pCaret
->GetPoint();
590 TextFrameIndex
const nActPos(pCurrTextFrame
->MapModelToViewPos(*pPoint
));
591 nLineNum
+= pCurrTextFrame
->GetLineCount( nActPos
);
599 sValue
+= "line-number:" + OUString::number( nLineNum
) + ";";
601 SwFrame
* pCurrCol
=static_cast<SwFrame
*>(pCurrFrame
)->FindColFrame();
603 sValue
+= "column-number:";
606 if(pCurrCol
!=nullptr)
608 //SwLayoutFrame* pParent = pCurrCol->GetUpper();
609 SwFrame
* pCurrPageCol
=static_cast<SwFrame
*>(pCurrFrame
)->FindColFrame();
610 while(pCurrPageCol
&& pCurrPageCol
->GetUpper() && pCurrPageCol
->GetUpper()->IsPageFrame())
612 pCurrPageCol
= pCurrPageCol
->GetUpper();
615 SwLayoutFrame
* pParent
= pCurrPageCol
->GetUpper();
619 SwFrame
* pCol
= pParent
->Lower();
620 while(pCol
&&(pCol
!=pCurrPageCol
))
622 pCol
= pCol
->GetNext();
627 sValue
+= OUString::number( nCurrCol
) + ";";
629 const SwFormatCol
&rFormatCol
=pCurrPage
->GetAttrSet()->GetCol();
630 sal_uInt16 nColCount
=rFormatCol
.GetNumCols();
631 nColCount
= nColCount
>0?nColCount
:1;
632 sValue
+= "total-columns:" + OUString::number( nColCount
) + ";";
634 SwSectionFrame
* pCurrSctFrame
=static_cast<SwFrame
*>(pCurrFrame
)->FindSctFrame();
635 if(pCurrSctFrame
!=nullptr && pCurrSctFrame
->GetSection()!=nullptr )
637 OUString sectionName
= pCurrSctFrame
->GetSection()->GetSectionName();
639 sectionName
= sectionName
.replaceFirst( "\\" , "\\\\" );
640 sectionName
= sectionName
.replaceFirst( "=" , "\\=" );
641 sectionName
= sectionName
.replaceFirst( ";" , "\\;" );
642 sectionName
= sectionName
.replaceFirst( "," , "\\," );
643 sectionName
= sectionName
.replaceFirst( ":" , "\\:" );
645 sValue
+= "section-name:" + sectionName
+ ";";
647 //section-columns-number
651 if(pCurrCol
!=nullptr)
653 SwLayoutFrame
* pParent
= pCurrCol
->GetUpper();
656 SwFrame
* pCol
= pParent
->Lower();
657 while(pCol
&&(pCol
!=pCurrCol
))
659 pCol
= pCol
->GetNext();
664 sValue
+= "section-columns-number:" +
665 OUString::number( nCurrCol
) + ";";
667 //section-total-columns
668 const SwFormatCol
&rFormatSctCol
=pCurrSctFrame
->GetAttrSet()->GetCol();
669 sal_uInt16 nSctColCount
=rFormatSctCol
.GetNumCols();
670 nSctColCount
= nSctColCount
>0?nSctColCount
:1;
671 sValue
+= "section-total-columns:" +
672 OUString::number( nSctColCount
) + ";";
675 anyAttribute
<<= sValue
;
680 sal_Int32 SAL_CALL
SwAccessibleDocument::getBackground()
682 SolarMutexGuard aGuard
;
683 return sal_Int32(SwModule::get()->GetColorConfig().GetColorValue(::svtools::DOCCOLOR
).nColor
);
686 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */