LibreOffice Module svx (master) 1
accessiblecell.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 <sal/config.h>
21#include <sal/log.hxx>
22
23#include <memory>
24
25#include "accessiblecell.hxx"
26#include <cell.hxx>
27
28#include <com/sun/star/accessibility/AccessibleRole.hpp>
29#include <com/sun/star/accessibility/AccessibleStateType.hpp>
30#include <com/sun/star/accessibility/AccessibleEventId.hpp>
31
32#include <editeng/unoedsrc.hxx>
33#include <utility>
34#include <vcl/svapp.hxx>
35#include <vcl/window.hxx>
36
37#include <comphelper/string.hxx>
40#include <svx/unoshtxt.hxx>
41#include <svx/svdotext.hxx>
42#include <tools/debug.hxx>
43
44using namespace sdr::table;
45using namespace ::com::sun::star;
46using namespace ::com::sun::star::uno;
47using namespace ::com::sun::star::accessibility;
48using namespace ::com::sun::star::lang;
49using namespace ::com::sun::star::container;
50
51namespace accessibility {
52
53AccessibleCell::AccessibleCell( const css::uno::Reference< css::accessibility::XAccessible>& rxParent, sdr::table::CellRef xCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo )
54: AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL )
55, maShapeTreeInfo( rShapeTreeInfo )
56, mnIndexInParent( nIndex )
57, mxCell(std::move( xCell ))
58{
59 //Init the pAccTable var
60 pAccTable = dynamic_cast <AccessibleTableShape *> (rxParent.get());
61}
62
63
65{
66 DBG_ASSERT( mpText == nullptr, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" );
67}
68
69
71{
73 const vcl::Window* pWindow = maShapeTreeInfo.GetWindow ();
74 if( !((pView != nullptr) && (pWindow != nullptr) && mxCell.is()))
75 return;
76
77 // create AccessibleTextHelper to handle this shape's text
78 if( mxCell->CanCreateEditOutlinerParaObject() || mxCell->GetOutlinerParaObject() != nullptr )
79 {
80 // non-empty text -> use full-fledged edit source right away
81
82 mpText.reset( new AccessibleTextHelper( std::make_unique<SvxTextEditSource>(mxCell->GetObject(), mxCell.get(), *pView, *pWindow->GetOutDev()) ) );
83 if( mxCell.is() && mxCell->IsActiveCell() )
84 mpText->SetFocus();
85 mpText->SetEventSource(this);
86 }
87}
88
89
90bool AccessibleCell::SetState (sal_Int64 aState)
91{
92 bool bStateHasChanged = false;
93
94 if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
95 {
96 // Offer FOCUSED state to edit engine and detect whether the state
97 // changes.
98 bool bIsFocused = mpText->HaveFocus ();
99 mpText->SetFocus();
100 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
101 }
102 else
103 bStateHasChanged = AccessibleContextBase::SetState (aState);
104
105 return bStateHasChanged;
106}
107
108
109bool AccessibleCell::ResetState (sal_Int64 aState)
110{
111 bool bStateHasChanged = false;
112
113 if (aState == AccessibleStateType::FOCUSED && mpText != nullptr)
114 {
115 // Try to remove FOCUSED state from the edit engine and detect
116 // whether the state changes.
117 bool bIsFocused = mpText->HaveFocus ();
118 mpText->SetFocus (false);
119 bStateHasChanged = (bIsFocused != mpText->HaveFocus ());
120 }
121 else
122 bStateHasChanged = AccessibleContextBase::ResetState (aState);
123
124 return bStateHasChanged;
125}
126
127
128// XInterface
129
130
132{
133 return AccessibleCellBase::queryInterface( aType );
134}
135
136
137void SAL_CALL AccessibleCell::acquire( ) noexcept
138{
139 AccessibleCellBase::acquire();
140}
141
142
143void SAL_CALL AccessibleCell::release( ) noexcept
144{
145 AccessibleCellBase::release();
146}
147
148
149// XAccessibleContext
150
151
155{
156 SolarMutexGuard aSolarGuard;
157 ThrowIfDisposed ();
158 return mpText != nullptr ? mpText->GetChildCount () : 0;
159}
160
161
165Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int64 nIndex)
166{
167 SolarMutexGuard aSolarGuard;
168 ThrowIfDisposed ();
169
170 return mpText->GetChild (nIndex);
171}
172
173
181{
182 SolarMutexGuard aSolarGuard;
183 ::osl::MutexGuard aGuard (m_aMutex);
184 sal_Int64 nStateSet = 0;
185
186 if (rBHelper.bDisposed || mpText == nullptr)
187 {
188 // Return a minimal state set that only contains the DEFUNC state.
190 }
191 else
192 {
193 // Merge current FOCUSED state from edit engine.
194 if (mpText != nullptr)
195 {
196 if (mpText->HaveFocus())
197 mnStateSet |= AccessibleStateType::FOCUSED;
198 else
199 mnStateSet &= ~AccessibleStateType::FOCUSED;
200 }
201 // Set the invisible state for merged cell
202 if (mxCell.is() && mxCell->isMerged())
203 mnStateSet &= ~AccessibleStateType::VISIBLE;
204 else
205 mnStateSet |= AccessibleStateType::VISIBLE;
206
207
208 //Just when the parent table is not read-only,set states EDITABLE,RESIZABLE,MOVEABLE
209 css::uno::Reference<XAccessible> xTempAcc = getAccessibleParent();
210 if( xTempAcc.is() )
211 {
212 css::uno::Reference<XAccessibleContext>
213 xTempAccContext = xTempAcc->getAccessibleContext();
214 if( xTempAccContext.is() )
215 {
216 if (xTempAccContext->getAccessibleStateSet() & AccessibleStateType::EDITABLE)
217 {
218 mnStateSet |= AccessibleStateType::EDITABLE;
219 mnStateSet |= AccessibleStateType::RESIZABLE;
220 mnStateSet |= AccessibleStateType::MOVEABLE;
221 }
222 }
223 }
224 nStateSet = mnStateSet;
225 }
226
227 return nStateSet;
228}
229
230
231// XAccessibleComponent
232
233
234sal_Bool SAL_CALL AccessibleCell::containsPoint( const css::awt::Point& aPoint)
235{
237}
238
247Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const css::awt::Point& aPoint)
248{
249 SolarMutexGuard aSolarGuard;
250 ::osl::MutexGuard aGuard (m_aMutex);
251
252 sal_Int64 nChildCount = getAccessibleChildCount ();
253 for (sal_Int64 i = 0; i < nChildCount; ++i)
254 {
255 Reference<XAccessible> xChild (getAccessibleChild (i));
256 if (xChild.is())
257 {
258 Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY);
259 if (xChildComponent.is())
260 {
261 awt::Rectangle aBBox (xChildComponent->getBounds());
262 if ( (aPoint.X >= aBBox.X)
263 && (aPoint.Y >= aBBox.Y)
264 && (aPoint.X < aBBox.X+aBBox.Width)
265 && (aPoint.Y < aBBox.Y+aBBox.Height) )
266 return xChild;
267 }
268 }
269 }
270
271 // Have not found a child under the given point. Returning empty
272 // reference to indicate this.
273 return uno::Reference<XAccessible>();
274}
275
276
277css::awt::Rectangle SAL_CALL AccessibleCell::getBounds()
278{
279 SolarMutexGuard aSolarGuard;
280 ::osl::MutexGuard aGuard (m_aMutex);
281
282 ThrowIfDisposed ();
283 css::awt::Rectangle aBoundingBox;
284 if( mxCell.is() )
285 {
286 // Get the cell's bounding box in internal coordinates (in 100th of mm)
287 const ::tools::Rectangle aCellRect( mxCell->getCellRect() );
288
289 // Transform coordinates from internal to pixel.
290 if (maShapeTreeInfo.GetViewForwarder() == nullptr)
291 throw uno::RuntimeException ("AccessibleCell has no valid view forwarder", getXWeak());
292
293 ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) );
294 ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() ));
295
296 // Clip the shape's bounding box with the bounding box of its parent.
297 Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY);
298 if (xParentComponent.is())
299 {
300 // Make the coordinates relative to the parent.
301 awt::Point aParentLocation (xParentComponent->getLocationOnScreen());
302 int x = aPixelPosition.getX() - aParentLocation.X;
303 int y = aPixelPosition.getY() - aParentLocation.Y;
304
305 // Clip with parent (with coordinates relative to itself).
306 ::tools::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight());
307 awt::Size aParentSize (xParentComponent->getSize());
308 ::tools::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height);
309 aBBox = aBBox.GetIntersection (aParentBBox);
310 aBoundingBox = awt::Rectangle ( aBBox.Left(), aBBox.Top(), aBBox.getOpenWidth(), aBBox.getOpenHeight());
311 }
312 else
313 {
314 SAL_INFO("svx", "parent does not support component");
315 aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight());
316 }
317 }
318
319 return aBoundingBox;
320}
321
322
323css::awt::Point SAL_CALL AccessibleCell::getLocation()
324{
325 ThrowIfDisposed ();
326 css::awt::Rectangle aBoundingBox(getBounds());
327 return css::awt::Point(aBoundingBox.X, aBoundingBox.Y);
328}
329
330
331css::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen()
332{
333 ThrowIfDisposed ();
334
335 // Get relative position...
336 css::awt::Point aLocation(getLocation ());
337
338 // ... and add absolute position of the parent.
339 Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY);
340 if(xParentComponent.is())
341 {
342 css::awt::Point aParentLocation(xParentComponent->getLocationOnScreen());
343 aLocation.X += aParentLocation.X;
344 aLocation.Y += aParentLocation.Y;
345 }
346 else
347 {
348 SAL_WARN("svx", "parent does not support XAccessibleComponent");
349 }
350
351 return aLocation;
352}
353
354
355awt::Size SAL_CALL AccessibleCell::getSize()
356{
357 ThrowIfDisposed ();
358 awt::Rectangle aBoundingBox (getBounds());
359 return awt::Size (aBoundingBox.Width, aBoundingBox.Height);
360}
361
362
364{
366}
367
368
370{
371 ThrowIfDisposed ();
372
373 // todo
374 return sal_Int32(0x0ffffffL);
375}
376
377
379{
380 ThrowIfDisposed ();
381
382 // todo
383 return 0;
384}
385
386
387// XAccessibleExtendedComponent
388
389
390css::uno::Reference< css::awt::XFont > SAL_CALL AccessibleCell::getFont()
391{
392//todo
394}
395
396
398{
400}
401
402
404{
406}
407
408
409// XAccessibleEventBroadcaster
410
411
412void SAL_CALL AccessibleCell::addAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
413{
414 SolarMutexGuard aSolarGuard;
415 ::osl::MutexGuard aGuard (m_aMutex);
416 if (rBHelper.bDisposed || rBHelper.bInDispose)
417 {
418 Reference<XInterface> xSource( static_cast<XComponent *>(this) );
419 lang::EventObject aEventObj(xSource);
420 rxListener->disposing(aEventObj);
421 }
422 else
423 {
425 if (mpText != nullptr)
426 mpText->AddEventListener (rxListener);
427 }
428}
429
430
431void SAL_CALL AccessibleCell::removeAccessibleEventListener( const Reference<XAccessibleEventListener >& rxListener)
432{
433 SolarMutexGuard aSolarGuard;
435 if (mpText != nullptr)
436 mpText->RemoveEventListener (rxListener);
437}
438
439
440// XServiceInfo
441
442
444{
445 return "AccessibleCell";
446}
447
448
449Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames()
450{
451 ThrowIfDisposed ();
452 const css::uno::Sequence<OUString> vals { "com.sun.star.drawing.AccessibleCell" };
454}
455
456
457// IAccessibleViewForwarderListener
458
459
461{
462 // Inform all listeners that the graphical representation (i.e. size
463 // and/or position) of the shape has changed.
464 CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any(), -1);
465
466 // update our children that our screen position might have changed
467 if( mpText )
468 mpText->UpdateChildren();
469}
470
471
472// protected
473
474
476{
477 SolarMutexGuard aSolarGuard;
478 ::osl::MutexGuard aGuard (m_aMutex);
479
480 // Make sure to send an event that this object loses the focus in the
481 // case that it has the focus.
482 mnStateSet &= ~AccessibleStateType::FOCUSED;
483
484 if (mpText != nullptr)
485 {
486 mpText->Dispose();
487 mpText.reset();
488 }
489
490 // Cleanup. Remove references to objects to allow them to be
491 // destroyed.
492 mxCell.clear();
494
495 // Call base classes.
496 AccessibleContextBase::dispose ();
497}
498
500{
501 ThrowIfDisposed ();
502 return mnIndexInParent;
503}
504
505
506OUString AccessibleCell::getCellName( sal_Int32 nCol, sal_Int32 nRow )
507{
508 OUStringBuffer aBuf;
509
510 if (nCol < 26*26)
511 {
512 if (nCol < 26)
513 aBuf.append( static_cast<sal_Unicode>( 'A' +
514 static_cast<sal_uInt16>(nCol)));
515 else
516 {
517 aBuf.append(
518 OUStringChar(static_cast<sal_Unicode>( 'A' +
519 (static_cast<sal_uInt16>(nCol) / 26) - 1))
520 + OUStringChar( static_cast<sal_Unicode>( 'A' +
521 (static_cast<sal_uInt16>(nCol) % 26))) );
522 }
523 }
524 else
525 {
526 OUStringBuffer aStr;
527 while (nCol >= 26)
528 {
529 sal_Int32 nC = nCol % 26;
530 aStr.append(static_cast<sal_Unicode>( 'A' +
531 static_cast<sal_uInt16>(nC)));
532 nCol = nCol - nC;
533 nCol = nCol / 26 - 1;
534 }
535 aStr.append(static_cast<sal_Unicode>( 'A' +
536 static_cast<sal_uInt16>(nCol)));
538 }
539 aBuf.append(nRow+1);
540 return aBuf.makeStringAndClear();
541}
542
544{
545 ThrowIfDisposed ();
546 SolarMutexGuard aSolarGuard;
547
548 if( pAccTable )
549 {
550 try
551 {
552 sal_Int32 nRow = 0, nCol = 0;
554 return getCellName( nCol, nRow );
555 }
556 catch(const Exception&)
557 {
558 }
559 }
560
561 return AccessibleCellBase::getAccessibleName();
562}
563
565{
566 if (mpText)
567 mpText->UpdateChildren();
568}
569
570/* MT: Above getAccessibleName was introduced with IA2 CWS, while below was introduce in 3.3 meanwhile. Check which one is correct
571+If this is correct, we also don't need sdr::table::CellRef getCellRef(), UpdateChildren(), getCellName( sal_Int32 nCol, sal_Int32 nRow ) above
572+
573
574OUString SAL_CALL AccessibleCell::getAccessibleName() throw (css::uno::RuntimeException)
575{
576 ThrowIfDisposed ();
577 SolarMutexGuard aSolarGuard;
578
579 if( mxCell.is() )
580 return mxCell->getName();
581
582 return AccessibleCellBase::getAccessibleName();
583}
584*/
585
586} // end of namespace accessibility
587
588/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr tools::Long getX() const
constexpr tools::Long getY() const
constexpr tools::Long getHeight() const
constexpr tools::Long getWidth() const
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild(sal_Int64 nIndex) override
Forward the request to the shape.
virtual css::awt::Point SAL_CALL getLocationOnScreen() override
virtual bool SetState(sal_Int64 aState) override
virtual OUString SAL_CALL getAccessibleName() override
virtual sal_Int64 SAL_CALL getAccessibleIndexInParent() override
virtual void SAL_CALL release() noexcept override
virtual void SAL_CALL addAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &rxListener) override
virtual css::awt::Size SAL_CALL getSize() override
AccessibleCell(const css::uno::Reference< css::accessibility::XAccessible > &rxParent, sdr::table::CellRef xCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo &rShapeTreeInfo)
virtual sal_Bool SAL_CALL containsPoint(const css::awt::Point &aPoint) override
virtual css::awt::Rectangle SAL_CALL getBounds() override
virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override
virtual void ViewForwarderChanged() override
This method is called to indicate a change of the specified view forwarder, specifically,...
std::unique_ptr< AccessibleTextHelper > mpText
The accessible text engine. May be NULL if it can not be created.
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual sal_Int32 SAL_CALL getForeground() override
AccessibleTableShape * pAccTable
virtual OUString SAL_CALL getToolTipText() override
static OUString getCellName(sal_Int32 nCol, sal_Int32 nRow)
virtual OUString SAL_CALL getImplementationName() override
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint(const css::awt::Point &aPoint) override
The implementation below is at the moment straightforward.
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &aType) override
virtual bool ResetState(sal_Int64 aState) override
virtual sal_Int32 SAL_CALL getBackground() override
AccessibleShapeTreeInfo maShapeTreeInfo
Bundle of information passed to all shapes in a document tree.
virtual css::awt::Point SAL_CALL getLocation() override
virtual ~AccessibleCell() override
virtual sal_Int64 SAL_CALL getAccessibleStateSet() override
Return a copy of the state set.
virtual void SAL_CALL acquire() noexcept override
sal_Int32 mnIndexInParent
the index in parent.
virtual void SAL_CALL removeAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &rxListener) override
virtual sal_Int64 SAL_CALL getAccessibleChildCount() override
The children of this cell come from the paragraphs of text.
virtual void SAL_CALL grabFocus() override
virtual OUString SAL_CALL getTitledBorderText() override
virtual void SAL_CALL disposing() override
This method is called from the component helper base class while disposing.
virtual OUString SAL_CALL getToolTipText() override
virtual void SAL_CALL grabFocus() override
virtual OUString SAL_CALL getTitledBorderText() override
virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override
virtual sal_Bool SAL_CALL containsPoint(const css::awt::Point &aPoint) override
virtual bool SetState(sal_Int64 aState)
virtual sal_Int64 SAL_CALL getAccessibleStateSet() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual bool ResetState(sal_Int64 aState)
virtual void SAL_CALL removeAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
virtual void SAL_CALL addAccessibleEventListener(const css::uno::Reference< css::accessibility::XAccessibleEventListener > &xListener) override
This class bundles all information that is passed down the tree of accessible shapes so that each sha...
const IAccessibleViewForwarder * GetViewForwarder() const
Return the current view forwarder.
SdrView * GetSdrView() const
Return the current SdrView.
vcl::Window * GetWindow() const
Return the current Window.
void getColumnAndRow(sal_Int64 nChildIndex, sal_Int32 &rnColumn, sal_Int32 &rnRow)
Helper class for objects containing EditEngine/Outliner text.
virtual Point LogicToPixel(const Point &rPoint) const =0
Transform the specified point from internal coordinates in 100th of mm to an absolute screen position...
tools::Rectangle GetIntersection(const tools::Rectangle &rRect) const
constexpr tools::Long Top() const
tools::Long getOpenHeight() const
tools::Long getOpenWidth() const
constexpr tools::Long Left() const
::OutputDevice const * GetOutDev() const
#define DBG_ASSERT(sCon, aError)
float y
float x
std::mutex m_aMutex
sal_Int32 nIndex
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
aStr
aBuf
::cppu::ImplInheritanceHelper< AccessibleContextBase, css::accessibility::XAccessibleExtendedComponent > AccessibleCellBase
@ Exception
OUString reverseString(std::u16string_view rStr)
css::uno::Sequence< T > concatSequences(const css::uno::Sequence< T > &rS1, const Ss &... rSn)
Type
int i
unsigned char sal_Bool
sal_uInt16 sal_Unicode