/* -*- 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 "scitems.hxx" #include "AccessiblePreviewTable.hxx" #include "AccessiblePreviewCell.hxx" #include "AccessiblePreviewHeaderCell.hxx" #include "AccessibilityHints.hxx" #include "prevwsh.hxx" #include "miscuno.hxx" #include "prevloc.hxx" #include "attrib.hxx" #include "document.hxx" #include "scresid.hxx" #include "sc.hrc" #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::accessibility; //===== internal ============================================================ ScAccessiblePreviewTable::ScAccessiblePreviewTable( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxParent, ScPreviewShell* pViewShell, sal_Int32 nIndex ) : ScAccessibleContextBase( rxParent, AccessibleRole::TABLE ), mpViewShell( pViewShell ), mnIndex( nIndex ), mpTableInfo( NULL ) { if (mpViewShell) mpViewShell->AddAccessibilityObject(*this); } ScAccessiblePreviewTable::~ScAccessiblePreviewTable() { if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) { // increment refcount to prevent double call off dtor osl_atomic_increment( &m_refCount ); dispose(); } } void SAL_CALL ScAccessiblePreviewTable::disposing() { SolarMutexGuard aGuard; if (mpViewShell) { mpViewShell->RemoveAccessibilityObject(*this); mpViewShell = NULL; } if (mpTableInfo) DELETEZ (mpTableInfo); ScAccessibleContextBase::disposing(); } //===== SfxListener ===================================================== void ScAccessiblePreviewTable::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) { if (rHint.ISA( SfxSimpleHint )) { const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; sal_uLong nId = rRef.GetId(); if ( nId == SFX_HINT_DATACHANGED ) { // column / row layout may change with any document change, // so it must be invalidated DELETEZ( mpTableInfo ); } else if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED) { AccessibleEventObject aEvent; aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; aEvent.Source = uno::Reference< XAccessibleContext >(this); CommitChange(aEvent); } } ScAccessibleContextBase::Notify(rBC, rHint); } //===== XInterface ===================================================== uno::Any SAL_CALL ScAccessiblePreviewTable::queryInterface( uno::Type const & rType ) throw (uno::RuntimeException) { uno::Any aAny (ScAccessiblePreviewTableImpl::queryInterface(rType)); return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType); } void SAL_CALL ScAccessiblePreviewTable::acquire() throw () { ScAccessibleContextBase::acquire(); } void SAL_CALL ScAccessiblePreviewTable::release() throw () { ScAccessibleContextBase::release(); } //===== XAccessibleTable ================================================ sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleRowCount() throw (uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); sal_Int32 nRet = 0; if ( mpTableInfo ) nRet = mpTableInfo->GetRows(); return nRet; } sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnCount() throw (uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); sal_Int32 nRet = 0; if ( mpTableInfo ) nRet = mpTableInfo->GetCols(); return nRet; } OUString SAL_CALL ScAccessiblePreviewTable::getAccessibleRowDescription( sal_Int32 nRow ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; FillTableInfo(); if ( nRow < 0 || (mpTableInfo && nRow >= mpTableInfo->GetRows()) ) throw lang::IndexOutOfBoundsException(); return OUString(); } OUString SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnDescription( sal_Int32 nColumn ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; FillTableInfo(); if ( nColumn < 0 || (mpTableInfo && nColumn >= mpTableInfo->GetCols()) ) throw lang::IndexOutOfBoundsException(); return OUString(); } sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); sal_Int32 nRows = 1; if ( mpViewShell && mpTableInfo && nColumn >= 0 && nRow >= 0 && nColumn < mpTableInfo->GetCols() && nRow < mpTableInfo->GetRows() ) { const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[nColumn]; const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[nRow]; if ( rColInfo.bIsHeader || rRowInfo.bIsHeader ) { // header cells only span a single cell } else { ScDocument* pDoc = mpViewShell->GetDocument(); const ScMergeAttr* pItem = (const ScMergeAttr*)pDoc->GetAttr( static_cast(rColInfo.nDocIndex), static_cast(rRowInfo.nDocIndex), mpTableInfo->GetTab(), ATTR_MERGE ); if ( pItem && pItem->GetRowMerge() > 0 ) nRows = pItem->GetRowMerge(); } } else throw lang::IndexOutOfBoundsException(); return nRows; } sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); sal_Int32 nColumns = 1; if ( mpViewShell && mpTableInfo && nColumn >= 0 && nRow >= 0 && nColumn < mpTableInfo->GetCols() && nRow < mpTableInfo->GetRows() ) { const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[nColumn]; const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[nRow]; if ( rColInfo.bIsHeader || rRowInfo.bIsHeader ) { // header cells only span a single cell } else { ScDocument* pDoc = mpViewShell->GetDocument(); const ScMergeAttr* pItem = (const ScMergeAttr*)pDoc->GetAttr( static_cast(rColInfo.nDocIndex), static_cast(rRowInfo.nDocIndex), mpTableInfo->GetTab(), ATTR_MERGE ); if ( pItem && pItem->GetColMerge() > 0 ) nColumns = pItem->GetColMerge(); } } else throw lang::IndexOutOfBoundsException(); return nColumns; } uno::Reference< XAccessibleTable > SAL_CALL ScAccessiblePreviewTable::getAccessibleRowHeaders() throw (uno::RuntimeException) { //! missing return NULL; } uno::Reference< XAccessibleTable > SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnHeaders() throw (uno::RuntimeException) { //! missing return NULL; } uno::Sequence< sal_Int32 > SAL_CALL ScAccessiblePreviewTable::getSelectedAccessibleRows() throw (uno::RuntimeException) { // in the page preview, there is no selection return uno::Sequence(0); } uno::Sequence< sal_Int32 > SAL_CALL ScAccessiblePreviewTable::getSelectedAccessibleColumns() throw (uno::RuntimeException) { // in the page preview, there is no selection return uno::Sequence(0); } sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleRowSelected( sal_Int32 nRow ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { // in the page preview, there is no selection SolarMutexGuard aGuard; FillTableInfo(); if ( nRow < 0 || (mpTableInfo && nRow >= mpTableInfo->GetRows()) ) throw lang::IndexOutOfBoundsException(); return false; } sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleColumnSelected( sal_Int32 nColumn ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { // in the page preview, there is no selection SolarMutexGuard aGuard; FillTableInfo(); if ( nColumn < 0 || (mpTableInfo && nColumn >= mpTableInfo->GetCols()) ) throw lang::IndexOutOfBoundsException(); return false; } uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); uno::Reference xRet; if ( mpTableInfo && nColumn >= 0 && nRow >= 0 && nColumn < mpTableInfo->GetCols() && nRow < mpTableInfo->GetRows() ) { // index iterates horizontally long nNewIndex = nRow * mpTableInfo->GetCols() + nColumn; const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[nColumn]; const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[nRow]; ScAddress aCellPos( static_cast(rColInfo.nDocIndex), static_cast(rRowInfo.nDocIndex), mpTableInfo->GetTab() ); if ( rColInfo.bIsHeader || rRowInfo.bIsHeader ) { ScAccessiblePreviewHeaderCell* pHeaderCell = new ScAccessiblePreviewHeaderCell( this, mpViewShell, aCellPos, rRowInfo.bIsHeader, rColInfo.bIsHeader, nNewIndex ); xRet = pHeaderCell; pHeaderCell->Init(); } else { ScAccessiblePreviewCell* pCell = new ScAccessiblePreviewCell( this, mpViewShell, aCellPos, nNewIndex ); xRet = pCell; pCell->Init(); } } if ( !xRet.is() ) throw lang::IndexOutOfBoundsException(); return xRet; } uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleCaption() throw (uno::RuntimeException) { //! missing return NULL; } uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleSummary() throw (uno::RuntimeException) { //! missing return NULL; } sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { // in the page preview, there is no selection SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); if ( mpTableInfo && nColumn >= 0 && nRow >= 0 && nColumn < mpTableInfo->GetCols() && nRow < mpTableInfo->GetRows() ) { // index iterates horizontally } else throw lang::IndexOutOfBoundsException(); return false; } sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); sal_Int32 nRet = 0; if ( mpTableInfo && nColumn >= 0 && nRow >= 0 && nColumn < mpTableInfo->GetCols() && nRow < mpTableInfo->GetRows() ) { // index iterates horizontally nRet = nRow * mpTableInfo->GetCols() + nColumn; } else throw lang::IndexOutOfBoundsException(); return nRet; } sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleRow( sal_Int32 nChildIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); sal_Int32 nRow = 0; if ( mpTableInfo && nChildIndex >= 0 && nChildIndex < static_cast(mpTableInfo->GetRows()) * mpTableInfo->GetCols() ) { nRow = nChildIndex / mpTableInfo->GetCols(); } else throw lang::IndexOutOfBoundsException(); return nRow; } sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleColumn( sal_Int32 nChildIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); sal_Int32 nCol = 0; if ( mpTableInfo && nChildIndex >= 0 && nChildIndex < static_cast(mpTableInfo->GetRows()) * mpTableInfo->GetCols() ) { nCol = nChildIndex % static_cast(mpTableInfo->GetCols()); } else throw lang::IndexOutOfBoundsException(); return nCol; } //===== XAccessibleComponent ============================================ uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleAtPoint( const awt::Point& aPoint ) throw (uno::RuntimeException) { uno::Reference xRet; if (containsPoint(aPoint)) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); if ( mpTableInfo ) { SCCOL nCols = mpTableInfo->GetCols(); SCROW nRows = mpTableInfo->GetRows(); const ScPreviewColRowInfo* pColInfo = mpTableInfo->GetColInfo(); const ScPreviewColRowInfo* pRowInfo = mpTableInfo->GetRowInfo(); Rectangle aScreenRect(GetBoundingBox()); awt::Point aMovedPoint = aPoint; aMovedPoint.X += aScreenRect.Left(); aMovedPoint.Y += aScreenRect.Top(); if ( nCols > 0 && nRows > 0 && aMovedPoint.X >= pColInfo[0].nPixelStart && aMovedPoint.Y >= pRowInfo[0].nPixelStart ) { SCCOL nColIndex = 0; while ( nColIndex < nCols && aMovedPoint.X > pColInfo[nColIndex].nPixelEnd ) ++nColIndex; SCROW nRowIndex = 0; while ( nRowIndex < nRows && aMovedPoint.Y > pRowInfo[nRowIndex].nPixelEnd ) ++nRowIndex; if ( nColIndex < nCols && nRowIndex < nRows ) { try { xRet = getAccessibleCellAt( nRowIndex, nColIndex ); } catch (uno::Exception&) { } } } } } return xRet; } void SAL_CALL ScAccessiblePreviewTable::grabFocus() throw (uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); if (getAccessibleParent().is()) { uno::Reference xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); if (xAccessibleComponent.is()) xAccessibleComponent->grabFocus(); } } //===== XAccessibleContext ============================================== sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleChildCount() throw (uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); long nRet = 0; if ( mpTableInfo ) nRet = static_cast(mpTableInfo->GetCols()) * mpTableInfo->GetRows(); return nRet; } uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleChild( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) { SolarMutexGuard aGuard; IsObjectValid(); FillTableInfo(); uno::Reference xRet; if ( mpTableInfo ) { long nColumns = mpTableInfo->GetCols(); if ( nColumns > 0 ) { // nCol, nRow are within the visible table, not the document long nCol = nIndex % nColumns; long nRow = nIndex / nColumns; xRet = getAccessibleCellAt( nRow, nCol ); } } if ( !xRet.is() ) throw lang::IndexOutOfBoundsException(); return xRet; } sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleIndexInParent() throw (uno::RuntimeException) { return mnIndex; } uno::Reference< XAccessibleStateSet > SAL_CALL ScAccessiblePreviewTable::getAccessibleStateSet() throw (uno::RuntimeException) { SolarMutexGuard aGuard; uno::Reference xParentStates; if (getAccessibleParent().is()) { uno::Reference xParentContext = getAccessibleParent()->getAccessibleContext(); xParentStates = xParentContext->getAccessibleStateSet(); } utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); if (IsDefunc(xParentStates)) pStateSet->AddState(AccessibleStateType::DEFUNC); else { pStateSet->AddState(AccessibleStateType::MANAGES_DESCENDANTS); pStateSet->AddState(AccessibleStateType::ENABLED); pStateSet->AddState(AccessibleStateType::OPAQUE); if (isShowing()) pStateSet->AddState(AccessibleStateType::SHOWING); if (isVisible()) pStateSet->AddState(AccessibleStateType::VISIBLE); } return pStateSet; } //===== XServiceInfo ==================================================== OUString SAL_CALL ScAccessiblePreviewTable::getImplementationName() throw(uno::RuntimeException) { return OUString("ScAccessiblePreviewTable"); } uno::Sequence SAL_CALL ScAccessiblePreviewTable::getSupportedServiceNames() throw(uno::RuntimeException) { uno::Sequence< OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); sal_Int32 nOldSize(aSequence.getLength()); aSequence.realloc(nOldSize + 1); OUString* pNames = aSequence.getArray(); pNames[nOldSize] = OUString("com.sun.star.table.AccessibleTableView"); return aSequence; } //===== XTypeProvider =================================================== uno::Sequence< uno::Type > SAL_CALL ScAccessiblePreviewTable::getTypes() throw (uno::RuntimeException) { return comphelper::concatSequences(ScAccessiblePreviewTableImpl::getTypes(), ScAccessibleContextBase::getTypes()); } namespace { class theScAccessiblePreviewTableImplementationId : public rtl::Static< UnoTunnelIdInit, theScAccessiblePreviewTableImplementationId > {}; } uno::Sequence SAL_CALL ScAccessiblePreviewTable::getImplementationId() throw(uno::RuntimeException) { return theScAccessiblePreviewTableImplementationId::get().getSeq(); } //==== internal ========================================================= OUString SAL_CALL ScAccessiblePreviewTable::createAccessibleDescription(void) throw (uno::RuntimeException) { String sDesc(ScResId(STR_ACC_TABLE_DESCR)); return OUString(sDesc); } OUString SAL_CALL ScAccessiblePreviewTable::createAccessibleName(void) throw (uno::RuntimeException) { String sName(ScResId(STR_ACC_TABLE_NAME)); if (mpViewShell && mpViewShell->GetDocument()) { FillTableInfo(); if ( mpTableInfo ) { OUString sCoreName; if (mpViewShell->GetDocument()->GetName( mpTableInfo->GetTab(), sCoreName )) sName.SearchAndReplaceAscii("%1", sCoreName); } } return OUString(sName); } Rectangle ScAccessiblePreviewTable::GetBoundingBoxOnScreen() const throw (uno::RuntimeException) { Rectangle aCellRect(GetBoundingBox()); if (mpViewShell) { Window* pWindow = mpViewShell->GetWindow(); if (pWindow) { Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL); aCellRect.setX(aCellRect.getX() + aRect.getX()); aCellRect.setY(aCellRect.getY() + aRect.getY()); } } return aCellRect; } Rectangle ScAccessiblePreviewTable::GetBoundingBox() const throw (uno::RuntimeException) { FillTableInfo(); Rectangle aRect; if ( mpTableInfo ) { SCCOL nColumns = mpTableInfo->GetCols(); SCROW nRows = mpTableInfo->GetRows(); if ( nColumns > 0 && nRows > 0 ) { const ScPreviewColRowInfo* pColInfo = mpTableInfo->GetColInfo(); const ScPreviewColRowInfo* pRowInfo = mpTableInfo->GetRowInfo(); aRect = Rectangle( pColInfo[0].nPixelStart, pRowInfo[0].nPixelStart, pColInfo[nColumns-1].nPixelEnd, pRowInfo[nRows-1].nPixelEnd ); } } return aRect; } sal_Bool ScAccessiblePreviewTable::IsDefunc( const uno::Reference& rxParentStates ) { return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() || (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); } void ScAccessiblePreviewTable::FillTableInfo() const { if ( mpViewShell && !mpTableInfo ) { Size aOutputSize; Window* pWindow = mpViewShell->GetWindow(); if ( pWindow ) aOutputSize = pWindow->GetOutputSizePixel(); Point aPoint; Rectangle aVisRect( aPoint, aOutputSize ); mpTableInfo = new ScPreviewTableInfo; mpViewShell->GetLocationData().GetTableInfo( aVisRect, *mpTableInfo ); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */