summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/Accessibility/AccessibleCsvControl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/Accessibility/AccessibleCsvControl.cxx')
-rw-r--r--sc/source/ui/Accessibility/AccessibleCsvControl.cxx1460
1 files changed, 1460 insertions, 0 deletions
diff --git a/sc/source/ui/Accessibility/AccessibleCsvControl.cxx b/sc/source/ui/Accessibility/AccessibleCsvControl.cxx
new file mode 100644
index 000000000..e9a4a1dee
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleCsvControl.cxx
@@ -0,0 +1,1460 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+
+#include <utility>
+
+#include <AccessibleCsvControl.hxx>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <scitems.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/langitem.hxx>
+#include <csvtablebox.hxx>
+#include <csvcontrol.hxx>
+#include <csvruler.hxx>
+#include <csvgrid.hxx>
+#include <AccessibleText.hxx>
+#include <editsrc.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <scmod.hxx>
+#include <svtools/colorcfg.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using ::utl::AccessibleRelationSetHelper;
+using ::utl::AccessibleStateSetHelper;
+using ::accessibility::AccessibleStaticTextBase;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::lang::IndexOutOfBoundsException;
+using ::com::sun::star::beans::PropertyValue;
+using namespace ::com::sun::star::accessibility;
+
+const sal_Unicode cRulerDot = '.';
+const sal_Unicode cRulerLine = '|';
+
+const sal_Int32 CSV_LINE_HEADER = CSV_POS_INVALID;
+const sal_uInt32 CSV_COLUMN_HEADER = CSV_COLUMN_INVALID;
+
+ScAccessibleCsvControl::ScAccessibleCsvControl(ScCsvControl& rControl)
+ : mpControl(&rControl)
+{
+}
+
+ScAccessibleCsvControl::~ScAccessibleCsvControl()
+{
+ ensureDisposed();
+}
+
+void SAL_CALL ScAccessibleCsvControl::disposing()
+{
+ SolarMutexGuard aGuard;
+ mpControl = nullptr;
+ comphelper::OAccessibleComponentHelper::disposing();
+}
+
+// XAccessibleComponent -------------------------------------------------------
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvControl::getAccessibleAtPoint( const css::awt::Point& /* rPoint */ )
+{
+ ensureAlive();
+ return nullptr;
+}
+
+void SAL_CALL ScAccessibleCsvControl::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ implGetControl().GrabFocus();
+}
+
+// events ---------------------------------------------------------------------
+
+void ScAccessibleCsvControl::SendFocusEvent( bool bFocused )
+{
+ Any aOldAny, aNewAny;
+ if (bFocused)
+ aNewAny <<= AccessibleStateType::FOCUSED;
+ else
+ aOldAny <<= AccessibleStateType::FOCUSED;
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny);
+}
+
+void ScAccessibleCsvControl::SendCaretEvent()
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendCaretEvent - Illegal call" );
+}
+
+void ScAccessibleCsvControl::SendVisibleEvent()
+{
+ NotifyAccessibleEvent(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
+}
+
+void ScAccessibleCsvControl::SendSelectionEvent()
+{
+ NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, Any(), Any());
+}
+
+void ScAccessibleCsvControl::SendTableUpdateEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */, bool /* bAllRows */ )
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendTableUpdateEvent - Illegal call" );
+}
+
+void ScAccessibleCsvControl::SendInsertColumnEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */ )
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendInsertColumnEvent - Illegal call" );
+}
+
+void ScAccessibleCsvControl::SendRemoveColumnEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */ )
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendRemoveColumnEvent - Illegal call" );
+}
+
+// helpers --------------------------------------------------------------------
+
+css::awt::Rectangle ScAccessibleCsvControl::implGetBounds()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ Size aOutSize(implGetControl().GetOutputSizePixel());
+ return css::awt::Rectangle(0, 0, aOutSize.Width(), aOutSize.Height());
+}
+
+ScCsvControl& ScAccessibleCsvControl::implGetControl() const
+{
+ assert(mpControl && "ScAccessibleCsvControl::implGetControl - missing control");
+ return *mpControl;
+}
+
+rtl::Reference<AccessibleStateSetHelper> ScAccessibleCsvControl::implCreateStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = new AccessibleStateSetHelper();
+ if (isAlive())
+ {
+ const ScCsvControl& rCtrl = implGetControl();
+ pStateSet->AddState( AccessibleStateType::OPAQUE );
+ if( rCtrl.IsEnabled() )
+ pStateSet->AddState( AccessibleStateType::ENABLED );
+ if( rCtrl.IsReallyVisible() )
+ pStateSet->AddState( AccessibleStateType::SHOWING );
+ if( rCtrl.IsVisible() )
+ pStateSet->AddState( AccessibleStateType::VISIBLE );
+ }
+ else
+ pStateSet->AddState( AccessibleStateType::DEFUNC );
+ return pStateSet;
+}
+
+// Ruler ======================================================================
+
+/** Converts a ruler cursor position to API text index. */
+static sal_Int32 lcl_GetApiPos( sal_Int32 nRulerPos )
+{
+ sal_Int32 nApiPos = nRulerPos;
+ sal_Int32 nStart = (nRulerPos - 1) / 10;
+ sal_Int32 nExp = 1;
+ while( nStart >= nExp )
+ {
+ nApiPos += nStart - nExp + 1;
+ nExp *= 10;
+ }
+ return ::std::max( nApiPos, static_cast<sal_Int32>(0) );
+}
+
+/** Converts an API text index to a ruler cursor position. */
+static sal_Int32 lcl_GetRulerPos( sal_Int32 nApiPos )
+{
+ sal_Int32 nDiv = 10;
+ sal_Int32 nExp = 10;
+ sal_Int32 nRulerPos = 0;
+ sal_Int32 nApiBase = 0;
+ sal_Int32 nApiLimit = 10;
+ while( nApiPos >= nApiLimit )
+ {
+ ++nDiv;
+ nRulerPos = nExp;
+ nExp *= 10;
+ nApiBase = nApiLimit;
+ nApiLimit = lcl_GetApiPos( nExp );
+ }
+ sal_Int32 nRelPos = nApiPos - nApiBase;
+ return nRulerPos + nRelPos / nDiv * 10 + ::std::max<sal_Int32>( nRelPos % nDiv - nDiv + 10, 0 );
+}
+
+/** Expands the sequence's size and returns the base index of the new inserted elements. */
+static sal_Int32 lcl_ExpandSequence( Sequence< PropertyValue >& rSeq, sal_Int32 nExp )
+{
+ OSL_ENSURE( nExp > 0, "lcl_ExpandSequence - invalid value" );
+ rSeq.realloc( rSeq.getLength() + nExp );
+ return rSeq.getLength() - nExp;
+}
+
+/** Fills the property value rVal with the specified name and value from the item. */
+static void lcl_FillProperty( PropertyValue& rVal, const OUString& rPropName, const SfxPoolItem& rItem, sal_uInt8 nMID )
+{
+ rVal.Name = rPropName;
+ rItem.QueryValue( rVal.Value, nMID );
+}
+
+/** Fills the sequence with all font attributes of rFont. */
+static void lcl_FillFontAttributes( Sequence< PropertyValue >& rSeq, const vcl::Font& rFont )
+{
+ SvxFontItem aFontItem( rFont.GetFamilyType(), rFont.GetFamilyName(), rFont.GetStyleName(), rFont.GetPitch(), rFont.GetCharSet(), ATTR_FONT );
+ SvxFontHeightItem aHeightItem( rFont.GetFontSize().Height(), 100, ATTR_FONT_HEIGHT );
+ SvxLanguageItem aLangItem( rFont.GetLanguage(), ATTR_FONT_LANGUAGE );
+
+ sal_Int32 nIndex = lcl_ExpandSequence( rSeq, 7 );
+ auto pSeq = rSeq.getArray();
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontName", aFontItem, MID_FONT_FAMILY_NAME );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontFamily", aFontItem, MID_FONT_FAMILY );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontStyleName", aFontItem, MID_FONT_STYLE_NAME );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontCharSet", aFontItem, MID_FONT_PITCH );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontPitch", aFontItem, MID_FONT_CHAR_SET );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharHeight", aHeightItem, MID_FONTHEIGHT );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharLocale", aLangItem, MID_LANG_LOCALE );
+}
+
+ScAccessibleCsvRuler::ScAccessibleCsvRuler(ScCsvRuler& rRuler)
+ : ScAccessibleCsvControl(rRuler)
+{
+ constructStringBuffer();
+}
+
+ScAccessibleCsvRuler::~ScAccessibleCsvRuler()
+{
+ ensureDisposed();
+}
+
+// XAccessibleComponent -----------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getForeground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetLabelTextColor());
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetFaceColor());
+}
+
+// XAccessibleContext ---------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getAccessibleChildCount()
+{
+ ensureAlive();
+ return 0;
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvRuler::getAccessibleChild( sal_Int32 /* nIndex */ )
+{
+ ensureAlive();
+ throw IndexOutOfBoundsException();
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvRuler::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ rtl::Reference<AccessibleRelationSetHelper> pRelationSet = new AccessibleRelationSetHelper();
+
+ ScCsvRuler& rRuler = implGetRuler();
+ ScCsvTableBox* pTableBox = rRuler.GetTableBox();
+ ScCsvGrid& rGrid = pTableBox->GetGrid();
+
+ css::uno::Reference<css::accessibility::XAccessible> xAccObj(static_cast<ScAccessibleCsvGrid*>(rGrid.GetAccessible()));
+ if( xAccObj.is() )
+ {
+ Sequence< Reference< XInterface > > aSeq{ xAccObj };
+ pRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::CONTROLLER_FOR, aSeq ) );
+ }
+
+ return pRelationSet;
+}
+
+Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvRuler::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = implCreateStateSet();
+ if( isAlive() )
+ {
+ pStateSet->AddState( AccessibleStateType::FOCUSABLE );
+ pStateSet->AddState( AccessibleStateType::SINGLE_LINE );
+ if( implGetRuler().HasFocus() )
+ pStateSet->AddState( AccessibleStateType::FOCUSED );
+ }
+ return pStateSet;
+}
+
+// XAccessibleText ------------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getCaretPosition()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return lcl_GetApiPos( implGetRuler().GetRulerCursorPos() );
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::setCaretPosition( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nIndex );
+ ScCsvRuler& rRuler = implGetRuler();
+ sal_Int32 nOldCursor = rRuler.GetRulerCursorPos();
+ rRuler.Execute( CSVCMD_MOVERULERCURSOR, lcl_GetRulerPos( nIndex ) );
+ return rRuler.GetRulerCursorPos() != nOldCursor;
+}
+
+sal_Unicode SAL_CALL ScAccessibleCsvRuler::getCharacter( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nIndex );
+ return maBuffer[nIndex];
+}
+
+Sequence< PropertyValue > SAL_CALL ScAccessibleCsvRuler::getCharacterAttributes( sal_Int32 nIndex,
+ const css::uno::Sequence< OUString >& /* aRequestedAttributes */ )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+ Sequence< PropertyValue > aSeq;
+ lcl_FillFontAttributes( aSeq, implGetRuler().GetDrawingArea()->get_ref_device().GetFont() );
+ return aSeq;
+}
+
+css::awt::Rectangle SAL_CALL ScAccessibleCsvRuler::getCharacterBounds( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+ ScCsvRuler& rRuler = implGetRuler();
+ Point aPos( rRuler.GetX( lcl_GetRulerPos( nIndex ) ) - rRuler.GetCharWidth() / 2, 0 );
+ css::awt::Rectangle aRect( aPos.X(), aPos.Y(), rRuler.GetCharWidth(), rRuler.GetOutputSizePixel().Height() );
+ // do not return rectangle out of window
+ sal_Int32 nWidth = rRuler.GetOutputSizePixel().Width();
+ if( aRect.X >= nWidth )
+ throw IndexOutOfBoundsException();
+ if( aRect.X + aRect.Width > nWidth )
+ aRect.Width = nWidth - aRect.X;
+ return aRect;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getCharacterCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetTextLength();
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getIndexAtPoint( const css::awt::Point& rPoint )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ScCsvRuler& rRuler = implGetRuler();
+ // use object's coordinate system, convert to API position
+ return lcl_GetApiPos( ::std::clamp( rRuler.GetPosFromX( rPoint.X ), sal_Int32(0), rRuler.GetPosCount() ) );
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getSelectedText()
+{
+ ensureAlive();
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getSelectionStart()
+{
+ ensureAlive();
+ return -1;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getSelectionEnd()
+{
+ ensureAlive();
+ return -1;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::setSelection( sal_Int32 /* nStartIndex */, sal_Int32 /* nEndIndex */ )
+{
+ ensureAlive();
+ return false;
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getText()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return OUString( maBuffer.getStr(), implGetTextLength() );
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidRange( nStartIndex, nEndIndex );
+ return OUString( maBuffer.getStr() + nStartIndex, nEndIndex - nStartIndex );
+}
+
+TextSegment SAL_CALL ScAccessibleCsvRuler::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+
+ TextSegment aResult;
+ aResult.SegmentStart = -1;
+ aResult.SegmentEnd = -1;
+
+ if( (nIndex == implGetTextLength()) && (nTextType != AccessibleTextType::LINE) )
+ return aResult;
+
+ ensureValidIndex( nIndex );
+
+ OUStringBuffer aResultText; // will be assigned to aResult.SegmentText below
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nIndex );
+
+ switch( nTextType )
+ {
+ // single character
+ case AccessibleTextType::CHARACTER:
+ {
+ aResult.SegmentStart = nIndex;
+ aResultText.append(maBuffer[nIndex]);
+ }
+ break;
+
+ // entire number or single dot/line
+ case AccessibleTextType::WORD:
+ case AccessibleTextType::GLYPH:
+ aResult.SegmentStart = nIndex;
+ if( nRulerPos % 10 )
+ aResultText.append(maBuffer[nIndex]);
+ else
+ aResultText.append( nRulerPos ); // string representation of sal_Int32!!!
+ break;
+
+ // entire text
+ case AccessibleTextType::SENTENCE:
+ case AccessibleTextType::PARAGRAPH:
+ case AccessibleTextType::LINE:
+ aResult.SegmentStart = 0;
+ aResultText.append( maBuffer.getStr(), implGetTextLength() );
+ break;
+
+ // equal-formatted text
+ case AccessibleTextType::ATTRIBUTE_RUN:
+ {
+ sal_Int32 nFirstIndex = implGetFirstEqualFormatted( nIndex );
+ sal_Int32 nLastIndex = implGetLastEqualFormatted( nIndex );
+ aResult.SegmentStart = nFirstIndex;
+ aResultText.append( maBuffer.getStr() + nFirstIndex, nLastIndex - nFirstIndex + 1 );
+ }
+ break;
+
+ default:
+ throw RuntimeException();
+ }
+
+ aResult.SegmentText = aResultText.makeStringAndClear();
+ aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
+ return aResult;
+}
+
+TextSegment SAL_CALL ScAccessibleCsvRuler::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+
+ TextSegment aResult;
+ aResult.SegmentStart = -1;
+ aResult.SegmentEnd = -1;
+
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nIndex );
+
+ switch( nTextType )
+ {
+ // single character
+ case AccessibleTextType::CHARACTER:
+ if( nIndex > 0 )
+ aResult = getTextAtIndex( nIndex - 1, nTextType );
+ // else empty
+ break;
+
+ // entire number or single dot/line
+ case AccessibleTextType::WORD:
+ case AccessibleTextType::GLYPH:
+ if( nRulerPos > 0 )
+ aResult = getTextAtIndex( lcl_GetApiPos( nRulerPos - 1 ), nTextType );
+ // else empty
+ break;
+
+ // entire text
+ case AccessibleTextType::SENTENCE:
+ case AccessibleTextType::PARAGRAPH:
+ case AccessibleTextType::LINE:
+ // empty
+ break;
+
+ // equal-formatted text
+ case AccessibleTextType::ATTRIBUTE_RUN:
+ {
+ sal_Int32 nFirstIndex = implGetFirstEqualFormatted( nIndex );
+ if( nFirstIndex > 0 )
+ aResult = getTextAtIndex( nFirstIndex - 1, nTextType );
+ // else empty
+ }
+ break;
+
+ default:
+ throw RuntimeException();
+ }
+ return aResult;
+}
+
+TextSegment SAL_CALL ScAccessibleCsvRuler::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+
+ TextSegment aResult;
+ aResult.SegmentStart = -1;
+ aResult.SegmentEnd = -1;
+
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nIndex );
+ sal_Int32 nLastValid = implGetTextLength();
+
+ switch( nTextType )
+ {
+ // single character
+ case AccessibleTextType::CHARACTER:
+ if( nIndex < nLastValid )
+ aResult = getTextAtIndex( nIndex + 1, nTextType );
+ // else empty
+ break;
+
+ // entire number or single dot/line
+ case AccessibleTextType::WORD:
+ case AccessibleTextType::GLYPH:
+ if( nRulerPos < implGetRuler().GetPosCount() )
+ aResult = getTextAtIndex( lcl_GetApiPos( nRulerPos + 1 ), nTextType );
+ // else empty
+ break;
+
+ // entire text
+ case AccessibleTextType::SENTENCE:
+ case AccessibleTextType::PARAGRAPH:
+ case AccessibleTextType::LINE:
+ // empty
+ break;
+
+ // equal-formatted text
+ case AccessibleTextType::ATTRIBUTE_RUN:
+ {
+ sal_Int32 nLastIndex = implGetLastEqualFormatted( nIndex );
+ if( nLastIndex < nLastValid )
+ aResult = getTextAtIndex( nLastIndex + 1, nTextType );
+ // else empty
+ }
+ break;
+
+ default:
+ throw RuntimeException();
+ }
+ return aResult;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::copyText( sal_Int32 /* nStartIndex */, sal_Int32 /* nEndIndex */ )
+{
+ ensureAlive();
+ return false;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::scrollSubstringTo( sal_Int32 /* nStartIndex */, sal_Int32/* nEndIndex */, AccessibleScrollType /* aScrollType */ )
+{
+ return false;
+}
+
+// XInterface -----------------------------------------------------------------
+
+Any SAL_CALL ScAccessibleCsvRuler::queryInterface( const css::uno::Type& rType )
+{
+ Any aAny( ScAccessibleCsvRulerImpl::queryInterface( rType ) );
+ return aAny.hasValue() ? aAny : ScAccessibleCsvControl::queryInterface( rType );
+}
+
+void SAL_CALL ScAccessibleCsvRuler::acquire() noexcept
+{
+ ScAccessibleCsvControl::acquire();
+}
+
+void SAL_CALL ScAccessibleCsvRuler::release() noexcept
+{
+ ScAccessibleCsvControl::release();
+}
+
+// XTypeProvider --------------------------------------------------------------
+
+Sequence< css::uno::Type > SAL_CALL ScAccessibleCsvRuler::getTypes()
+{
+ return ::comphelper::concatSequences( ScAccessibleCsvControl::getTypes(),
+ Sequence { cppu::UnoType<XAccessibleText>::get() });
+}
+
+Sequence< sal_Int8 > SAL_CALL ScAccessibleCsvRuler::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// events ---------------------------------------------------------------------
+
+void ScAccessibleCsvRuler::SendCaretEvent()
+{
+ sal_Int32 nPos = implGetRuler().GetRulerCursorPos();
+ if (nPos != CSV_POS_INVALID)
+ {
+ Any aOldValue, aNewValue;
+ aNewValue <<= nPos;
+ NotifyAccessibleEvent( AccessibleEventId::CARET_CHANGED, aOldValue, aNewValue );
+ }
+}
+
+// helpers --------------------------------------------------------------------
+
+OUString SAL_CALL ScAccessibleCsvRuler::getAccessibleName()
+{
+ return ScResId( STR_ACC_CSVRULER_NAME );
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getAccessibleDescription()
+{
+ return ScResId( STR_ACC_CSVRULER_DESCR );
+}
+
+void ScAccessibleCsvRuler::ensureValidIndex( sal_Int32 nIndex ) const
+{
+ if( (nIndex < 0) || (nIndex >= implGetTextLength()) )
+ throw IndexOutOfBoundsException();
+}
+
+void ScAccessibleCsvRuler::ensureValidIndexWithEnd( sal_Int32 nIndex ) const
+{
+ if( (nIndex < 0) || (nIndex > implGetTextLength()) )
+ throw IndexOutOfBoundsException();
+}
+
+void ScAccessibleCsvRuler::ensureValidRange( sal_Int32& rnStartIndex, sal_Int32& rnEndIndex ) const
+{
+ if( rnStartIndex > rnEndIndex )
+ ::std::swap( rnStartIndex, rnEndIndex );
+ if( (rnStartIndex < 0) || (rnEndIndex > implGetTextLength()) )
+ throw IndexOutOfBoundsException();
+}
+
+ScCsvRuler& ScAccessibleCsvRuler::implGetRuler() const
+{
+ return static_cast< ScCsvRuler& >( implGetControl() );
+}
+
+void ScAccessibleCsvRuler::constructStringBuffer()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ // extend existing string buffer to new ruler size
+ sal_Int32 nRulerCount = implGetRuler().GetPosCount();
+ sal_Int32 nRulerPos = lcl_GetRulerPos( maBuffer.getLength() );
+ for( ; nRulerPos <= nRulerCount; ++nRulerPos ) // include last position
+ {
+ switch( nRulerPos % 10 )
+ {
+ case 0: maBuffer.append( nRulerPos ); break;
+ case 5: maBuffer.append( cRulerLine ); break;
+ default: maBuffer.append( cRulerDot );
+ }
+ }
+}
+
+sal_Int32 ScAccessibleCsvRuler::implGetTextLength() const
+{
+ return lcl_GetApiPos( implGetRuler().GetPosCount() + 1 );
+}
+
+bool ScAccessibleCsvRuler::implHasSplit( sal_Int32 nApiPos )
+{
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nApiPos );
+ return implGetRuler().HasSplit( nRulerPos ) && (nApiPos == lcl_GetApiPos( nRulerPos ));
+}
+
+sal_Int32 ScAccessibleCsvRuler::implGetFirstEqualFormatted( sal_Int32 nApiPos )
+{
+ bool bSplit = implHasSplit( nApiPos );
+ while( (nApiPos > 0) && (implHasSplit( nApiPos - 1 ) == bSplit) )
+ --nApiPos;
+ return nApiPos;
+}
+
+sal_Int32 ScAccessibleCsvRuler::implGetLastEqualFormatted( sal_Int32 nApiPos )
+{
+ bool bSplit = implHasSplit( nApiPos );
+ sal_Int32 nLength = implGetTextLength();
+ while( (nApiPos < nLength - 1) && (implHasSplit( nApiPos + 1 ) == bSplit) )
+ ++nApiPos;
+ return nApiPos;
+}
+
+css::uno::Reference<css::accessibility::XAccessible> SAL_CALL ScAccessibleCsvRuler::getAccessibleParent()
+{
+ return implGetControl().GetDrawingArea()->get_accessible_parent();
+}
+
+// Grid =======================================================================
+
+/** Converts a grid columnm index to an API column index. */
+static sal_Int32 lcl_GetApiColumn( sal_uInt32 nGridColumn )
+{
+ return (nGridColumn != CSV_COLUMN_HEADER) ? static_cast< sal_Int32 >( nGridColumn + 1 ) : 0;
+}
+
+/** Converts an API columnm index to a ScCsvGrid column index. */
+static sal_uInt32 lcl_GetGridColumn( sal_Int32 nApiColumn )
+{
+ return (nApiColumn > 0) ? static_cast< sal_uInt32 >( nApiColumn - 1 ) : CSV_COLUMN_HEADER;
+}
+
+ScAccessibleCsvGrid::ScAccessibleCsvGrid(ScCsvGrid& rGrid)
+ : ScAccessibleCsvControl(rGrid)
+{
+}
+
+ScAccessibleCsvGrid::~ScAccessibleCsvGrid()
+{
+ ensureDisposed();
+}
+
+void ScAccessibleCsvGrid::disposing()
+{
+ SolarMutexGuard aGuard;
+ for (auto& rEntry : maAccessibleChildren)
+ rEntry.second->dispose();
+ maAccessibleChildren.clear();
+ ScAccessibleCsvControl::disposing();
+}
+
+// XAccessibleComponent -------------------------------------------------------
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleAtPoint( const css::awt::Point& rPoint )
+{
+ Reference< XAccessible > xRet;
+ if( containsPoint( rPoint ) )
+ {
+ SolarMutexGuard aGuard;
+ ensureAlive();
+
+ const ScCsvGrid& rGrid = implGetGrid();
+ // #102679#; use <= instead of <, because the offset is the size and not the point
+ sal_Int32 nColumn = ((rGrid.GetFirstX() <= rPoint.X) && (rPoint.X <= rGrid.GetLastX())) ?
+ lcl_GetApiColumn( rGrid.GetColumnFromX( rPoint.X ) ) : 0;
+ sal_Int32 nRow = (rPoint.Y >= rGrid.GetHdrHeight()) ?
+ (rGrid.GetLineFromY( rPoint.Y ) - rGrid.GetFirstVisLine() + 1) : 0;
+ xRet = getAccessibleCell(nRow, nColumn);
+ }
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getForeground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetButtonTextColor());
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
+}
+
+// XAccessibleContext ---------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetCellCount();
+}
+
+Reference<XAccessible> ScAccessibleCsvGrid::getAccessibleCell(sal_Int32 nRow, sal_Int32 nColumn)
+{
+ sal_Int32 nIndex = implGetIndex(nRow, nColumn);
+
+ XAccessibleSet::iterator aI = maAccessibleChildren.lower_bound(nIndex);
+ if (aI != maAccessibleChildren.end() && !(maAccessibleChildren.key_comp()(nIndex, aI->first)))
+ {
+ // key already exists
+ return aI->second;
+ }
+ // key does not exist
+ rtl::Reference<ScAccessibleCsvCell> xNew = implCreateCellObj(nRow, nColumn);
+ maAccessibleChildren.insert(aI, XAccessibleSet::value_type(nIndex, xNew));
+ return xNew;
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleChild( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nIndex );
+
+ return getAccessibleCell(implGetRow(nIndex), implGetColumn(nIndex));
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvGrid::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ rtl::Reference<AccessibleRelationSetHelper> pRelationSet = new AccessibleRelationSetHelper();
+
+ ScCsvGrid& rGrid = implGetGrid();
+ ScCsvTableBox* pTableBox = rGrid.GetTableBox();
+ ScCsvRuler& rRuler = pTableBox->GetRuler();
+
+ if (rRuler.IsVisible())
+ {
+ css::uno::Reference<css::accessibility::XAccessible> xAccObj(static_cast<ScAccessibleCsvGrid*>(rRuler.GetAccessible()));
+ if( xAccObj.is() )
+ {
+ Sequence< Reference< XInterface > > aSeq{ xAccObj };
+ pRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::CONTROLLED_BY, aSeq ) );
+ }
+ }
+
+ return pRelationSet;
+}
+
+Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvGrid::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = implCreateStateSet();
+ if( isAlive() )
+ {
+ pStateSet->AddState( AccessibleStateType::FOCUSABLE );
+ pStateSet->AddState( AccessibleStateType::MULTI_SELECTABLE );
+ pStateSet->AddState( AccessibleStateType::MANAGES_DESCENDANTS );
+ if( implGetGrid().HasFocus() )
+ pStateSet->AddState( AccessibleStateType::FOCUSED );
+ }
+ else
+ pStateSet->AddState( AccessibleStateType::DEFUNC );
+ return pStateSet;
+}
+
+// XAccessibleTable -----------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRowCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetRowCount();
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetColumnCount();
+}
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleRowDescription( sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( nRow, 0 );
+ return implGetCellText( nRow, 0 );
+}
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnDescription( sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( 0, nColumn );
+ return implGetCellText( 0, nColumn );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return 1;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return 1;
+}
+
+Reference< XAccessibleTable > SAL_CALL ScAccessibleCsvGrid::getAccessibleRowHeaders()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+Reference< XAccessibleTable > SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnHeaders()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+Sequence< sal_Int32 > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleRows()
+{
+ ensureAlive();
+ return Sequence< sal_Int32 >();
+}
+
+Sequence< sal_Int32 > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleColumns()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+
+ ScCsvGrid& rGrid = implGetGrid();
+ Sequence< sal_Int32 > aSeq( implGetColumnCount() );
+ auto pSeq = aSeq.getArray();
+
+ sal_Int32 nSeqIx = 0;
+ sal_uInt32 nColIx = rGrid.GetFirstSelected();
+ for( ; nColIx != CSV_COLUMN_INVALID; ++nSeqIx, nColIx = rGrid.GetNextSelected( nColIx ) )
+ pSeq[ nSeqIx ] = lcl_GetApiColumn( nColIx );
+
+ aSeq.realloc( nSeqIx );
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleRowSelected( sal_Int32 /* nRow */ )
+{
+ ensureAlive();
+ return false;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleColumnSelected( sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nColumn );
+ return implIsColumnSelected( nColumn );
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return getAccessibleCell(nRow, nColumn);
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleCaption()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleSummary()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleSelected( sal_Int32 /* nRow */, sal_Int32 nColumn )
+{
+ return isAccessibleColumnSelected( nColumn );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return implGetIndex( nRow, nColumn );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRow( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ return implGetRow( nChildIndex );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumn( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ return implGetColumn( nChildIndex );
+}
+
+// XAccessibleSelection -------------------------------------------------------
+
+void SAL_CALL ScAccessibleCsvGrid::selectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ sal_Int32 nColumn = implGetColumn( nChildIndex );
+ if( nChildIndex == 0 )
+ implGetGrid().SelectAll();
+ else
+ implSelectColumn( nColumn, true );
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleChildSelected( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ sal_Int32 nColumn = implGetColumn( nChildIndex );
+ return implIsColumnSelected( nColumn );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::clearAccessibleSelection()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ implGetGrid().SelectAll( false );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::selectAllAccessibleChildren()
+{
+ selectAccessibleChild( 0 );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetRowCount() * implGetSelColumnCount();
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ sal_Int32 nColumns = implGetSelColumnCount();
+ if( nColumns == 0 )
+ throw IndexOutOfBoundsException();
+
+ sal_Int32 nRow = nSelectedChildIndex / nColumns;
+ sal_Int32 nColumn = implGetSelColumn( nSelectedChildIndex % nColumns );
+ return getAccessibleCellAt( nRow, nColumn );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::deselectAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ sal_Int32 nColumns = implGetSelColumnCount();
+ if( nColumns == 0 )
+ throw IndexOutOfBoundsException();
+
+ sal_Int32 nColumn = implGetSelColumn( nSelectedChildIndex % nColumns );
+ ensureValidPosition( nSelectedChildIndex / nColumns, nColumn );
+ if( nColumn > 0 )
+ implSelectColumn( nColumn, false );
+}
+
+// XInterface -----------------------------------------------------------------
+
+Any SAL_CALL ScAccessibleCsvGrid::queryInterface( const css::uno::Type& rType )
+{
+ Any aAny( ScAccessibleCsvGridImpl::queryInterface( rType ) );
+ return aAny.hasValue() ? aAny : ScAccessibleCsvControl::queryInterface( rType );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::acquire() noexcept
+{
+ ScAccessibleCsvControl::acquire();
+}
+
+void SAL_CALL ScAccessibleCsvGrid::release() noexcept
+{
+ ScAccessibleCsvControl::release();
+}
+
+// XTypeProvider --------------------------------------------------------------
+
+Sequence< css::uno::Type > SAL_CALL ScAccessibleCsvGrid::getTypes()
+{
+ return ::comphelper::concatSequences( ScAccessibleCsvControl::getTypes(),
+ Sequence {
+ cppu::UnoType<XAccessibleTable>::get(),
+ cppu::UnoType<XAccessibleSelection>::get() });
+}
+
+Sequence< sal_Int8 > SAL_CALL ScAccessibleCsvGrid::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// events ---------------------------------------------------------------------
+
+void ScAccessibleCsvGrid::SendFocusEvent( bool bFocused )
+{
+ ScAccessibleCsvControl::SendFocusEvent( bFocused );
+ Any aOldAny, aNewAny;
+ (bFocused ? aNewAny : aOldAny) <<=
+ getAccessibleCellAt( 0, lcl_GetApiColumn( implGetGrid().GetFocusColumn() ) );
+ NotifyAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny);
+}
+
+void ScAccessibleCsvGrid::SendTableUpdateEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn, bool bAllRows )
+{
+ if( nFirstColumn <= nLastColumn )
+ {
+ AccessibleTableModelChange aModelChange(
+ AccessibleTableModelChangeType::UPDATE, 0, bAllRows ? implGetRowCount() - 1 : 0,
+ lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) );
+ Any aOldAny, aNewAny;
+ aNewAny <<= aModelChange;
+ NotifyAccessibleEvent(AccessibleEventId::TABLE_MODEL_CHANGED, aOldAny, aNewAny);
+ }
+}
+
+void ScAccessibleCsvGrid::SendInsertColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn )
+{
+ if( nFirstColumn <= nLastColumn )
+ {
+ AccessibleTableModelChange aModelChange(
+ AccessibleTableModelChangeType::COLUMNS_INSERTED, -1, -1,
+ lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) );
+ Any aOldAny, aNewAny;
+ aNewAny <<= aModelChange;
+ NotifyAccessibleEvent(AccessibleEventId::TABLE_MODEL_CHANGED, aOldAny, aNewAny);
+ }
+}
+
+void ScAccessibleCsvGrid::SendRemoveColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn )
+{
+ if( nFirstColumn <= nLastColumn )
+ {
+ AccessibleTableModelChange aModelChange(
+ AccessibleTableModelChangeType::COLUMNS_REMOVED, -1, -1,
+ lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) );
+ Any aOldAny, aNewAny;
+ aNewAny <<= aModelChange;
+ NotifyAccessibleEvent(AccessibleEventId::TABLE_MODEL_CHANGED, aOldAny, aNewAny);
+ }
+}
+
+// helpers --------------------------------------------------------------------
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleName()
+{
+ return ScResId( STR_ACC_CSVGRID_NAME );
+}
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleDescription()
+{
+ return ScResId( STR_ACC_CSVGRID_DESCR );
+}
+
+void ScAccessibleCsvGrid::ensureValidIndex( sal_Int32 nIndex ) const
+{
+ if( (nIndex < 0) || (nIndex >= implGetCellCount()) )
+ throw IndexOutOfBoundsException();
+}
+
+void ScAccessibleCsvGrid::ensureValidPosition( sal_Int32 nRow, sal_Int32 nColumn ) const
+{
+ if( (nRow < 0) || (nRow >= implGetRowCount()) || (nColumn < 0) || (nColumn >= implGetColumnCount()) )
+ throw IndexOutOfBoundsException();
+}
+
+ScCsvGrid& ScAccessibleCsvGrid::implGetGrid() const
+{
+ return static_cast< ScCsvGrid& >( implGetControl() );
+}
+
+bool ScAccessibleCsvGrid::implIsColumnSelected( sal_Int32 nColumn ) const
+{
+ return (nColumn > 0) && implGetGrid().IsSelected( lcl_GetGridColumn( nColumn ) );
+}
+
+void ScAccessibleCsvGrid::implSelectColumn( sal_Int32 nColumn, bool bSelect )
+{
+ if( nColumn > 0 )
+ implGetGrid().Select( lcl_GetGridColumn( nColumn ), bSelect );
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetRowCount() const
+{
+ return static_cast< sal_Int32 >( implGetGrid().GetLastVisLine() - implGetGrid().GetFirstVisLine() + 2 );
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetColumnCount() const
+{
+ return static_cast< sal_Int32 >( implGetGrid().GetColumnCount() + 1 );
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetSelColumnCount() const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ sal_Int32 nCount = 0;
+ for( sal_uInt32 nColIx = rGrid.GetFirstSelected(); nColIx != CSV_COLUMN_INVALID; nColIx = rGrid.GetNextSelected( nColIx ) )
+ ++nCount;
+ return nCount;
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetSelColumn( sal_Int32 nSelColumn ) const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ sal_Int32 nColumn = 0;
+ for( sal_uInt32 nColIx = rGrid.GetFirstSelected(); nColIx != CSV_COLUMN_INVALID; nColIx = rGrid.GetNextSelected( nColIx ) )
+ {
+ if( nColumn == nSelColumn )
+ return static_cast< sal_Int32 >( nColIx + 1 );
+ ++nColumn;
+ }
+ return 0;
+}
+
+OUString ScAccessibleCsvGrid::implGetCellText( sal_Int32 nRow, sal_Int32 nColumn ) const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ sal_Int32 nLine = nRow + rGrid.GetFirstVisLine() - 1;
+ OUString aCellStr;
+ if( (nColumn > 0) && (nRow > 0) )
+ aCellStr = rGrid.GetCellText( lcl_GetGridColumn( nColumn ), nLine );
+ else if( nRow > 0 )
+ aCellStr = OUString::number( nLine + 1 );
+ else if( nColumn > 0 )
+ aCellStr = rGrid.GetColumnTypeName( lcl_GetGridColumn( nColumn ) );
+ return aCellStr;
+}
+
+rtl::Reference<ScAccessibleCsvCell> ScAccessibleCsvGrid::implCreateCellObj( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return new ScAccessibleCsvCell(implGetGrid(), implGetCellText(nRow, nColumn), nRow, nColumn);
+}
+
+css::uno::Reference<css::accessibility::XAccessible> SAL_CALL ScAccessibleCsvGrid::getAccessibleParent()
+{
+ return implGetControl().GetDrawingArea()->get_accessible_parent();
+}
+
+ScAccessibleCsvCell::ScAccessibleCsvCell(
+ ScCsvGrid& rGrid,
+ const OUString& rCellText,
+ sal_Int32 nRow, sal_Int32 nColumn ) :
+ ScAccessibleCsvControl( rGrid ),
+ AccessibleStaticTextBase( SvxEditSourcePtr() ),
+ maCellText( rCellText ),
+ mnLine( nRow ? (nRow + rGrid.GetFirstVisLine() - 1) : CSV_LINE_HEADER ),
+ mnColumn( lcl_GetGridColumn( nColumn ) ),
+ mnIndex( nRow * (rGrid.GetColumnCount() + 1) + nColumn )
+{
+ SetEditSource( implCreateEditSource() );
+}
+
+ScAccessibleCsvCell::~ScAccessibleCsvCell()
+{
+}
+
+void SAL_CALL ScAccessibleCsvCell::disposing()
+{
+ SolarMutexGuard aGuard;
+ SetEditSource( SvxEditSourcePtr() );
+ ScAccessibleCsvControl::disposing();
+}
+
+// XAccessibleComponent -------------------------------------------------------
+
+void SAL_CALL ScAccessibleCsvCell::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ScCsvGrid& rGrid = implGetGrid();
+ rGrid.Execute( CSVCMD_MOVEGRIDCURSOR, rGrid.GetColumnPos( mnColumn ) );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getForeground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetButtonTextColor());
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
+}
+
+// XAccessibleContext -----------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getAccessibleChildCount()
+{
+ return AccessibleStaticTextBase::getAccessibleChildCount();
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvCell::getAccessibleChild( sal_Int32 nIndex )
+{
+ return AccessibleStaticTextBase::getAccessibleChild( nIndex );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getAccessibleIndexInParent()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return mnIndex;
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvCell::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return new AccessibleRelationSetHelper();
+}
+
+Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvCell::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = implCreateStateSet();
+ if( isAlive() )
+ {
+ const ScCsvGrid& rGrid = implGetGrid();
+ pStateSet->AddState( AccessibleStateType::SINGLE_LINE );
+ if( mnColumn != CSV_COLUMN_HEADER )
+ pStateSet->AddState( AccessibleStateType::SELECTABLE );
+ if( rGrid.HasFocus() && (rGrid.GetFocusColumn() == mnColumn) && (mnLine == CSV_LINE_HEADER) )
+ pStateSet->AddState( AccessibleStateType::ACTIVE );
+ if( rGrid.IsSelected( mnColumn ) )
+ pStateSet->AddState( AccessibleStateType::SELECTED );
+ }
+ return pStateSet;
+}
+
+// XInterface -----------------------------------------------------------------
+
+IMPLEMENT_FORWARD_XINTERFACE2( ScAccessibleCsvCell, ScAccessibleCsvControl, AccessibleStaticTextBase )
+
+// XTypeProvider --------------------------------------------------------------
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScAccessibleCsvCell, ScAccessibleCsvControl, AccessibleStaticTextBase )
+
+// helpers --------------------------------------------------------------------
+
+OUString SAL_CALL ScAccessibleCsvCell::getAccessibleName()
+{
+ return maCellText;
+}
+
+OUString SAL_CALL ScAccessibleCsvCell::getAccessibleDescription()
+{
+ return OUString();
+}
+
+ScCsvGrid& ScAccessibleCsvCell::implGetGrid() const
+{
+ return static_cast< ScCsvGrid& >( implGetControl() );
+}
+
+Point ScAccessibleCsvCell::implGetRealPos() const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ return Point(
+ (mnColumn == CSV_COLUMN_HEADER) ? rGrid.GetHdrX() : rGrid.GetColumnX( mnColumn ),
+ (mnLine == CSV_LINE_HEADER) ? 0 : rGrid.GetY( mnLine ) );
+}
+
+sal_uInt32 ScAccessibleCsvCell::implCalcPixelWidth(sal_uInt32 nChars) const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ return rGrid.GetCharWidth() * nChars;
+}
+
+Size ScAccessibleCsvCell::implGetRealSize() const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ return Size(
+ (mnColumn == CSV_COLUMN_HEADER) ? rGrid.GetHdrWidth() : implCalcPixelWidth( rGrid.GetColumnWidth( mnColumn ) ),
+ (mnLine == CSV_LINE_HEADER) ? rGrid.GetHdrHeight() : rGrid.GetLineHeight() );
+}
+
+css::awt::Rectangle ScAccessibleCsvCell::implGetBounds()
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ tools::Rectangle aClipRect( Point( 0, 0 ), rGrid.GetOutputSizePixel() );
+ if( mnColumn != CSV_COLUMN_HEADER )
+ {
+ aClipRect.SetLeft( rGrid.GetFirstX() );
+ aClipRect.SetRight( rGrid.GetLastX() );
+ }
+ if( mnLine != CSV_LINE_HEADER )
+ aClipRect.SetTop( rGrid.GetHdrHeight() );
+
+ tools::Rectangle aRect( implGetRealPos(), implGetRealSize() );
+ aRect.Intersection( aClipRect );
+ if( aRect.IsEmpty() )
+ aRect.SetSize( Size( -1, -1 ) );
+
+ return css::awt::Rectangle(aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());
+}
+
+::std::unique_ptr< SvxEditSource > ScAccessibleCsvCell::implCreateEditSource()
+{
+ ScCsvGrid& rGrid = implGetGrid();
+
+ ::std::unique_ptr< SvxEditSource > pEditSource( new ScAccessibilityEditSource( std::make_unique<ScAccessibleCsvTextData>(&rGrid.GetDrawingArea()->get_ref_device(), rGrid.GetEditEngine(), maCellText, implGetRealSize()) ) );
+ return pEditSource;
+}
+
+css::uno::Reference<css::accessibility::XAccessible> SAL_CALL ScAccessibleCsvCell::getAccessibleParent()
+{
+ ScCsvGrid& rGrid = implGetGrid();
+
+ ScAccessibleCsvGrid* pAcc = static_cast<ScAccessibleCsvGrid*>(rGrid.GetAccessible());
+
+ return pAcc;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */