OAccessible returns itself in its XAccessible::getAccessibleContext implementation and implements the XAccessibleComponent interface itself, so there is no need to call the method and query for that interface. Change-Id: I232d86a3c972a8313a6dc62a1b6c799c6b1a9d81 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210603 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
386 lines
11 KiB
C++
386 lines
11 KiB
C++
/* -*- 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 <AccessibleChartView.hxx>
|
|
#include <ObjectHierarchy.hxx>
|
|
#include <ObjectIdentifier.hxx>
|
|
#include <ResId.hxx>
|
|
#include <strings.hrc>
|
|
#include "AccessibleViewForwarder.hxx"
|
|
#include <ChartModel.hxx>
|
|
#include <ChartView.hxx>
|
|
#include <ChartController.hxx>
|
|
|
|
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleRole.hpp>
|
|
#include <com/sun/star/view/XSelectionSupplier.hpp>
|
|
|
|
#include <rtl/ustring.hxx>
|
|
#include <vcl/window.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <osl/mutex.hxx>
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::accessibility;
|
|
|
|
using ::com::sun::star::uno::Reference;
|
|
using ::com::sun::star::uno::WeakReference;
|
|
using osl::MutexGuard;
|
|
|
|
namespace chart
|
|
{
|
|
|
|
AccessibleChartView::AccessibleChartView(SdrView* pView)
|
|
: ImplInheritanceHelper(AccessibleElementInfo(), // empty for now
|
|
true, // has children
|
|
true // always transparent
|
|
)
|
|
, m_pSdrView(pView)
|
|
{
|
|
AddState( AccessibleStateType::OPAQUE );
|
|
}
|
|
|
|
AccessibleChartView::~AccessibleChartView()
|
|
{
|
|
}
|
|
|
|
awt::Rectangle AccessibleChartView::GetWindowPosSize() const
|
|
{
|
|
SolarMutexGuard aSolarGuard;
|
|
|
|
VclPtr<vcl::Window> pWindow = GetInfo().m_pWindow;
|
|
if (!pWindow)
|
|
return awt::Rectangle();
|
|
|
|
awt::Rectangle aBBox;
|
|
Point aVCLPoint( pWindow->OutputToAbsoluteScreenPixel( Point( 0, 0 ) ));
|
|
const Size aSize = pWindow->GetSizePixel();
|
|
aBBox.X = aVCLPoint.getX();
|
|
aBBox.Y = aVCLPoint.getY();
|
|
aBBox.Width = aSize.Width();
|
|
aBBox.Height = aSize.Height();
|
|
|
|
return aBBox;
|
|
}
|
|
|
|
awt::Point AccessibleChartView::GetUpperLeftOnScreen() const
|
|
{
|
|
awt::Point aParentPosition;
|
|
|
|
awt::Rectangle aBBox( GetWindowPosSize() );
|
|
aParentPosition.X = aBBox.X;
|
|
aParentPosition.Y = aBBox.Y;
|
|
|
|
return aParentPosition;
|
|
}
|
|
|
|
// ________ XAccessibleContext ________
|
|
OUString SAL_CALL AccessibleChartView::getAccessibleName()
|
|
{
|
|
return SchResId(STR_OBJECT_DIAGRAM);
|
|
}
|
|
|
|
OUString SAL_CALL AccessibleChartView::getAccessibleDescription()
|
|
{
|
|
return getAccessibleName();
|
|
}
|
|
|
|
Reference< XAccessible > SAL_CALL AccessibleChartView::getAccessibleParent()
|
|
{
|
|
return m_pParent.get();
|
|
}
|
|
|
|
sal_Int64 SAL_CALL AccessibleChartView::getAccessibleIndexInParent()
|
|
{
|
|
// the document is always the only child of the window
|
|
return 0;
|
|
}
|
|
|
|
sal_Int16 SAL_CALL AccessibleChartView::getAccessibleRole()
|
|
{
|
|
return AccessibleRole::DOCUMENT;
|
|
}
|
|
|
|
awt::Rectangle AccessibleChartView::implGetBounds()
|
|
{
|
|
awt::Rectangle aResult( GetWindowPosSize());
|
|
rtl::Reference<comphelper::OAccessible> pParent(m_pParent);
|
|
if (pParent.is())
|
|
{
|
|
awt::Point aParentPosition = pParent->getLocationOnScreen();
|
|
aResult.X -= aParentPosition.X;
|
|
aResult.Y -= aParentPosition.Y;
|
|
}
|
|
return aResult;
|
|
}
|
|
|
|
|
|
void SAL_CALL AccessibleChartView::disposing()
|
|
{
|
|
m_pChartWindow.reset();
|
|
|
|
AccessibleBase::disposing();
|
|
}
|
|
|
|
void AccessibleChartView::initialize(ChartController& rNewChartController,
|
|
const rtl::Reference<::chart::ChartModel>& xNewChartModel,
|
|
const rtl::Reference<::chart::ChartView>& xNewChartView,
|
|
const rtl::Reference<comphelper::OAccessible>& rpNewParent,
|
|
ChartWindow* pNewChartWindow)
|
|
{
|
|
//0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself
|
|
//1: frame::XModel representing the chart model - offers access to object data
|
|
//2: lang::XInterface representing the normal chart view - offers access to some extra object data
|
|
|
|
//all arguments are only valid until next initialization
|
|
bool bChanged = false;
|
|
bool bOldInvalid = false;
|
|
bool bNewInvalid = false;
|
|
|
|
rtl::Reference< ::chart::ChartController > xChartController;
|
|
rtl::Reference<::chart::ChartModel> xChartModel;
|
|
rtl::Reference<::chart::ChartView> xChartView;
|
|
rtl::Reference<comphelper::OAccessible> pParent;
|
|
VclPtr<ChartWindow> pChartWindow;
|
|
{
|
|
MutexGuard aGuard( m_aMutex);
|
|
xChartController = m_xChartController;
|
|
xChartModel = m_xChartModel;
|
|
xChartView = m_xChartView;
|
|
pParent = m_pParent.get();
|
|
pChartWindow = m_pChartWindow;
|
|
}
|
|
|
|
if( !xChartController.is() || !xChartModel.is() || !xChartView.is() )
|
|
{
|
|
bOldInvalid = true;
|
|
}
|
|
|
|
if( xNewChartModel.get() != xChartModel.get() )
|
|
{
|
|
xChartModel = xNewChartModel;
|
|
bChanged = true;
|
|
}
|
|
|
|
if( xNewChartView != xChartView )
|
|
{
|
|
xChartView = xNewChartView;
|
|
bChanged = true;
|
|
}
|
|
|
|
if (rpNewParent != pParent)
|
|
{
|
|
pParent = rpNewParent;
|
|
bChanged = true;
|
|
}
|
|
|
|
if (pNewChartWindow != pChartWindow)
|
|
{
|
|
pChartWindow = pNewChartWindow;
|
|
bChanged = true;
|
|
}
|
|
|
|
if(xChartController != &rNewChartController)
|
|
{
|
|
if (xChartController)
|
|
xChartController->removeSelectionChangeListener(this);
|
|
rNewChartController.addSelectionChangeListener(this);
|
|
xChartController = &rNewChartController;
|
|
bChanged = true;
|
|
}
|
|
|
|
if( !xChartController.is() || !xChartModel.is() || !xChartView.is() )
|
|
{
|
|
if(xChartController.is())
|
|
{
|
|
xChartController->removeSelectionChangeListener(this);
|
|
xChartController.clear();
|
|
}
|
|
xChartModel.clear();
|
|
xChartView.clear();
|
|
pParent.clear();
|
|
pChartWindow.reset();
|
|
|
|
bNewInvalid = true;
|
|
}
|
|
|
|
{
|
|
MutexGuard aGuard( m_aMutex);
|
|
m_xChartController = xChartController.get();
|
|
m_xChartModel = xChartModel.get();
|
|
m_xChartView = xChartView.get();
|
|
m_pParent = pParent.get();
|
|
m_pChartWindow = std::move(pChartWindow);
|
|
}
|
|
|
|
if( bOldInvalid && bNewInvalid )
|
|
bChanged = false;
|
|
|
|
if( !bChanged )
|
|
return;
|
|
|
|
{
|
|
//before notification we prepare for creation of new context
|
|
//the old context will be deleted after notification then
|
|
MutexGuard aGuard( m_aMutex);
|
|
if( xChartModel.is())
|
|
m_spObjectHierarchy =
|
|
std::make_shared<ObjectHierarchy>( xChartModel, m_xChartView.get().get() );
|
|
else
|
|
m_spObjectHierarchy.reset();
|
|
}
|
|
|
|
{
|
|
AccessibleElementInfo aAccInfo;
|
|
aAccInfo.m_aOID = ObjectIdentifier(u"ROOT"_ustr);
|
|
aAccInfo.m_xChartDocument = m_xChartModel;
|
|
aAccInfo.m_xChartController = m_xChartController;
|
|
aAccInfo.m_xView = m_xChartView;
|
|
aAccInfo.m_pWindow = m_pChartWindow;
|
|
aAccInfo.m_pParent = nullptr;
|
|
aAccInfo.m_spObjectHierarchy = m_spObjectHierarchy;
|
|
aAccInfo.m_pSdrView = m_pSdrView;
|
|
m_pViewForwarder.reset(new AccessibleViewForwarder(this, m_pChartWindow));
|
|
aAccInfo.m_pViewForwarder = m_pViewForwarder.get();
|
|
// broadcasts an INVALIDATE_ALL_CHILDREN event globally
|
|
SetInfo( aAccInfo );
|
|
}
|
|
}
|
|
|
|
void AccessibleChartView::initialize()
|
|
{
|
|
//0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself
|
|
//1: frame::XModel representing the chart model - offers access to object data
|
|
//2: lang::XInterface representing the normal chart view - offers access to some extra object data
|
|
|
|
//all arguments are only valid until next initialization
|
|
bool bChanged = false;
|
|
bool bOldInvalid = false;
|
|
|
|
rtl::Reference< ::chart::ChartController > xChartController;
|
|
rtl::Reference<::chart::ChartModel> xChartModel;
|
|
rtl::Reference<::chart::ChartView> xChartView;
|
|
{
|
|
MutexGuard aGuard( m_aMutex);
|
|
xChartController = m_xChartController;
|
|
xChartModel = m_xChartModel;
|
|
xChartView = m_xChartView;
|
|
}
|
|
|
|
if( !xChartController.is() || !xChartModel.is() || !xChartView.is() )
|
|
{
|
|
bOldInvalid = true;
|
|
}
|
|
|
|
if( xChartModel.is() )
|
|
{
|
|
bChanged = true;
|
|
xChartModel = nullptr;
|
|
}
|
|
|
|
if( xChartView.is() )
|
|
{
|
|
bChanged = true;
|
|
xChartView = nullptr;
|
|
}
|
|
|
|
if( xChartController.is() )
|
|
{
|
|
bChanged = true;
|
|
xChartController->removeSelectionChangeListener(this);
|
|
xChartController = nullptr;
|
|
}
|
|
|
|
{
|
|
MutexGuard aGuard( m_aMutex);
|
|
m_xChartController = xChartController.get();
|
|
m_xChartModel = xChartModel.get();
|
|
m_xChartView = xChartView.get();
|
|
m_pParent.clear();
|
|
m_pChartWindow.reset();
|
|
}
|
|
|
|
if( bOldInvalid )
|
|
bChanged = false;
|
|
|
|
if( !bChanged )
|
|
return;
|
|
|
|
{
|
|
//before notification we prepare for creation of new context
|
|
//the old context will be deleted after notification then
|
|
MutexGuard aGuard( m_aMutex);
|
|
if( xChartModel.is())
|
|
m_spObjectHierarchy =
|
|
std::make_shared<ObjectHierarchy>( xChartModel, m_xChartView.get().get() );
|
|
else
|
|
m_spObjectHierarchy.reset();
|
|
}
|
|
|
|
{
|
|
AccessibleElementInfo aAccInfo;
|
|
aAccInfo.m_aOID = ObjectIdentifier(u"ROOT"_ustr);
|
|
aAccInfo.m_xChartDocument = m_xChartModel;
|
|
aAccInfo.m_xChartController = m_xChartController;
|
|
aAccInfo.m_xView = m_xChartView;
|
|
aAccInfo.m_pWindow.reset();
|
|
aAccInfo.m_pParent = nullptr;
|
|
aAccInfo.m_spObjectHierarchy = m_spObjectHierarchy;
|
|
aAccInfo.m_pSdrView = m_pSdrView;
|
|
m_pViewForwarder.reset(new AccessibleViewForwarder(this, nullptr));
|
|
aAccInfo.m_pViewForwarder = m_pViewForwarder.get();
|
|
// broadcasts an INVALIDATE_ALL_CHILDREN event globally
|
|
SetInfo( aAccInfo );
|
|
}
|
|
}
|
|
|
|
// view::XSelectionChangeListener
|
|
|
|
void SAL_CALL AccessibleChartView::selectionChanged( const lang::EventObject& /*rEvent*/ )
|
|
{
|
|
rtl::Reference< ::chart::ChartController > xChartController;
|
|
{
|
|
MutexGuard aGuard( m_aMutex);
|
|
xChartController = m_xChartController.get();
|
|
}
|
|
|
|
if( !xChartController.is() )
|
|
return;
|
|
|
|
ObjectIdentifier aSelectedOID( xChartController->getSelection() );
|
|
if ( m_aCurrentSelectionOID.isValid() )
|
|
{
|
|
NotifyEvent( EventType::LOST_SELECTION, m_aCurrentSelectionOID );
|
|
}
|
|
if( aSelectedOID.isValid() )
|
|
{
|
|
NotifyEvent( EventType::GOT_SELECTION, aSelectedOID );
|
|
}
|
|
m_aCurrentSelectionOID = std::move(aSelectedOID);
|
|
}
|
|
|
|
// XEventListener
|
|
void SAL_CALL AccessibleChartView::disposing( const lang::EventObject& /*Source*/ )
|
|
{
|
|
}
|
|
|
|
} //namespace chart
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|