tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / Accessibility / AccessibleEditObject.cxx
blobd903b9d432187a6b9f46c4efc968af98a9563f9c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <sal/config.h>
22 #include <memory>
23 #include <utility>
25 #include <AccessibleEditObject.hxx>
26 #include <AccessibleText.hxx>
27 #include <editsrc.hxx>
28 #include <scmod.hxx>
29 #include <inputhdl.hxx>
30 #include <inputwin.hxx>
32 #include <com/sun/star/accessibility/AccessibleRole.hpp>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
35 #include <com/sun/star/sheet/XSpreadsheet.hpp>
36 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
37 #include <svx/AccessibleTextHelper.hxx>
38 #include <editeng/editview.hxx>
39 #include <editeng/editeng.hxx>
40 #include <svx/svdmodel.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/window.hxx>
43 #include <sfx2/objsh.hxx>
44 #include <cppuhelper/queryinterface.hxx>
46 #include <unonames.hxx>
47 #include <document.hxx>
48 #include <AccessibleDocument.hxx>
49 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
50 #include <unotools/accessiblerelationsethelper.hxx>
51 #include <com/sun/star/accessibility/XAccessibleText.hpp>
53 using ::com::sun::star::lang::IndexOutOfBoundsException;
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::accessibility;
57 //===== internal ============================================================
59 ScAccessibleEditObject::ScAccessibleEditObject(
60 const uno::Reference<XAccessible>& rxParent,
61 EditView* pEditView, vcl::Window* pWin, const OUString& rName,
62 const OUString& rDescription, EditObjectType eObjectType)
63 : ScAccessibleContextBase(rxParent, AccessibleRole::TEXT_FRAME)
64 , mpEditView(pEditView)
65 , mpWindow(pWin)
66 , mpTextWnd(nullptr)
67 , meObjectType(eObjectType)
68 , mbHasFocus(false)
69 , m_pScDoc(nullptr)
71 InitAcc(rxParent, pEditView, rName, rDescription);
74 ScAccessibleEditObject::ScAccessibleEditObject(EditObjectType eObjectType)
75 : ScAccessibleContextBase(nullptr, AccessibleRole::TEXT_FRAME)
76 , mpEditView(nullptr)
77 , mpWindow(nullptr)
78 , mpTextWnd(nullptr)
79 , meObjectType(eObjectType)
80 , mbHasFocus(false)
81 , m_pScDoc(nullptr)
85 void ScAccessibleEditObject::InitAcc(
86 const uno::Reference<XAccessible>& rxParent,
87 EditView* pEditView,
88 const OUString& rName,
89 const OUString& rDescription)
91 SetParent(rxParent);
92 mpEditView = pEditView;
94 CreateTextHelper();
95 SetName(rName);
96 SetDescription(rDescription);
97 if( meObjectType == CellInEditMode)
99 const ScAccessibleDocument *pAccDoc = static_cast<ScAccessibleDocument*>(rxParent.get());
100 if (pAccDoc)
102 m_pScDoc = pAccDoc->GetDocument();
103 m_curCellAddress =pAccDoc->GetCurCellAddress();
108 ScAccessibleEditObject::~ScAccessibleEditObject()
110 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
112 // increment refcount to prevent double call off dtor
113 osl_atomic_increment( &m_refCount );
114 // call dispose to inform object which have a weak reference to this object
115 dispose();
119 void SAL_CALL ScAccessibleEditObject::disposing()
121 SolarMutexGuard aGuard;
122 mpTextHelper.reset();
124 ScAccessibleContextBase::disposing();
127 void ScAccessibleEditObject::LostFocus()
129 mbHasFocus = false;
130 if (mpTextHelper)
131 mpTextHelper->SetFocus(false);
132 CommitFocusLost();
135 void ScAccessibleEditObject::GotFocus()
137 mbHasFocus = true;
138 CommitFocusGained();
139 if (mpTextHelper)
140 mpTextHelper->SetFocus();
143 //===== XInterface ==========================================================
145 css::uno::Any SAL_CALL
146 ScAccessibleEditObject::queryInterface (const css::uno::Type & rType)
148 css::uno::Any aReturn = ScAccessibleContextBase::queryInterface (rType);
149 if ( ! aReturn.hasValue())
150 aReturn = ::cppu::queryInterface (rType,
151 static_cast< css::accessibility::XAccessibleSelection* >(this)
153 return aReturn;
155 void SAL_CALL
156 ScAccessibleEditObject::acquire()
157 noexcept
159 ScAccessibleContextBase::acquire ();
161 void SAL_CALL
162 ScAccessibleEditObject::release()
163 noexcept
165 ScAccessibleContextBase::release ();
167 //===== XAccessibleComponent ============================================
169 uno::Reference< XAccessible > SAL_CALL ScAccessibleEditObject::getAccessibleAtPoint(
170 const awt::Point& rPoint )
172 uno::Reference<XAccessible> xRet;
173 if (containsPoint(rPoint))
175 SolarMutexGuard aGuard;
176 IsObjectValid();
178 CreateTextHelper();
180 xRet = mpTextHelper->GetAt(rPoint);
183 return xRet;
186 AbsoluteScreenPixelRectangle ScAccessibleEditObject::GetBoundingBoxOnScreen() const
188 AbsoluteScreenPixelRectangle aScreenBounds;
190 if ( mpWindow )
192 if ( meObjectType == CellInEditMode )
194 if (mpEditView)
196 MapMode aMapMode(mpEditView->getEditEngine().GetRefMapMode());
197 tools::Rectangle aScreenBoundsLog = mpWindow->LogicToPixel( mpEditView->GetOutputArea(), aMapMode );
198 Point aCellLoc = aScreenBoundsLog.TopLeft();
199 AbsoluteScreenPixelRectangle aWindowRect = mpWindow->GetWindowExtentsAbsolute();
200 AbsoluteScreenPixelPoint aWindowLoc = aWindowRect.TopLeft();
201 AbsoluteScreenPixelPoint aPos( aCellLoc.getX() + aWindowLoc.getX(), aCellLoc.getY() + aWindowLoc.getY() );
202 aScreenBounds = AbsoluteScreenPixelRectangle( aPos, aScreenBoundsLog.GetSize() );
205 else
207 aScreenBounds = mpWindow->GetWindowExtentsAbsolute();
211 return aScreenBounds;
214 tools::Rectangle ScAccessibleEditObject::GetBoundingBox() const
216 tools::Rectangle aBounds( GetBoundingBoxOnScreen() );
218 if ( mpWindow )
220 uno::Reference< XAccessible > xThis( mpWindow->GetAccessible() );
221 if ( xThis.is() )
223 uno::Reference< XAccessibleContext > xContext( xThis->getAccessibleContext() );
224 if ( xContext.is() )
226 uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() );
227 if ( xParent.is() )
229 uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
230 if ( xParentComponent.is() )
232 Point aScreenLoc = aBounds.TopLeft();
233 awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
234 Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y );
235 aBounds.SetPos( aPos );
242 return aBounds;
245 //===== XAccessibleContext ==============================================
247 sal_Int64 SAL_CALL
248 ScAccessibleEditObject::getAccessibleChildCount()
250 SolarMutexGuard aGuard;
251 IsObjectValid();
252 CreateTextHelper();
253 return mpTextHelper->GetChildCount();
256 uno::Reference< XAccessible > SAL_CALL
257 ScAccessibleEditObject::getAccessibleChild(sal_Int64 nIndex)
259 SolarMutexGuard aGuard;
260 IsObjectValid();
261 CreateTextHelper();
262 return mpTextHelper->GetChild(nIndex);
265 sal_Int64 SAL_CALL ScAccessibleEditObject::getAccessibleStateSet()
267 SolarMutexGuard aGuard;
268 sal_Int64 nParentStates = 0;
269 if (getAccessibleParent().is())
271 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
272 nParentStates = xParentContext->getAccessibleStateSet();
274 sal_Int64 nStateSet = 0;
275 if (IsDefunc(nParentStates))
276 nStateSet |= AccessibleStateType::DEFUNC;
277 else
279 // all states are const, because this object exists only in one state
280 nStateSet |= AccessibleStateType::EDITABLE;
281 nStateSet |= AccessibleStateType::ENABLED;
282 nStateSet |= AccessibleStateType::SENSITIVE;
283 nStateSet |= AccessibleStateType::MULTI_LINE;
284 nStateSet |= AccessibleStateType::MULTI_SELECTABLE;
285 nStateSet |= AccessibleStateType::SHOWING;
286 nStateSet |= AccessibleStateType::VISIBLE;
288 return nStateSet;
291 OUString
292 ScAccessibleEditObject::createAccessibleDescription()
294 // OSL_FAIL("Should never be called, because is set in the constructor.")
295 return OUString();
298 OUString
299 ScAccessibleEditObject::createAccessibleName()
301 OSL_FAIL("Should never be called, because is set in the constructor.");
302 return OUString();
305 ///===== XAccessibleEventBroadcaster =====================================
307 void SAL_CALL
308 ScAccessibleEditObject::addAccessibleEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
310 CreateTextHelper();
312 mpTextHelper->AddEventListener(xListener);
314 ScAccessibleContextBase::addAccessibleEventListener(xListener);
317 void SAL_CALL
318 ScAccessibleEditObject::removeAccessibleEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
320 CreateTextHelper();
322 mpTextHelper->RemoveEventListener(xListener);
324 ScAccessibleContextBase::removeAccessibleEventListener(xListener);
327 //===== XServiceInfo ====================================================
329 OUString SAL_CALL ScAccessibleEditObject::getImplementationName()
331 return u"ScAccessibleEditObject"_ustr;
334 //===== XTypeProvider =======================================================
336 uno::Sequence<sal_Int8> SAL_CALL
337 ScAccessibleEditObject::getImplementationId()
339 return css::uno::Sequence<sal_Int8>();
342 //==== internal =========================================================
344 bool ScAccessibleEditObject::IsDefunc(sal_Int64 nParentStates)
346 return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
347 (nParentStates & AccessibleStateType::DEFUNC);
350 OutputDevice* ScAccessibleEditObject::GetOutputDeviceForView()
352 return mpWindow->GetOutDev();
355 void ScAccessibleEditObject::CreateTextHelper()
357 if (mpTextHelper)
358 return;
360 ::std::unique_ptr < ScAccessibleTextData > pAccessibleTextData;
361 if (meObjectType == CellInEditMode || meObjectType == EditControl)
363 pAccessibleTextData.reset
364 (new ScAccessibleEditObjectTextData(mpEditView, GetOutputDeviceForView()));
366 else
368 pAccessibleTextData.reset
369 (new ScAccessibleEditLineTextData(nullptr, GetOutputDeviceForView(), mpTextWnd));
372 std::unique_ptr<ScAccessibilityEditSource> pEditSrc =
373 std::make_unique<ScAccessibilityEditSource>(std::move(pAccessibleTextData));
375 mpTextHelper = std::make_unique<::accessibility::AccessibleTextHelper>(std::move(pEditSrc));
376 mpTextHelper->SetEventSource(this);
378 const ScInputHandler* pInputHdl = ScModule::get()->GetInputHdl();
379 if ( pInputHdl && pInputHdl->IsEditMode() )
381 mpTextHelper->SetFocus();
383 else
385 mpTextHelper->SetFocus(mbHasFocus);
388 // #i54814# activate cell in edit mode
389 if( meObjectType == CellInEditMode )
391 // do not activate cell object, if top edit line is active
392 if( pInputHdl && !pInputHdl->IsTopMode() )
394 SdrHint aHint( SdrHintKind::BeginEdit );
395 mpTextHelper->GetEditSource().GetBroadcaster().Broadcast( aHint );
400 sal_Int32 SAL_CALL ScAccessibleEditObject::getForeground( )
402 return GetFgBgColor(SC_UNONAME_CCOLOR);
405 sal_Int32 SAL_CALL ScAccessibleEditObject::getBackground( )
407 return GetFgBgColor(SC_UNONAME_CELLBACK);
410 sal_Int32 ScAccessibleEditObject::GetFgBgColor( const OUString &strPropColor)
412 SolarMutexGuard aGuard;
413 sal_Int32 nColor(0);
414 if (m_pScDoc)
416 ScDocShell* pObjSh = m_pScDoc->GetDocumentShell();
417 if ( pObjSh )
419 ScModelObj* pSpreadDoc = pObjSh->GetModel();
420 if ( pSpreadDoc )
422 uno::Reference<sheet::XSpreadsheets> xSheets = pSpreadDoc->getSheets();
423 uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
424 if ( xIndex.is() )
426 uno::Any aTable = xIndex->getByIndex(m_curCellAddress.Tab());
427 uno::Reference<sheet::XSpreadsheet> xTable;
428 if (aTable>>=xTable)
430 uno::Reference<table::XCell> xCell = xTable->getCellByPosition(m_curCellAddress.Col(), m_curCellAddress.Row());
431 if (xCell.is())
433 uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
434 if (xCellProps.is())
436 uno::Any aAny = xCellProps->getPropertyValue(strPropColor);
437 aAny >>= nColor;
445 return nColor;
447 //===== XAccessibleSelection ============================================
449 void SAL_CALL ScAccessibleEditObject::selectAccessibleChild( sal_Int64 )
453 sal_Bool SAL_CALL ScAccessibleEditObject::isAccessibleChildSelected( sal_Int64 nChildIndex )
455 uno::Reference<XAccessible> xAcc = getAccessibleChild( nChildIndex );
456 uno::Reference<XAccessibleContext> xContext;
457 if( xAcc.is() )
458 xContext = xAcc->getAccessibleContext();
459 if( xContext.is() )
461 if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
463 uno::Reference< css::accessibility::XAccessibleText >
464 xText(xAcc, uno::UNO_QUERY);
465 if( xText.is() )
467 if( xText->getSelectionStart() >= 0 ) return true;
471 return false;
474 void SAL_CALL ScAccessibleEditObject::clearAccessibleSelection( )
478 void SAL_CALL ScAccessibleEditObject::selectAllAccessibleChildren( )
482 sal_Int64 SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChildCount()
484 sal_Int64 nCount = 0;
485 sal_Int64 TotalCount = getAccessibleChildCount();
486 for( sal_Int64 i = 0; i < TotalCount; i++ )
487 if( isAccessibleChildSelected(i) ) nCount++;
488 return nCount;
491 uno::Reference<XAccessible> SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex )
493 if ( nSelectedChildIndex < 0 || nSelectedChildIndex > getSelectedAccessibleChildCount() )
494 throw IndexOutOfBoundsException();
496 for (sal_Int64 i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++ )
497 if( isAccessibleChildSelected(i1) )
499 if( i2 == nSelectedChildIndex )
500 return getAccessibleChild( i1 );
501 i2++;
503 return uno::Reference<XAccessible>();
506 void SAL_CALL ScAccessibleEditObject::deselectAccessibleChild(sal_Int64)
510 uno::Reference< XAccessibleRelationSet > ScAccessibleEditObject::getAccessibleRelationSet( )
512 SolarMutexGuard aGuard;
513 vcl::Window* pWindow = mpWindow;
514 rtl::Reference<utl::AccessibleRelationSetHelper> rRelationSet = new utl::AccessibleRelationSetHelper;
515 if ( pWindow )
517 vcl::Window *pLabeledBy = pWindow->GetAccessibleRelationLabeledBy();
518 if ( pLabeledBy && pLabeledBy != pWindow )
520 uno::Sequence<uno::Reference<css::accessibility::XAccessible>> aSequence { pLabeledBy->GetAccessible() };
521 rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType_LABELED_BY, aSequence ) );
523 vcl::Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf();
524 if ( pMemberOf && pMemberOf != pWindow )
526 uno::Sequence< uno::Reference<css::accessibility::XAccessible> > aSequence { pMemberOf->GetAccessible() };
527 rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType_MEMBER_OF, aSequence ) );
529 return rRelationSet;
531 return uno::Reference< XAccessibleRelationSet >();
534 AbsoluteScreenPixelRectangle ScAccessibleEditControlObject::GetBoundingBoxOnScreen() const
536 AbsoluteScreenPixelRectangle aScreenBounds;
538 if (m_pController && m_pController->GetDrawingArea())
540 aScreenBounds = AbsoluteScreenPixelRectangle(m_pController->GetDrawingArea()->get_accessible_location_on_screen(),
541 m_pController->GetOutputSizePixel());
544 return aScreenBounds;
547 tools::Rectangle ScAccessibleEditControlObject::GetBoundingBox() const
549 tools::Rectangle aBounds( GetBoundingBoxOnScreen() );
551 uno::Reference< XAccessibleContext > xContext(const_cast<ScAccessibleEditControlObject*>(this)->getAccessibleContext());
552 if ( xContext.is() )
554 uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() );
555 if ( xParent.is() )
557 uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
558 if ( xParentComponent.is() )
560 Point aScreenLoc = aBounds.TopLeft();
561 awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
562 Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y );
563 aBounds.SetPos( aPos );
568 return aBounds;
571 void SAL_CALL ScAccessibleEditControlObject::disposing()
573 ScAccessibleEditObject::disposing();
574 m_pController = nullptr;
577 uno::Reference< XAccessibleRelationSet > ScAccessibleEditControlObject::getAccessibleRelationSet()
579 SolarMutexGuard aGuard;
580 if (!m_pController || !m_pController->GetDrawingArea())
581 return uno::Reference< XAccessibleRelationSet >();
582 return m_pController->GetDrawingArea()->get_accessible_relation_set();
585 OutputDevice* ScAccessibleEditControlObject::GetOutputDeviceForView()
587 if (!m_pController || !m_pController->GetDrawingArea())
588 return nullptr;
589 return &m_pController->GetDrawingArea()->get_ref_device();
592 ScAccessibleEditLineObject::ScAccessibleEditLineObject(ScTextWnd* pTextWnd)
593 : ScAccessibleEditControlObject(pTextWnd, ScAccessibleEditObject::EditLine)
595 // tdf#141769 set this early so its always available, even before the on-demand
596 // editview is created
597 mpTextWnd = pTextWnd;
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */