summaryrefslogtreecommitdiffstats
path: root/sw/source/core/access/accframebase.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/core/access/accframebase.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/access/accframebase.cxx')
-rw-r--r--sw/source/core/access/accframebase.cxx374
1 files changed, 374 insertions, 0 deletions
diff --git a/sw/source/core/access/accframebase.cxx b/sw/source/core/access/accframebase.cxx
new file mode 100644
index 000000000..cfbfe9ecf
--- /dev/null
+++ b/sw/source/core/access/accframebase.cxx
@@ -0,0 +1,374 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <osl/mutex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <frmfmt.hxx>
+#include <flyfrm.hxx>
+#include <fmtcntnt.hxx>
+#include <ndindex.hxx>
+#include <fesh.hxx>
+#include <hints.hxx>
+#include <accmap.hxx>
+#include "accframebase.hxx"
+
+#include <crsrsh.hxx>
+#include <notxtfrm.hxx>
+#include <ndtxt.hxx>
+#include <undobj.hxx>
+#include <fmtanchr.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+bool SwAccessibleFrameBase::IsSelected()
+{
+ bool bRet = false;
+
+ assert(GetMap());
+ const SwViewShell *pVSh = GetMap()->GetShell();
+ assert(pVSh);
+ if( auto pFESh = dynamic_cast<const SwFEShell*>(pVSh) )
+ {
+ const SwFrame *pFlyFrame = pFESh->GetSelectedFlyFrame();
+ if( pFlyFrame == GetFrame() )
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void SwAccessibleFrameBase::GetStates(
+ ::utl::AccessibleStateSetHelper& rStateSet )
+{
+ SwAccessibleContext::GetStates( rStateSet );
+
+ const SwViewShell *pVSh = GetMap()->GetShell();
+ assert(pVSh);
+
+ if (dynamic_cast<const SwFEShell*>(pVSh))
+ {
+ // SELECTABLE
+ rStateSet.AddState(AccessibleStateType::SELECTABLE);
+ // FOCUSABLE
+ rStateSet.AddState(AccessibleStateType::FOCUSABLE);
+ }
+
+ // SELECTED and FOCUSED
+ if( IsSelected() )
+ {
+ rStateSet.AddState( AccessibleStateType::SELECTED );
+ SAL_WARN_IF(!m_bIsSelected, "sw.a11y", "bSelected out of sync");
+ ::rtl::Reference < SwAccessibleContext > xThis( this );
+ GetMap()->SetCursorContext( xThis );
+
+ vcl::Window *pWin = GetWindow();
+ if( pWin && pWin->HasFocus() )
+ rStateSet.AddState( AccessibleStateType::FOCUSED );
+ }
+ if( GetSelectedState() )
+ rStateSet.AddState( AccessibleStateType::SELECTED );
+}
+
+SwNodeType SwAccessibleFrameBase::GetNodeType( const SwFlyFrame *pFlyFrame )
+{
+ SwNodeType nType = SwNodeType::Text;
+ if( pFlyFrame->Lower() )
+ {
+ if( pFlyFrame->Lower()->IsNoTextFrame() )
+ {
+ const SwNoTextFrame *const pContentFrame =
+ static_cast<const SwNoTextFrame *>(pFlyFrame->Lower());
+ nType = pContentFrame->GetNode()->GetNodeType();
+ }
+ }
+ else
+ {
+ const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
+ const SwFormatContent& rContent = pFrameFormat->GetContent();
+ const SwNodeIndex *pNdIdx = rContent.GetContentIdx();
+ if( pNdIdx )
+ {
+ const SwContentNode *pCNd =
+ (pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetContentNode();
+ if( pCNd )
+ nType = pCNd->GetNodeType();
+ }
+ }
+
+ return nType;
+}
+
+SwAccessibleFrameBase::SwAccessibleFrameBase(
+ std::shared_ptr<SwAccessibleMap> const& pInitMap,
+ sal_Int16 nInitRole,
+ const SwFlyFrame* pFlyFrame ) :
+ SwAccessibleContext( pInitMap, nInitRole, pFlyFrame ),
+ m_bIsSelected( false )
+{
+ const SwFrameFormat* pFrameFormat = pFlyFrame->GetFormat();
+ if(pFrameFormat)
+ StartListening(const_cast<SwFrameFormat*>(pFrameFormat)->GetNotifier());
+
+ SetName( pFrameFormat->GetName() );
+
+ m_bIsSelected = IsSelected();
+}
+
+void SwAccessibleFrameBase::InvalidateCursorPos_()
+{
+ bool bNewSelected = IsSelected();
+ bool bOldSelected;
+
+ {
+ osl::MutexGuard aGuard( m_Mutex );
+ bOldSelected = m_bIsSelected;
+ m_bIsSelected = bNewSelected;
+ }
+
+ if( bNewSelected )
+ {
+ // remember that object as the one that has the caret. This is
+ // necessary to notify that object if the cursor leaves it.
+ ::rtl::Reference < SwAccessibleContext > xThis( this );
+ GetMap()->SetCursorContext( xThis );
+ }
+
+ if( bOldSelected != bNewSelected )
+ {
+ vcl::Window *pWin = GetWindow();
+ if( pWin && pWin->HasFocus() && bNewSelected )
+ FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
+ if( pWin && pWin->HasFocus() && !bNewSelected )
+ FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
+ if(bNewSelected)
+ {
+ uno::Reference< XAccessible > xParent( GetWeakParent() );
+ if( xParent.is() )
+ {
+ SwAccessibleContext *pAcc =
+ static_cast <SwAccessibleContext *>( xParent.get() );
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
+ uno::Reference< XAccessible > xChild(this);
+ aEvent.NewValue <<= xChild;
+ pAcc->FireAccessibleEvent( aEvent );
+ }
+ }
+ }
+}
+
+void SwAccessibleFrameBase::InvalidateFocus_()
+{
+ vcl::Window *pWin = GetWindow();
+ if( pWin )
+ {
+ bool bSelected;
+
+ {
+ osl::MutexGuard aGuard( m_Mutex );
+ bSelected = m_bIsSelected;
+ }
+ assert(bSelected && "focus object should be selected");
+
+ FireStateChangedEvent( AccessibleStateType::FOCUSED,
+ pWin->HasFocus() && bSelected );
+ }
+}
+
+bool SwAccessibleFrameBase::HasCursor()
+{
+ osl::MutexGuard aGuard( m_Mutex );
+ return m_bIsSelected;
+}
+
+SwAccessibleFrameBase::~SwAccessibleFrameBase()
+{
+}
+
+void SwAccessibleFrameBase::Notify(const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ EndListeningAll();
+ }
+ else if(auto pLegacyModifyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
+ {
+ sal_uInt16 nWhich = pLegacyModifyHint->m_pOld ? pLegacyModifyHint->m_pOld->Which() : pLegacyModifyHint->m_pNew ? pLegacyModifyHint->m_pNew->Which() : 0;
+ const SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrame*>(GetFrame());
+ if(nWhich == RES_NAME_CHANGED && pFlyFrame)
+ {
+ const SwFrameFormat* pFrameFormat = pFlyFrame->GetFormat();
+
+ const OUString sOldName( GetName() );
+ assert( !pLegacyModifyHint->m_pOld ||
+ static_cast<const SwStringMsgPoolItem *>(pLegacyModifyHint->m_pOld)->GetString() == GetName());
+
+ SetName( pFrameFormat->GetName() );
+ assert( !pLegacyModifyHint->m_pNew ||
+ static_cast<const SwStringMsgPoolItem *>(pLegacyModifyHint->m_pNew)->GetString() == GetName());
+
+ if( sOldName != GetName() )
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::NAME_CHANGED;
+ aEvent.OldValue <<= sOldName;
+ aEvent.NewValue <<= GetName();
+ FireAccessibleEvent( aEvent );
+ }
+ }
+ }
+}
+
+void SwAccessibleFrameBase::Dispose(bool bRecursive, bool bCanSkipInvisible)
+{
+ SolarMutexGuard aGuard;
+ EndListeningAll();
+ SwAccessibleContext::Dispose(bRecursive, bCanSkipInvisible);
+}
+
+//Get the selection cursor of the document.
+SwPaM* SwAccessibleFrameBase::GetCursor()
+{
+ // get the cursor shell; if we don't have any, we don't have a
+ // cursor/selection either
+ SwPaM* pCursor = nullptr;
+ SwCursorShell* pCursorShell = GetCursorShell();
+ if( pCursorShell != nullptr && !pCursorShell->IsTableMode() )
+ {
+ SwFEShell *pFESh = dynamic_cast<const SwFEShell*>( pCursorShell) != nullptr
+ ? static_cast< SwFEShell * >( pCursorShell ) : nullptr;
+ if( !pFESh ||
+ !(pFESh->IsFrameSelected() || pFESh->IsObjSelected() > 0) )
+ {
+ // get the selection, and test whether it affects our text node
+ pCursor = pCursorShell->GetCursor( false /* ??? */ );
+ }
+ }
+
+ return pCursor;
+}
+
+//Return the selected state of the object.
+//when the object's anchor are in the selection cursor, we should return true.
+bool SwAccessibleFrameBase::GetSelectedState( )
+{
+ SolarMutexGuard aGuard;
+
+ if(GetMap()->IsDocumentSelAll())
+ {
+ return true;
+ }
+
+ // SELECTED.
+ SwFlyFrame* pFlyFrame = getFlyFrame();
+ const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
+ const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
+ const SwPosition *pPos = rAnchor.GetContentAnchor();
+ if( !pPos )
+ return false;
+ int nIndex = pPos->nContent.GetIndex();
+ if( pPos->nNode.GetNode().GetTextNode() )
+ {
+ SwPaM* pCursor = GetCursor();
+ if( pCursor != nullptr )
+ {
+ const SwTextNode* pNode = pPos->nNode.GetNode().GetTextNode();
+ sal_uLong nHere = pNode->GetIndex();
+
+ // iterate over ring
+ SwPaM* pRingStart = pCursor;
+ do
+ {
+ // ignore, if no mark
+ if( pCursor->HasMark() )
+ {
+ // check whether nHere is 'inside' pCursor
+ SwPosition* pStart = pCursor->Start();
+ sal_uLong nStartIndex = pStart->nNode.GetIndex();
+ SwPosition* pEnd = pCursor->End();
+ sal_uLong nEndIndex = pEnd->nNode.GetIndex();
+ if( ( nHere >= nStartIndex ) && (nHere <= nEndIndex) )
+ {
+ if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
+ {
+ if( ((nHere == nStartIndex) && (nIndex >= pStart->nContent.GetIndex())) || (nHere > nStartIndex) )
+ if( ((nHere == nEndIndex) && (nIndex < pEnd->nContent.GetIndex())) || (nHere < nEndIndex) )
+ return true;
+ }
+ else if( rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA )
+ {
+ if (IsSelectFrameAnchoredAtPara(*pPos, *pStart, *pEnd))
+ return true;
+ }
+ else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
+ {
+ if (IsDestroyFrameAnchoredAtChar(*pPos, *pStart, *pEnd))
+ {
+ return true;
+ }
+ }
+ break;
+ }
+ // else: this PaM doesn't point to this paragraph
+ }
+ // else: this PaM is collapsed and doesn't select anything
+
+ // next PaM in ring
+ pCursor = pCursor->GetNext();
+ }
+ while( pCursor != pRingStart );
+ }
+ }
+ return false;
+}
+
+SwFlyFrame* SwAccessibleFrameBase::getFlyFrame() const
+{
+ SwFlyFrame* pFlyFrame = nullptr;
+
+ const SwFrame* pFrame = GetFrame();
+ assert(pFrame);
+ if( pFrame->IsFlyFrame() )
+ {
+ pFlyFrame = static_cast<SwFlyFrame*>( const_cast<SwFrame*>( pFrame ) );
+ }
+
+ return pFlyFrame;
+}
+
+bool SwAccessibleFrameBase::SetSelectedState( bool )
+{
+ bool bParaSelected = GetSelectedState() || IsSelected();
+
+ if (m_isSelectedInDoc != bParaSelected)
+ {
+ m_isSelectedInDoc = bParaSelected;
+ FireStateChangedEvent( AccessibleStateType::SELECTED, bParaSelected );
+ return true;
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */