diff options
Diffstat (limited to 'sc/source/ui/Accessibility')
24 files changed, 15149 insertions, 0 deletions
diff --git a/sc/source/ui/Accessibility/AccessibilityHints.cxx b/sc/source/ui/Accessibility/AccessibilityHints.cxx new file mode 100644 index 000000000000..6c276b806e88 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibilityHints.cxx @@ -0,0 +1,112 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +#include "AccessibilityHints.hxx" + +using namespace ::com::sun::star; + +// ----------------------------------------------------------------------- + +TYPEINIT1(ScAccWinFocusLostHint, SfxHint); + +// ----------------------------------------------------------------------- +// ScAccWinFocusLostHint - the current window lost its focus (to another application, view or document) +// ----------------------------------------------------------------------- + +ScAccWinFocusLostHint::ScAccWinFocusLostHint( + const uno::Reference< uno::XInterface >& xOld ) + : + xOldAccessible(xOld) +{ +} + +ScAccWinFocusLostHint::~ScAccWinFocusLostHint() +{ +} + +// ----------------------------------------------------------------------- + +TYPEINIT1(ScAccWinFocusGotHint, SfxHint); + +// ----------------------------------------------------------------------- +// ScAccWinFocusGotHint - the window got the focus (from another application, view or document) +// ----------------------------------------------------------------------- + +ScAccWinFocusGotHint::ScAccWinFocusGotHint( + const uno::Reference< uno::XInterface >& xNew ) + : + xNewAccessible(xNew) +{ +} + +ScAccWinFocusGotHint::~ScAccWinFocusGotHint() +{ +} +// ----------------------------------------------------------------------- + +TYPEINIT1(ScAccGridWinFocusLostHint, SfxHint); + +// ----------------------------------------------------------------------- +// ScAccGridWinFocusLostHint - the current grid window lost its focus (to another application, view or document) +// ----------------------------------------------------------------------- + +ScAccGridWinFocusLostHint::ScAccGridWinFocusLostHint(ScSplitPos eOld, + const uno::Reference< uno::XInterface >& xOld ) + : + ScAccWinFocusLostHint(xOld), + eOldGridWin(eOld) +{ +} + +ScAccGridWinFocusLostHint::~ScAccGridWinFocusLostHint() +{ +} + +// ----------------------------------------------------------------------- + +TYPEINIT1(ScAccGridWinFocusGotHint, SfxHint); + +// ----------------------------------------------------------------------- +// ScAccGridWinFocusGotHint - the grid window got the focus (from another application, view or document) +// ----------------------------------------------------------------------- + +ScAccGridWinFocusGotHint::ScAccGridWinFocusGotHint(ScSplitPos eNew, + const uno::Reference< uno::XInterface >& xNew ) + : + ScAccWinFocusGotHint(xNew), + eNewGridWin(eNew) +{ +} + +ScAccGridWinFocusGotHint::~ScAccGridWinFocusGotHint() +{ +} diff --git a/sc/source/ui/Accessibility/AccessibleCell.cxx b/sc/source/ui/Accessibility/AccessibleCell.cxx new file mode 100644 index 000000000000..434ea2dea40c --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleCell.cxx @@ -0,0 +1,459 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include "AccessibleCell.hxx" +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + + +#include "AccessibleText.hxx" +#include "AccessibleDocument.hxx" +#include "tabvwsh.hxx" +#include "document.hxx" +#include "attrib.hxx" +#include "miscuno.hxx" +#include "unoguard.hxx" +#include "editsrc.hxx" +#include "dociter.hxx" +#include "cell.hxx" + +#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX +#include <unotools/accessiblestatesethelper.hxx> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/accessibility/XAccessibleTable.hpp> +#include <rtl/uuid.h> +#include <tools/debug.hxx> +#include <editeng/brshitem.hxx> +#include <comphelper/sequence.hxx> +#include <float.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +ScAccessibleCell::ScAccessibleCell( + const uno::Reference<XAccessible>& rxParent, + ScTabViewShell* pViewShell, + ScAddress& rCellAddress, + sal_Int32 nIndex, + ScSplitPos eSplitPos, + ScAccessibleDocument* pAccDoc) + : + ScAccessibleCellBase(rxParent, GetDocument(pViewShell), rCellAddress, nIndex), + ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell, rCellAddress, eSplitPos)), + mpViewShell(pViewShell), + mpAccDoc(pAccDoc), + meSplitPos(eSplitPos) +{ + if (pViewShell) + pViewShell->AddAccessibilityObject(*this); +} + +ScAccessibleCell::~ScAccessibleCell() +{ + if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + // call dispose to inform object wich have a weak reference to this object + dispose(); + } +} + +void ScAccessibleCell::Init() +{ + ScAccessibleCellBase::Init(); + + SetEventSource(this); +} + +void SAL_CALL ScAccessibleCell::disposing() +{ + ScUnoGuard aGuard; + // #100593# dispose in AccessibleStaticTextBase + Dispose(); + + if (mpViewShell) + { + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + mpAccDoc = NULL; + + ScAccessibleCellBase::disposing(); +} + + //===== XInterface ===================================================== + +IMPLEMENT_FORWARD_XINTERFACE2( ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase ) + + //===== XTypeProvider =================================================== + +IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase ) + + //===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessibleCell::getAccessibleAtPoint( + const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + return AccessibleStaticTextBase::getAccessibleAtPoint(rPoint); +} + +void SAL_CALL ScAccessibleCell::grabFocus( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (getAccessibleParent().is() && mpViewShell) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + { + xAccessibleComponent->grabFocus(); + mpViewShell->SetCursor(maCellAddress.Col(), maCellAddress.Row()); + } + } +} + +Rectangle ScAccessibleCell::GetBoundingBoxOnScreen(void) const + throw (uno::RuntimeException) +{ + Rectangle aCellRect(GetBoundingBox()); + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + { + Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL); + aCellRect.setX(aCellRect.getX() + aRect.getX()); + aCellRect.setY(aCellRect.getY() + aRect.getY()); + } + } + return aCellRect; +} + +Rectangle ScAccessibleCell::GetBoundingBox(void) const + throw (uno::RuntimeException) +{ + Rectangle aCellRect; + if (mpViewShell) + { + long nSizeX, nSizeY; + mpViewShell->GetViewData()->GetMergeSizePixel( + maCellAddress.Col(), maCellAddress.Row(), nSizeX, nSizeY); + aCellRect.SetSize(Size(nSizeX, nSizeY)); + aCellRect.SetPos(mpViewShell->GetViewData()->GetScrPos(maCellAddress.Col(), maCellAddress.Row(), meSplitPos, TRUE)); + + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + { + Rectangle aRect(pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow())); + aRect.Move(-aRect.Left(), -aRect.Top()); + aCellRect = aRect.Intersection(aCellRect); + } + + /* #i19430# Gnopernicus reads text partly if it sticks out of the cell + boundaries. This leads to wrong results in cases where the cell + text is rotated, because rotation is not taken into account when + calculating the visible part of the text. In these cases we will + simply expand the cell size to the width of the unrotated text. */ + if (mpDoc) + { + const SfxInt32Item* pItem = static_cast< const SfxInt32Item* >( + mpDoc->GetAttr( maCellAddress.Col(), maCellAddress.Row(), maCellAddress.Tab(), ATTR_ROTATE_VALUE ) ); + if( pItem && (pItem->GetValue() != 0) ) + { + Rectangle aParaRect = GetParagraphBoundingBox(); + if( !aParaRect.IsEmpty() && (aCellRect.GetWidth() < aParaRect.GetWidth()) ) + aCellRect.SetSize( Size( aParaRect.GetWidth(), aCellRect.GetHeight() ) ); + } + } + } + if (aCellRect.IsEmpty()) + aCellRect.SetPos(Point(-1, -1)); + return aCellRect; +} + + //===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL + ScAccessibleCell::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + return AccessibleStaticTextBase::getAccessibleChildCount(); +} + +uno::Reference< XAccessible > SAL_CALL + ScAccessibleCell::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, + lang::IndexOutOfBoundsException) +{ + return AccessibleStaticTextBase::getAccessibleChild(nIndex); +} + +uno::Reference<XAccessibleStateSet> SAL_CALL + ScAccessibleCell::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc(xParentStates)) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + if (IsEditable(xParentStates)) + { + pStateSet->AddState(AccessibleStateType::EDITABLE); + pStateSet->AddState(AccessibleStateType::RESIZABLE); + } + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::MULTI_LINE); + pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE); + if (IsOpaque(xParentStates)) + pStateSet->AddState(AccessibleStateType::OPAQUE); + pStateSet->AddState(AccessibleStateType::SELECTABLE); + if (IsSelected()) + pStateSet->AddState(AccessibleStateType::SELECTED); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + pStateSet->AddState(AccessibleStateType::TRANSIENT); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + +uno::Reference<XAccessibleRelationSet> SAL_CALL + ScAccessibleCell::getAccessibleRelationSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + utl::AccessibleRelationSetHelper* pRelationSet = NULL; + if (mpAccDoc) + pRelationSet = mpAccDoc->GetRelationSet(&maCellAddress); + if (!pRelationSet) + pRelationSet = new utl::AccessibleRelationSetHelper(); + FillDependends(pRelationSet); + FillPrecedents(pRelationSet); + return pRelationSet; +} + + //===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleCell::getImplementationName(void) + throw (uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleCell")); +} + +uno::Sequence< ::rtl::OUString> SAL_CALL + ScAccessibleCell::getSupportedServiceNames(void) + throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.AccessibleCell")); + + return aSequence; +} + + //==== internal ========================================================= + +sal_Bool ScAccessibleCell::IsDefunc( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + return ScAccessibleContextBase::IsDefunc() || (mpDoc == NULL) || (mpViewShell == NULL) || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +sal_Bool ScAccessibleCell::IsEditable( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + sal_Bool bEditable(sal_True); + if (rxParentStates.is() && !rxParentStates->contains(AccessibleStateType::EDITABLE) && + mpDoc) + { + // here I have to test whether the protection of the table should influence this cell. + const ScProtectionAttr* pItem = (const ScProtectionAttr*)mpDoc->GetAttr( + maCellAddress.Col(), maCellAddress.Row(), + maCellAddress.Tab(), ATTR_PROTECTION); + if (pItem) + bEditable = !pItem->GetProtection(); + } + return bEditable; +} + +sal_Bool ScAccessibleCell::IsOpaque( + const uno::Reference<XAccessibleStateSet>& /* rxParentStates */) +{ + // test whether there is a background color + sal_Bool bOpaque(sal_True); + if (mpDoc) + { + const SvxBrushItem* pItem = (const SvxBrushItem*)mpDoc->GetAttr( + maCellAddress.Col(), maCellAddress.Row(), + maCellAddress.Tab(), ATTR_BACKGROUND); + if (pItem) + bOpaque = pItem->GetColor() != COL_TRANSPARENT; + } + return bOpaque; +} + +sal_Bool ScAccessibleCell::IsSelected() +{ + sal_Bool bResult(sal_False); + if (mpViewShell && mpViewShell->GetViewData()) + { + const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData(); + bResult = rMarkdata.IsCellMarked(maCellAddress.Col(), maCellAddress.Row()); + } + return bResult; +} + +ScDocument* ScAccessibleCell::GetDocument(ScTabViewShell* pViewShell) +{ + ScDocument* pDoc = NULL; + if (pViewShell && pViewShell->GetViewData()) + pDoc = pViewShell->GetViewData()->GetDocument(); + return pDoc; +} + +::std::auto_ptr< SvxEditSource > ScAccessibleCell::CreateEditSource(ScTabViewShell* pViewShell, ScAddress aCell, ScSplitPos eSplitPos) +{ + ::std::auto_ptr < ScAccessibleTextData > pAccessibleCellTextData + ( new ScAccessibleCellTextData( pViewShell, aCell, eSplitPos, this ) ); + ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleCellTextData)); + + return pEditSource; +} + +void ScAccessibleCell::FillDependends(utl::AccessibleRelationSetHelper* pRelationSet) +{ + if (mpDoc) + { + ScCellIterator aCellIter( mpDoc, 0,0, maCellAddress.Tab(), MAXCOL,MAXROW, maCellAddress.Tab() ); + ScBaseCell* pCell = aCellIter.GetFirst(); + while (pCell) + { + if (pCell->GetCellType() == CELLTYPE_FORMULA) + { + sal_Bool bFound(sal_False); + ScDetectiveRefIter aIter( (ScFormulaCell*) pCell ); + ScRange aRef; + while ( !bFound && aIter.GetNextRef( aRef ) ) + { + if (aRef.In(maCellAddress)) + bFound = sal_True; + } + if (bFound) + AddRelation(ScAddress(aCellIter.GetCol(), aCellIter.GetRow(), aCellIter.GetTab()), AccessibleRelationType::CONTROLLER_FOR, pRelationSet); + } + pCell = aCellIter.GetNext(); + } + } +} + +void ScAccessibleCell::FillPrecedents(utl::AccessibleRelationSetHelper* pRelationSet) +{ + if (mpDoc) + { + ScBaseCell* pBaseCell = mpDoc->GetCell(maCellAddress); + if (pBaseCell && (pBaseCell->GetCellType() == CELLTYPE_FORMULA)) + { + ScFormulaCell* pFCell = (ScFormulaCell*) pBaseCell; + + ScDetectiveRefIter aIter( pFCell ); + ScRange aRef; + while ( aIter.GetNextRef( aRef ) ) + { + AddRelation( aRef, AccessibleRelationType::CONTROLLED_BY, pRelationSet); + } + } + } +} + +void ScAccessibleCell::AddRelation(const ScAddress& rCell, + const sal_uInt16 aRelationType, + utl::AccessibleRelationSetHelper* pRelationSet) +{ + AddRelation(ScRange(rCell, rCell), aRelationType, pRelationSet); +} + +void ScAccessibleCell::AddRelation(const ScRange& rRange, + const sal_uInt16 aRelationType, + utl::AccessibleRelationSetHelper* pRelationSet) +{ + uno::Reference < XAccessibleTable > xTable ( getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY ); + if (xTable.is()) + { + sal_uInt32 nCount(static_cast<sal_uInt32>(rRange.aEnd.Col() - + rRange.aStart.Col() + 1) * (rRange.aEnd.Row() - + rRange.aStart.Row() + 1)); + uno::Sequence < uno::Reference < uno::XInterface > > aTargetSet( nCount ); + uno::Reference < uno::XInterface >* pTargetSet = aTargetSet.getArray(); + if (pTargetSet) + { + sal_uInt32 nPos(0); + for (sal_uInt32 nRow = rRange.aStart.Row(); nRow <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Row()); ++nRow) + { + for (sal_uInt32 nCol = rRange.aStart.Col(); nCol <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Col()); ++nCol) + { + pTargetSet[nPos] = xTable->getAccessibleCellAt(nRow, nCol); + ++nPos; + } + } + DBG_ASSERT(nCount == nPos, "something wents wrong"); + } + AccessibleRelation aRelation; + aRelation.RelationType = aRelationType; + aRelation.TargetSet = aTargetSet; + pRelationSet->AddRelation(aRelation); + } +} diff --git a/sc/source/ui/Accessibility/AccessibleCellBase.cxx b/sc/source/ui/Accessibility/AccessibleCellBase.cxx new file mode 100644 index 000000000000..cc93d0a93350 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleCellBase.cxx @@ -0,0 +1,345 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include "AccessibleCellBase.hxx" +#include "attrib.hxx" +#include "scitems.hxx" +#include "miscuno.hxx" +#include "document.hxx" +#include "docfunc.hxx" +#include "cell.hxx" +#include "unoguard.hxx" +#include "scresid.hxx" +#ifndef SC_SC_HRC +#include "sc.hrc" +#endif +#include "unonames.hxx" + +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <tools/debug.hxx> +#include <editeng/brshitem.hxx> +#include <rtl/uuid.h> +#include <comphelper/sequence.hxx> +#include <sfx2/objsh.hxx> + +#include <float.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +ScAccessibleCellBase::ScAccessibleCellBase( + const uno::Reference<XAccessible>& rxParent, + ScDocument* pDoc, + const ScAddress& rCellAddress, + sal_Int32 nIndex) + : + ScAccessibleContextBase(rxParent, AccessibleRole::TABLE_CELL), + maCellAddress(rCellAddress), + mpDoc(pDoc), + mnIndex(nIndex) +{ +} + +ScAccessibleCellBase::~ScAccessibleCellBase() +{ +} + + //===== XAccessibleComponent ============================================ + +sal_Bool SAL_CALL ScAccessibleCellBase::isVisible( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + // test whether the cell is hidden (column/row - hidden/filtered) + sal_Bool bVisible(sal_True); + if (mpDoc) + { + bool bColHidden = mpDoc->ColHidden(maCellAddress.Col(), maCellAddress.Tab()); + bool bRowHidden = mpDoc->RowHidden(maCellAddress.Row(), maCellAddress.Tab()); + bool bColFiltered = mpDoc->ColFiltered(maCellAddress.Col(), maCellAddress.Tab()); + bool bRowFiltered = mpDoc->RowFiltered(maCellAddress.Row(), maCellAddress.Tab()); + + if (bColHidden || bColFiltered || bRowHidden || bRowFiltered) + bVisible = sal_False; + } + return bVisible; +} + +sal_Int32 SAL_CALL ScAccessibleCellBase::getForeground() + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nColor(0); + if (mpDoc) + { + SfxObjectShell* pObjSh = mpDoc->GetDocumentShell(); + if ( pObjSh ) + { + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY ); + if ( xSpreadDoc.is() ) + { + uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets(); + uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY ); + if ( xIndex.is() ) + { + uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab()); + uno::Reference<sheet::XSpreadsheet> xTable; + if (aTable>>=xTable) + { + uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row()); + if (xCell.is()) + { + uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY); + if (xCellProps.is()) + { + uno::Any aAny = xCellProps->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CCOLOR))); + aAny >>= nColor; + } + } + } + } + } + } + } + return nColor; +} + +sal_Int32 SAL_CALL ScAccessibleCellBase::getBackground() + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nColor(0); + + if (mpDoc) + { + SfxObjectShell* pObjSh = mpDoc->GetDocumentShell(); + if ( pObjSh ) + { + uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY ); + if ( xSpreadDoc.is() ) + { + uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets(); + uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY ); + if ( xIndex.is() ) + { + uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab()); + uno::Reference<sheet::XSpreadsheet> xTable; + if (aTable>>=xTable) + { + uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row()); + if (xCell.is()) + { + uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY); + if (xCellProps.is()) + { + uno::Any aAny = xCellProps->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CELLBACK))); + aAny >>= nColor; + } + } + } + } + } + } + } + + return nColor; +} + + //===== XInterface ===================================================== + +uno::Any SAL_CALL ScAccessibleCellBase::queryInterface( uno::Type const & rType ) + throw (uno::RuntimeException) +{ + uno::Any aAny (ScAccessibleCellBaseImpl::queryInterface(rType)); + return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType); +} + +void SAL_CALL ScAccessibleCellBase::acquire() + throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessibleCellBase::release() + throw () +{ + ScAccessibleContextBase::release(); +} + + //===== XAccessibleContext ============================================== + +sal_Int32 + ScAccessibleCellBase::getAccessibleIndexInParent(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return mnIndex; +} + +::rtl::OUString SAL_CALL + ScAccessibleCellBase::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + rtl::OUString sDescription = String(ScResId(STR_ACC_CELL_DESCR)); + + return sDescription; +} + +::rtl::OUString SAL_CALL + ScAccessibleCellBase::createAccessibleName(void) + throw (uno::RuntimeException) +{ + String sName( ScResId(STR_ACC_CELL_NAME) ); + String sAddress; + // Document not needed, because only the cell address, but not the tablename is needed + // always us OOO notation + maCellAddress.Format( sAddress, SCA_VALID, NULL ); + sName.SearchAndReplaceAscii("%1", sAddress); + /* #i65103# ZoomText merges cell address and contents, e.g. if value 2 is + contained in cell A1, ZT reads "cell A twelve" instead of "cell A1 - 2". + Simple solution: Append a space character to the cell address. */ + sName.Append( ' ' ); + return rtl::OUString(sName); +} + + //===== XAccessibleValue ================================================ + +uno::Any SAL_CALL + ScAccessibleCellBase::getCurrentValue( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Any aAny; + if (mpDoc) + aAny <<= mpDoc->GetValue(maCellAddress); + + return aAny; +} + +sal_Bool SAL_CALL + ScAccessibleCellBase::setCurrentValue( const uno::Any& aNumber ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + double fValue = 0; + sal_Bool bResult(sal_False); + if((aNumber >>= fValue) && mpDoc && mpDoc->GetDocumentShell()) + { + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + if (IsEditable(xParentStates)) + { + ScDocShell* pDocShell = (ScDocShell*) mpDoc->GetDocumentShell(); + ScDocFunc aFunc(*pDocShell); + bResult = aFunc.PutCell( maCellAddress, new ScValueCell(fValue), TRUE ); + } + } + return bResult; +} + +uno::Any SAL_CALL + ScAccessibleCellBase::getMaximumValue( ) + throw (uno::RuntimeException) +{ + uno::Any aAny; + aAny <<= DBL_MAX; + + return aAny; +} + +uno::Any SAL_CALL + ScAccessibleCellBase::getMinimumValue( ) + throw (uno::RuntimeException) +{ + uno::Any aAny; + aAny <<= -DBL_MAX; + + return aAny; +} + + //===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleCellBase::getImplementationName(void) + throw (uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleCellBase")); +} + + //===== XTypeProvider =================================================== + +uno::Sequence< uno::Type > SAL_CALL ScAccessibleCellBase::getTypes() + throw (uno::RuntimeException) +{ + return comphelper::concatSequences(ScAccessibleCellBaseImpl::getTypes(), ScAccessibleContextBase::getTypes()); +} + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessibleCellBase::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +sal_Bool ScAccessibleCellBase::IsEditable( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + sal_Bool bEditable(sal_False); + if (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::EDITABLE)) + bEditable = sal_True; + return bEditable; +} diff --git a/sc/source/ui/Accessibility/AccessibleContextBase.cxx b/sc/source/ui/Accessibility/AccessibleContextBase.cxx new file mode 100644 index 000000000000..0f1fcfa337a5 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleContextBase.cxx @@ -0,0 +1,628 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include "AccessibleContextBase.hxx" +#include "unoguard.hxx" +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <rtl/uuid.h> +#include <tools/debug.hxx> +#include <tools/gen.hxx> +#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX +#include <unotools/accessiblestatesethelper.hxx> +#endif +#include <toolkit/helper/convert.hxx> +#include <svl/smplhint.hxx> +#include <comphelper/sequence.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <vcl/unohelp.hxx> +#include <tools/color.hxx> +#include <comphelper/accessibleeventnotifier.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +DBG_NAME(ScAccessibleContextBase) + +ScAccessibleContextBase::ScAccessibleContextBase( + const uno::Reference<XAccessible>& rxParent, + const sal_Int16 aRole) + : + ScAccessibleContextBaseWeakImpl(m_aMutex), + mxParent(rxParent), + mnClientId(0), + maRole(aRole) +{ + DBG_CTOR(ScAccessibleContextBase, NULL); +} + + +ScAccessibleContextBase::~ScAccessibleContextBase(void) +{ + DBG_DTOR(ScAccessibleContextBase, NULL); + + if (!IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + // call dispose to inform object wich have a weak reference to this object + dispose(); + } +} + +void ScAccessibleContextBase::Init() +{ + // hold reference to make sure that the destructor is not called + uno::Reference< XAccessibleContext > xOwnContext(this); + + if (mxParent.is()) + { + uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addEventListener(this); + } + msName = createAccessibleName(); + msDescription = createAccessibleDescription(); +} + +void SAL_CALL ScAccessibleContextBase::disposing() +{ + ScUnoGuard aGuard; +// CommitDefunc(); not necessary and should not be send, because it cost a lot of time + + // hold reference to make sure that the destructor is not called + uno::Reference< XAccessibleContext > xOwnContext(this); + + if ( mnClientId ) + { + sal_Int32 nTemClientId(mnClientId); + mnClientId = 0; + comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId, *this ); + } + + if (mxParent.is()) + { + uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeEventListener(this); + mxParent = NULL; + } + + ScAccessibleContextBaseWeakImpl::disposing(); +} + +//===== XInterface ===================================================== + +uno::Any SAL_CALL ScAccessibleContextBase::queryInterface( uno::Type const & rType ) + throw (uno::RuntimeException) +{ + uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType)); + return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType); +} + +void SAL_CALL ScAccessibleContextBase::acquire() + throw () +{ + ScAccessibleContextBaseWeakImpl::acquire(); +} + +void SAL_CALL ScAccessibleContextBase::release() + throw () +{ + ScAccessibleContextBaseWeakImpl::release(); +} + +//===== SfxListener ===================================================== + +void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if (rHint.ISA( SfxSimpleHint ) ) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + if (rRef.GetId() == SFX_HINT_DYING) + { + // it seems the Broadcaster is dying, since the view is dying + dispose(); + } + } +} + +//===== XAccessible ========================================================= + +uno::Reference< XAccessibleContext> SAL_CALL + ScAccessibleContextBase::getAccessibleContext(void) + throw (uno::RuntimeException) +{ + return this; +} + +//===== XAccessibleComponent ================================================ + +sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return Rectangle (Point(), GetBoundingBox().GetSize()).IsInside(VCLPoint(rPoint)); +} + +uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint( + const awt::Point& /* rPoint */ ) + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented"); + return uno::Reference<XAccessible>(); +} + +awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return AWTRectangle(GetBoundingBox()); +} + +awt::Point SAL_CALL ScAccessibleContextBase::getLocation( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return AWTPoint(GetBoundingBox().TopLeft()); +} + +awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return AWTPoint(GetBoundingBoxOnScreen().TopLeft()); +} + +awt::Size SAL_CALL ScAccessibleContextBase::getSize( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return AWTSize(GetBoundingBox().GetSize()); +} + +sal_Bool SAL_CALL ScAccessibleContextBase::isShowing( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Bool bShowing(sal_False); + if (mxParent.is()) + { + uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY); + if (xParentComponent.is()) + { + Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds())); + Rectangle aBounds(VCLRectangle(getBounds())); + bShowing = aBounds.IsOver(aParentBounds); + } + } + return bShowing; +} + +sal_Bool SAL_CALL ScAccessibleContextBase::isVisible( ) + throw (uno::RuntimeException) +{ + return sal_True; +} + +void SAL_CALL ScAccessibleContextBase::grabFocus( ) + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented"); +} + +sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( ) + throw (uno::RuntimeException) +{ + return COL_BLACK; +} + +sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( ) + throw (uno::RuntimeException) +{ + return COL_WHITE; +} + +//===== XAccessibleContext ================================================== + +sal_Int32 SAL_CALL + ScAccessibleContextBase::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + DBG_ERROR("should be implemented in the abrevated class"); + return 0; +} + +uno::Reference<XAccessible> SAL_CALL + ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + DBG_ERROR("should be implemented in the abrevated class"); + return uno::Reference<XAccessible>(); +} + +uno::Reference<XAccessible> SAL_CALL + ScAccessibleContextBase::getAccessibleParent(void) + throw (uno::RuntimeException) +{ + return mxParent; +} + +sal_Int32 SAL_CALL + ScAccessibleContextBase::getAccessibleIndexInParent(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + // Use a simple but slow solution for now. Optimize later. + // Return -1 to indicate that this object's parent does not know about the + // object. + sal_Int32 nIndex(-1); + + // Iterate over all the parent's children and search for this object. + if (mxParent.is()) + { + uno::Reference<XAccessibleContext> xParentContext ( + mxParent->getAccessibleContext()); + if (xParentContext.is()) + { + sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); + for (sal_Int32 i=0; i<nChildCount; ++i) + { + uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i)); + if (xChild.is()) + { + if (xChild.get() == this) + nIndex = i; + } + } + } + } + + return nIndex; +} + +sal_Int16 SAL_CALL + ScAccessibleContextBase::getAccessibleRole(void) + throw (uno::RuntimeException) +{ + return maRole; +} + +::rtl::OUString SAL_CALL + ScAccessibleContextBase::getAccessibleDescription(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!msDescription.getLength()) + { + OUString sDescription(createAccessibleDescription()); +// DBG_ASSERT(sDescription.getLength(), "We should give always a descripition."); + + if (msDescription != sDescription) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.OldValue <<= msDescription; + aEvent.NewValue <<= sDescription; + + msDescription = sDescription; + + CommitChange(aEvent); + } + } + return msDescription; +} + +OUString SAL_CALL + ScAccessibleContextBase::getAccessibleName(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!msName.getLength()) + { + OUString sName(createAccessibleName()); + DBG_ASSERT(sName.getLength(), "We should give always a name."); + + if (msName != sName) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::NAME_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.OldValue <<= msName; + aEvent.NewValue <<= sName; + + msName = sName; + + CommitChange(aEvent); + } + } + return msName; +} + +uno::Reference<XAccessibleRelationSet> SAL_CALL + ScAccessibleContextBase::getAccessibleRelationSet(void) + throw (uno::RuntimeException) +{ + return new utl::AccessibleRelationSetHelper(); +} + +uno::Reference<XAccessibleStateSet> SAL_CALL + ScAccessibleContextBase::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + return uno::Reference<XAccessibleStateSet>(); +} + +lang::Locale SAL_CALL + ScAccessibleContextBase::getLocale(void) + throw (IllegalAccessibleComponentStateException, + uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mxParent.is()) + { + uno::Reference<XAccessibleContext> xParentContext ( + mxParent->getAccessibleContext()); + if (xParentContext.is()) + return xParentContext->getLocale (); + } + + // No locale and no parent. Therefore throw exception to indicate this + // cluelessness. + throw IllegalAccessibleComponentStateException (); +} + + //===== XAccessibleEventBroadcaster ===================================== + +void SAL_CALL + ScAccessibleContextBase::addEventListener( + const uno::Reference<XAccessibleEventListener>& xListener) + throw (uno::RuntimeException) +{ + if (xListener.is()) + { + ScUnoGuard aGuard; + IsObjectValid(); + if (!IsDefunc()) + { + if (!mnClientId) + mnClientId = comphelper::AccessibleEventNotifier::registerClient( ); + comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener ); + } + } +} + +void SAL_CALL + ScAccessibleContextBase::removeEventListener( + const uno::Reference<XAccessibleEventListener>& xListener) + throw (uno::RuntimeException) +{ + if (xListener.is()) + { + ScUnoGuard aGuard; + if (!IsDefunc() && mnClientId) + { + sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener ); + if ( !nListenerCount ) + { + // no listeners anymore + // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), + // and at least to us not firing any events anymore, in case somebody calls + // NotifyAccessibleEvent, again + comphelper::AccessibleEventNotifier::revokeClient( mnClientId ); + mnClientId = 0; + } + } + } +} + + //===== XAccessibleEventListener ======================================== + +void SAL_CALL ScAccessibleContextBase::disposing( + const lang::EventObject& rSource ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + if (rSource.Source == mxParent) + dispose(); +} + +void SAL_CALL ScAccessibleContextBase::notifyEvent( + const AccessibleEventObject& /* aEvent */ ) + throw (uno::RuntimeException) +{ +} + +//===== XServiceInfo ======================================================== + +::rtl::OUString SAL_CALL + ScAccessibleContextBase::getImplementationName(void) + throw (uno::RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleContextBase")); +} + +sal_Bool SAL_CALL + ScAccessibleContextBase::supportsService(const OUString& sServiceName) + throw (uno::RuntimeException) +{ + // Iterate over all supported service names and return true if on of them + // matches the given name. + uno::Sequence< ::rtl::OUString> aSupportedServices ( + getSupportedServiceNames ()); + sal_Int32 nLength(aSupportedServices.getLength()); + const OUString* pServiceNames = aSupportedServices.getConstArray(); + for (int i=0; i<nLength; ++i, ++pServiceNames) + if (sServiceName == *pServiceNames) + return sal_True; + return sal_False; +} + +uno::Sequence< ::rtl::OUString> SAL_CALL + ScAccessibleContextBase::getSupportedServiceNames(void) + throw (uno::RuntimeException) +{ + uno::Sequence<OUString> aServiceNames(2); + OUString* pServiceNames = aServiceNames.getArray(); + if (pServiceNames) + { + pServiceNames[0] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.Accessible")); + pServiceNames[1] = OUString(RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext")); + } + + return aServiceNames; +} + +//===== XTypeProvider ======================================================= + +uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes() + throw (uno::RuntimeException) +{ + return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes()); +} + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessibleContextBase::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +//===== internal ============================================================ + +::rtl::OUString SAL_CALL + ScAccessibleContextBase::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + DBG_ERROR("should be implemented in the abrevated class"); + return rtl::OUString(); +} + +::rtl::OUString SAL_CALL + ScAccessibleContextBase::createAccessibleName(void) + throw (uno::RuntimeException) +{ + DBG_ERROR("should be implemented in the abrevated class"); + return rtl::OUString(); +} + +void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const +{ + if (mnClientId) + comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent ); +} + +void ScAccessibleContextBase::ChangeName() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::NAME_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); + aEvent.OldValue <<= msName; + + msName = rtl::OUString(); // reset the name so it will be hold again + getAccessibleName(); // create the new name + + aEvent.NewValue <<= msName; + + CommitChange(aEvent); +} + +void ScAccessibleContextBase::CommitFocusGained() const +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::STATE_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); + aEvent.NewValue <<= AccessibleStateType::FOCUSED; + + CommitChange(aEvent); + + ::vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent); +} + +void ScAccessibleContextBase::CommitFocusLost() const +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::STATE_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this)); + aEvent.OldValue <<= AccessibleStateType::FOCUSED; + + CommitChange(aEvent); + + vcl::unohelper::NotifyAccessibleStateEventGlobally(aEvent); +} + +Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen(void) const + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented"); + return Rectangle(); +} + +Rectangle ScAccessibleContextBase::GetBoundingBox(void) const + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented"); + return Rectangle(); +} + +void ScAccessibleContextBase::IsObjectValid() const + throw (lang::DisposedException) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + throw lang::DisposedException(); +} + diff --git a/sc/source/ui/Accessibility/AccessibleCsvControl.cxx b/sc/source/ui/Accessibility/AccessibleCsvControl.cxx new file mode 100644 index 000000000000..e99bd1971e4c --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleCsvControl.cxx @@ -0,0 +1,1680 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +// ============================================================================ +#include "AccessibleCsvControl.hxx" +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLERELATIONTYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#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 <tools/debug.hxx> +#include <rtl/uuid.h> +#include <toolkit/helper/convert.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX +#include <unotools/accessiblestatesethelper.hxx> +#endif +#include <comphelper/sequence.hxx> +#include "scitems.hxx" +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/langitem.hxx> +#include "csvcontrol.hxx" +#include "csvruler.hxx" +#include "csvgrid.hxx" +#include "AccessibleText.hxx" +#include "editsrc.hxx" +#include "unoguard.hxx" +#include "scresid.hxx" +#include "sc.hrc" +#include "scmod.hxx" +#include <svtools/colorcfg.hxx> +// ause +#include "editutil.hxx" + +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +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::DisposedException; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::beans::PropertyValue; +using namespace ::com::sun::star::accessibility; + + +// ---------------------------------------------------------------------------- + +const sal_uInt16 nRulerRole = AccessibleRole::TEXT; +const sal_uInt16 nGridRole = AccessibleRole::TABLE; +const sal_uInt16 nCellRole = AccessibleRole::TEXT; + +#define CREATE_OUSTRING( name ) OUString( RTL_CONSTASCII_USTRINGPARAM( name ) ) + +#define RULER_IMPL_NAME "ScAccessibleCsvRuler" +#define GRID_IMPL_NAME "ScAccessibleCsvGrid" +#define CELL_IMPL_NAME "ScAccessibleCsvCell" + +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; + + +// CSV base control =========================================================== + +DBG_NAME( ScAccessibleCsvControl ) + +ScAccessibleCsvControl::ScAccessibleCsvControl( + const Reference< XAccessible >& rxParent, + ScCsvControl& rControl, + sal_uInt16 nRole ) : + ScAccessibleContextBase( rxParent, nRole ), + mpControl( &rControl ) +{ + DBG_CTOR( ScAccessibleCsvControl, NULL ); +} + +ScAccessibleCsvControl::~ScAccessibleCsvControl() +{ + DBG_DTOR( ScAccessibleCsvControl, NULL ); + implDispose(); +} + +void SAL_CALL ScAccessibleCsvControl::disposing() +{ + ScUnoGuard aGuard; + mpControl = NULL; + ScAccessibleContextBase::disposing(); +} + + +// XAccessibleComponent ------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ScAccessibleCsvControl::getAccessibleAtPoint( const AwtPoint& /* rPoint */ ) + throw( RuntimeException ) +{ + ensureAlive(); + return NULL; +} + +sal_Bool SAL_CALL ScAccessibleCsvControl::isVisible() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetControl().IsVisible(); +} + +void SAL_CALL ScAccessibleCsvControl::grabFocus() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + implGetControl().GrabFocus(); +} + + +// events --------------------------------------------------------------------- + +void ScAccessibleCsvControl::SendFocusEvent( bool bFocused ) +{ + if( bFocused ) + CommitFocusGained(); + else + CommitFocusLost(); +} + +void ScAccessibleCsvControl::SendCaretEvent() +{ + DBG_ERRORFILE( "ScAccessibleCsvControl::SendCaretEvent - Illegal call" ); +} + +void ScAccessibleCsvControl::SendVisibleEvent() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; + aEvent.Source = Reference< XAccessible >( this ); + CommitChange( aEvent ); +} + +void ScAccessibleCsvControl::SendSelectionEvent() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; + aEvent.Source = Reference< XAccessible >( this ); + CommitChange( aEvent ); +} + +void ScAccessibleCsvControl::SendTableUpdateEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */, bool /* bAllRows */ ) +{ + DBG_ERRORFILE( "ScAccessibleCsvControl::SendTableUpdateEvent - Illegal call" ); +} + +void ScAccessibleCsvControl::SendInsertColumnEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */ ) +{ + DBG_ERRORFILE( "ScAccessibleCsvControl::SendInsertColumnEvent - Illegal call" ); +} + +void ScAccessibleCsvControl::SendRemoveColumnEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */ ) +{ + DBG_ERRORFILE( "ScAccessibleCsvControl::SendRemoveColumnEvent - Illegal call" ); +} + + +// helpers -------------------------------------------------------------------- + +Rectangle ScAccessibleCsvControl::GetBoundingBoxOnScreen() const throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetControl().GetWindowExtentsRelative( NULL ); +} + +Rectangle ScAccessibleCsvControl::GetBoundingBox() const throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetControl().GetWindowExtentsRelative( implGetControl().GetAccessibleParentWindow() ); +} + +void ScAccessibleCsvControl::getUuid( Sequence< sal_Int8 >& rSeq ) +{ + ScUnoGuard aGuard; + ensureAlive(); + if( !rSeq.hasElements() ) + { + rSeq.realloc( 16 ); + rtl_createUuid( reinterpret_cast< sal_uInt8* >( rSeq.getArray() ), NULL, sal_True ); + } +} + +void ScAccessibleCsvControl::ensureAlive() const throw( DisposedException ) +{ + if( !implIsAlive() ) + throw DisposedException(); +} + +ScCsvControl& ScAccessibleCsvControl::implGetControl() const +{ + DBG_ASSERT( mpControl, "ScAccessibleCsvControl::implGetControl - missing control" ); + return *mpControl; +} + +Reference< XAccessible > ScAccessibleCsvControl::implGetChildByRole( + const Reference< XAccessible >& rxParentObj, sal_uInt16 nRole ) throw( RuntimeException ) +{ + Reference< XAccessible > xAccObj; + if( rxParentObj.is() ) + { + Reference< XAccessibleContext > xParentCtxt = rxParentObj->getAccessibleContext(); + if( xParentCtxt.is() ) + { + sal_Int32 nCount = xParentCtxt->getAccessibleChildCount(); + sal_Int32 nIndex = 0; + while( !xAccObj.is() && (nIndex < nCount) ) + { + Reference< XAccessible > xCurrObj = xParentCtxt->getAccessibleChild( nIndex ); + if( xCurrObj.is() ) + { + Reference< XAccessibleContext > xCurrCtxt = xCurrObj->getAccessibleContext(); + if( xCurrCtxt.is() && (xCurrCtxt->getAccessibleRole() == nRole) ) + xAccObj = xCurrObj; + } + ++nIndex; + } + } + } + return xAccObj; +} + +AccessibleStateSetHelper* ScAccessibleCsvControl::implCreateStateSet() +{ + ScUnoGuard aGuard; + AccessibleStateSetHelper* pStateSet = new AccessibleStateSetHelper(); + if( implIsAlive() ) + { + const ScCsvControl& rCtrl = implGetControl(); + pStateSet->AddState( AccessibleStateType::OPAQUE ); + if( rCtrl.IsEnabled() ) + pStateSet->AddState( AccessibleStateType::ENABLED ); + if( isShowing() ) + pStateSet->AddState( AccessibleStateType::SHOWING ); + if( isVisible() ) + pStateSet->AddState( AccessibleStateType::VISIBLE ); + } + else + pStateSet->AddState( AccessibleStateType::DEFUNC ); + return pStateSet; +} + +void ScAccessibleCsvControl::implDispose() +{ + if( implIsAlive() ) + { + // prevent multiple call of dtor + osl_incrementInterlockedCount( &m_refCount ); + dispose(); + } +} + +Point ScAccessibleCsvControl::implGetAbsPos( const Point& rPos ) const +{ + return rPos + implGetControl().GetWindowExtentsRelative( NULL ).TopLeft(); +} + + +// Ruler ====================================================================== + +/** Converts a ruler cursor position to API text index. */ +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. */ +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( nRelPos % nDiv - nDiv + 10L, 0L ); +} + +/** Expands the sequence's size and returns the base index of the new inserted elements. */ +inline sal_Int32 lcl_ExpandSequence( Sequence< PropertyValue >& rSeq, sal_Int32 nExp ) +{ + DBG_ASSERT( 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. */ +inline 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. */ +void lcl_FillFontAttributes( Sequence< PropertyValue >& rSeq, const Font& rFont ) +{ + SvxFontItem aFontItem( rFont.GetFamily(), rFont.GetName(), rFont.GetStyleName(), rFont.GetPitch(), rFont.GetCharSet(), ATTR_FONT ); + SvxFontHeightItem aHeightItem( rFont.GetSize().Height(), 100, ATTR_FONT_HEIGHT ); + SvxLanguageItem aLangItem( rFont.GetLanguage(), ATTR_FONT_LANGUAGE ); + + sal_Int32 nIndex = lcl_ExpandSequence( rSeq, 7 ); + lcl_FillProperty( rSeq[ nIndex++ ], CREATE_OUSTRING( "CharFontName" ), aFontItem, MID_FONT_FAMILY_NAME ); + lcl_FillProperty( rSeq[ nIndex++ ], CREATE_OUSTRING( "CharFontFamily" ), aFontItem, MID_FONT_FAMILY ); + lcl_FillProperty( rSeq[ nIndex++ ], CREATE_OUSTRING( "CharFontStyleName" ), aFontItem, MID_FONT_STYLE_NAME ); + lcl_FillProperty( rSeq[ nIndex++ ], CREATE_OUSTRING( "CharFontCharSet" ), aFontItem, MID_FONT_PITCH ); + lcl_FillProperty( rSeq[ nIndex++ ], CREATE_OUSTRING( "CharFontPitch" ), aFontItem, MID_FONT_CHAR_SET ); + lcl_FillProperty( rSeq[ nIndex++ ], CREATE_OUSTRING( "CharHeight" ), aHeightItem, MID_FONTHEIGHT ); + lcl_FillProperty( rSeq[ nIndex++ ], CREATE_OUSTRING( "CharLocale" ), aLangItem, MID_LANG_LOCALE ); +} + + + +// ---------------------------------------------------------------------------- + +DBG_NAME( ScAccessibleCsvRuler ) + +ScAccessibleCsvRuler::ScAccessibleCsvRuler( ScCsvRuler& rRuler ) : + ScAccessibleCsvControl( rRuler.GetAccessibleParentWindow()->GetAccessible(), rRuler, nRulerRole ) +{ + DBG_CTOR( ScAccessibleCsvRuler, NULL ); + constructStringBuffer(); +} + +ScAccessibleCsvRuler::~ScAccessibleCsvRuler() +{ + DBG_DTOR( ScAccessibleCsvRuler, NULL ); + implDispose(); +} + +// XAccessibleComponent ----------------------------------------------------- + +sal_Int32 SAL_CALL ScAccessibleCsvRuler::getForeground( ) + throw (RuntimeException) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetRuler().GetSettings().GetStyleSettings().GetLabelTextColor().GetColor(); +} + +sal_Int32 SAL_CALL ScAccessibleCsvRuler::getBackground( ) + throw (RuntimeException) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetRuler().GetSettings().GetStyleSettings().GetFaceColor().GetColor(); +} + +// XAccessibleContext --------------------------------------------------------- + +sal_Int32 SAL_CALL ScAccessibleCsvRuler::getAccessibleChildCount() throw( RuntimeException ) +{ + ensureAlive(); + return 0; +} + +Reference< XAccessible > SAL_CALL ScAccessibleCsvRuler::getAccessibleChild( sal_Int32 /* nIndex */ ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ensureAlive(); + throw IndexOutOfBoundsException(); +} + +Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvRuler::getAccessibleRelationSet() + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + AccessibleRelationSetHelper* pRelationSet = new AccessibleRelationSetHelper(); + Reference< XAccessible > xAccObj = implGetChildByRole( getAccessibleParent(), nGridRole ); + if( xAccObj.is() ) + { + Sequence< Reference< XInterface > > aSeq( 1 ); + aSeq[ 0 ] = xAccObj; + pRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::CONTROLLER_FOR, aSeq ) ); + } + return pRelationSet; +} + +Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvRuler::getAccessibleStateSet() + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + AccessibleStateSetHelper* pStateSet = implCreateStateSet(); + if( implIsAlive() ) + { + 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() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return lcl_GetApiPos( implGetRuler().GetRulerCursorPos() ); +} + +sal_Bool SAL_CALL ScAccessibleCsvRuler::setCaretPosition( sal_Int32 nIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard 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 ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndex( nIndex ); + return maBuffer.charAt( nIndex ); +} + +Sequence< PropertyValue > SAL_CALL ScAccessibleCsvRuler::getCharacterAttributes( sal_Int32 nIndex, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& /* aRequestedAttributes */ ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndexWithEnd( nIndex ); + Sequence< PropertyValue > aSeq; + lcl_FillFontAttributes( aSeq, implGetRuler().GetFont() ); +//! TODO split attribute: waiting for #102221# +// if( implHasSplit( nIndex ) ) +// { +// sal_Int32 nIndex = lcl_ExpandSequence( aSeq, 1 ); +// aSeq[ nIndex ].Name = CREATE_OUSTRING( "..." ); +// aSeq[ nIndex ].Value <<= ...; +// } + return aSeq; +} + +ScAccessibleCsvRuler::AwtRectangle SAL_CALL ScAccessibleCsvRuler::getCharacterBounds( sal_Int32 nIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndexWithEnd( nIndex ); + ScCsvRuler& rRuler = implGetRuler(); + Point aPos( rRuler.GetX( lcl_GetRulerPos( nIndex ) ) - rRuler.GetCharWidth() / 2, 0 ); + AwtRectangle aRect( aPos.X(), aPos.Y(), rRuler.GetCharWidth(), rRuler.GetSizePixel().Height() ); + // #107054# 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() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetTextLength(); +} + +sal_Int32 SAL_CALL ScAccessibleCsvRuler::getIndexAtPoint( const AwtPoint& rPoint ) + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ScCsvRuler& rRuler = implGetRuler(); + // #107054# use object's coordinate system, convert to API position + return lcl_GetApiPos( ::std::min( ::std::max( rRuler.GetPosFromX( rPoint.X ), static_cast<sal_Int32>(0) ), rRuler.GetPosCount() ) ); +} + +OUString SAL_CALL ScAccessibleCsvRuler::getSelectedText() throw( RuntimeException ) +{ + ensureAlive(); + return OUString(); +} + +sal_Int32 SAL_CALL ScAccessibleCsvRuler::getSelectionStart() throw( RuntimeException ) +{ + ensureAlive(); + return -1; +} + +sal_Int32 SAL_CALL ScAccessibleCsvRuler::getSelectionEnd() throw( RuntimeException ) +{ + ensureAlive(); + return -1; +} + +sal_Bool SAL_CALL ScAccessibleCsvRuler::setSelection( sal_Int32 /* nStartIndex */, sal_Int32 /* nEndIndex */ ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ensureAlive(); + return sal_False; +} + +OUString SAL_CALL ScAccessibleCsvRuler::getText() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return OUString( maBuffer.getStr(), implGetTextLength() ); +} + +OUString SAL_CALL ScAccessibleCsvRuler::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidRange( nStartIndex, nEndIndex ); + return OUString( maBuffer.getStr() + nStartIndex, nEndIndex - nStartIndex ); +} + +TextSegment SAL_CALL ScAccessibleCsvRuler::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType ) + throw( IndexOutOfBoundsException, IllegalArgumentException, RuntimeException ) +{ + ScUnoGuard 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.charAt( nIndex ) ); + } + break; + + // entire number or single dot/line + case AccessibleTextType::WORD: + case AccessibleTextType::GLYPH: + aResult.SegmentStart = nIndex; + if( nRulerPos % 10 ) + aResultText.append( maBuffer.charAt( 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 ) + throw( IndexOutOfBoundsException, IllegalArgumentException, RuntimeException ) +{ + ScUnoGuard 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 ) + throw( IndexOutOfBoundsException, IllegalArgumentException, RuntimeException ) +{ + ScUnoGuard 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 */ ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ensureAlive(); + return sal_False; +} + + +// XInterface ----------------------------------------------------------------- + +Any SAL_CALL ScAccessibleCsvRuler::queryInterface( const ::com::sun::star::uno::Type& rType ) + throw( RuntimeException ) +{ + Any aAny( ScAccessibleCsvRulerImpl::queryInterface( rType ) ); + return aAny.hasValue() ? aAny : ScAccessibleCsvControl::queryInterface( rType ); +} + +void SAL_CALL ScAccessibleCsvRuler::acquire() throw () +{ + ScAccessibleCsvControl::acquire(); +} + +void SAL_CALL ScAccessibleCsvRuler::release() throw () +{ + ScAccessibleCsvControl::release(); +} + + +// XServiceInfo --------------------------------------------------------------- + +OUString SAL_CALL ScAccessibleCsvRuler::getImplementationName() throw( RuntimeException ) +{ + return CREATE_OUSTRING( RULER_IMPL_NAME ); +} + + +// XTypeProvider -------------------------------------------------------------- + +Sequence< ::com::sun::star::uno::Type > SAL_CALL ScAccessibleCsvRuler::getTypes() throw( RuntimeException ) +{ + Sequence< ::com::sun::star::uno::Type > aSeq( 1 ); + aSeq[ 0 ] = getCppuType( static_cast< const Reference< XAccessibleText >* >( NULL ) ); + return ::comphelper::concatSequences( ScAccessibleCsvControl::getTypes(), aSeq ); +} + +Sequence< sal_Int8 > SAL_CALL ScAccessibleCsvRuler::getImplementationId() throw( RuntimeException ) +{ + static Sequence< sal_Int8 > aSeq; + getUuid( aSeq ); + return aSeq; +} + + +// events --------------------------------------------------------------------- + +void ScAccessibleCsvRuler::SendCaretEvent() +{ + sal_Int32 nPos = implGetRuler().GetRulerCursorPos(); + if( nPos != CSV_POS_INVALID ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CARET_CHANGED; + aEvent.Source = Reference< XAccessible >( this ); + aEvent.NewValue <<= nPos; + CommitChange( aEvent ); + } +} + + +// helpers -------------------------------------------------------------------- + +OUString SAL_CALL ScAccessibleCsvRuler::createAccessibleName() throw( RuntimeException ) +{ + return String( ScResId( STR_ACC_CSVRULER_NAME ) ); +} + +OUString SAL_CALL ScAccessibleCsvRuler::createAccessibleDescription() throw( RuntimeException ) +{ + return String( ScResId( STR_ACC_CSVRULER_DESCR ) ); +} + +void ScAccessibleCsvRuler::ensureValidIndex( sal_Int32 nIndex ) const + throw( IndexOutOfBoundsException ) +{ + if( (nIndex < 0) || (nIndex >= implGetTextLength()) ) + throw IndexOutOfBoundsException(); +} + +void ScAccessibleCsvRuler::ensureValidIndexWithEnd( sal_Int32 nIndex ) const + throw( IndexOutOfBoundsException ) +{ + if( (nIndex < 0) || (nIndex > implGetTextLength()) ) + throw IndexOutOfBoundsException(); +} + +void ScAccessibleCsvRuler::ensureValidRange( sal_Int32& rnStartIndex, sal_Int32& rnEndIndex ) const + throw( IndexOutOfBoundsException ) +{ + 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() throw( RuntimeException ) +{ + ScUnoGuard 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; +} + + +// Grid ======================================================================= + +/** Converts a grid columnm index to an API column index. */ +inline 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. */ +inline sal_uInt32 lcl_GetGridColumn( sal_Int32 nApiColumn ) +{ + return (nApiColumn > 0) ? static_cast< sal_uInt32 >( nApiColumn - 1 ) : CSV_COLUMN_HEADER; +} + + +// ---------------------------------------------------------------------------- + +DBG_NAME( ScAccessibleCsvGrid ) + +ScAccessibleCsvGrid::ScAccessibleCsvGrid( ScCsvGrid& rGrid ) : + ScAccessibleCsvControl( rGrid.GetAccessibleParentWindow()->GetAccessible(), rGrid, nGridRole ) +{ + DBG_CTOR( ScAccessibleCsvGrid, NULL ); +} + +ScAccessibleCsvGrid::~ScAccessibleCsvGrid() +{ + DBG_DTOR( ScAccessibleCsvGrid, NULL ); + implDispose(); +} + + +// XAccessibleComponent ------------------------------------------------------- + +Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleAtPoint( const AwtPoint& rPoint ) + throw( RuntimeException ) +{ + Reference< XAccessible > xRet; + if( containsPoint( rPoint ) ) + { + ScUnoGuard 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 = implCreateCellObj( nRow, nColumn ); + } + return xRet; +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getForeground( ) +throw (RuntimeException) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetGrid().GetSettings().GetStyleSettings().GetButtonTextColor().GetColor(); +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getBackground( ) +throw (RuntimeException) +{ + ScUnoGuard aGuard; + ensureAlive(); + return SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor; +} + +// XAccessibleContext --------------------------------------------------------- + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleChildCount() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetCellCount(); +} + +Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleChild( sal_Int32 nIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndex( nIndex ); + return implCreateCellObj( implGetRow( nIndex ), implGetColumn( nIndex ) ); +} + +Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvGrid::getAccessibleRelationSet() + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + AccessibleRelationSetHelper* pRelationSet = new AccessibleRelationSetHelper(); + Reference< XAccessible > xAccObj = implGetChildByRole( getAccessibleParent(), nRulerRole ); + if( xAccObj.is() ) + { + Sequence< Reference< XInterface > > aSeq( 1 ); + aSeq[ 0 ] = xAccObj; + pRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::CONTROLLED_BY, aSeq ) ); + } + return pRelationSet; +} + +Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvGrid::getAccessibleStateSet() + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + AccessibleStateSetHelper* pStateSet = implCreateStateSet(); + if( implIsAlive() ) + { + 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() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetRowCount(); +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnCount() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetColumnCount(); +} + +OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleRowDescription( sal_Int32 nRow ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidPosition( nRow, 0 ); + return implGetCellText( nRow, 0 ); +} + +OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnDescription( sal_Int32 nColumn ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidPosition( 0, nColumn ); + return implGetCellText( 0, nColumn ); +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ensureAlive(); + ensureValidPosition( nRow, nColumn ); + return 1; +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ensureAlive(); + ensureValidPosition( nRow, nColumn ); + return 1; +} + +Reference< XAccessibleTable > SAL_CALL ScAccessibleCsvGrid::getAccessibleRowHeaders() + throw( RuntimeException ) +{ + ensureAlive(); + return NULL; +} + +Reference< XAccessibleTable > SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnHeaders() + throw( RuntimeException ) +{ + ensureAlive(); + return NULL; +} + +Sequence< sal_Int32 > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleRows() + throw( RuntimeException ) +{ + ensureAlive(); + return Sequence< sal_Int32 >(); +} + +Sequence< sal_Int32 > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleColumns() + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + + ScCsvGrid& rGrid = implGetGrid(); + Sequence< sal_Int32 > aSeq( implGetColumnCount() ); + + sal_Int32 nSeqIx = 0; + sal_uInt32 nColIx = rGrid.GetFirstSelected(); + for( ; nColIx != CSV_COLUMN_INVALID; ++nSeqIx, nColIx = rGrid.GetNextSelected( nColIx ) ) + aSeq[ nSeqIx ] = lcl_GetApiColumn( nColIx ); + + aSeq.realloc( nSeqIx ); + return aSeq; +} + +sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleRowSelected( sal_Int32 /* nRow */ ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ensureAlive(); + return sal_False; +} + +sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleColumnSelected( sal_Int32 nColumn ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndex( nColumn ); + return implIsColumnSelected( nColumn ); +} + +Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidPosition( nRow, nColumn ); + return implCreateCellObj( nRow, nColumn ); +} + +Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleCaption() + throw( RuntimeException ) +{ + ensureAlive(); + return NULL; +} + +Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleSummary() + throw( RuntimeException ) +{ + ensureAlive(); + return NULL; +} + +sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleSelected( sal_Int32 /* nRow */, sal_Int32 nColumn ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + return isAccessibleColumnSelected( nColumn ); +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidPosition( nRow, nColumn ); + return implGetIndex( nRow, nColumn ); +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRow( sal_Int32 nChildIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndex( nChildIndex ); + return implGetRow( nChildIndex ); +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumn( sal_Int32 nChildIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndex( nChildIndex ); + return implGetColumn( nChildIndex ); +} + + +// XAccessibleSelection ------------------------------------------------------- + +void SAL_CALL ScAccessibleCsvGrid::selectAccessibleChild( sal_Int32 nChildIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard 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 ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ensureValidIndex( nChildIndex ); + sal_Int32 nColumn = implGetColumn( nChildIndex ); + return implIsColumnSelected( nColumn ); +} + +void SAL_CALL ScAccessibleCsvGrid::clearAccessibleSelection() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + implGetGrid().SelectAll( false ); +} + +void SAL_CALL ScAccessibleCsvGrid::selectAllAccessibleChildren() throw( RuntimeException ) +{ + selectAccessibleChild( 0 ); +} + +sal_Int32 SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleChildCount() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetRowCount() * implGetSelColumnCount(); +} + +Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard 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 ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + ScUnoGuard 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 ::com::sun::star::uno::Type& rType ) + throw( RuntimeException ) +{ + Any aAny( ScAccessibleCsvGridImpl::queryInterface( rType ) ); + return aAny.hasValue() ? aAny : ScAccessibleCsvControl::queryInterface( rType ); +} + +void SAL_CALL ScAccessibleCsvGrid::acquire() throw () +{ + ScAccessibleCsvControl::acquire(); +} + +void SAL_CALL ScAccessibleCsvGrid::release() throw () +{ + ScAccessibleCsvControl::release(); +} + + +// XServiceInfo --------------------------------------------------------------- + +OUString SAL_CALL ScAccessibleCsvGrid::getImplementationName() throw( RuntimeException ) +{ + return CREATE_OUSTRING( GRID_IMPL_NAME ); +} + + +// XTypeProvider -------------------------------------------------------------- + +Sequence< ::com::sun::star::uno::Type > SAL_CALL ScAccessibleCsvGrid::getTypes() throw( RuntimeException ) +{ + Sequence< ::com::sun::star::uno::Type > aSeq( 2 ); + aSeq[ 0 ] = getCppuType( static_cast< const Reference< XAccessibleTable >* >( NULL ) ); + aSeq[ 1 ] = getCppuType( static_cast< const Reference< XAccessibleSelection >* >( NULL ) ); + return ::comphelper::concatSequences( ScAccessibleCsvControl::getTypes(), aSeq ); +} + +Sequence< sal_Int8 > SAL_CALL ScAccessibleCsvGrid::getImplementationId() throw( RuntimeException ) +{ + static Sequence< sal_Int8 > aSeq; + getUuid( aSeq ); + return aSeq; +} + + +// events --------------------------------------------------------------------- + +void ScAccessibleCsvGrid::SendFocusEvent( bool bFocused ) +{ + ScAccessibleCsvControl::SendFocusEvent( bFocused ); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; + aEvent.Source = Reference< XAccessible >( this ); + (bFocused ? aEvent.NewValue : aEvent.OldValue) <<= + getAccessibleCellAt( 0, lcl_GetApiColumn( implGetGrid().GetFocusColumn() ) ); + CommitChange( aEvent ); +} + +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 ) ); + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED; + aEvent.Source = Reference< XAccessible >( this ); + aEvent.NewValue <<= aModelChange; + CommitChange( aEvent ); + } +} + +void ScAccessibleCsvGrid::SendInsertColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn ) +{ + if( nFirstColumn <= nLastColumn ) + { + AccessibleTableModelChange aModelChange( + AccessibleTableModelChangeType::INSERT, 0, implGetRowCount() - 1, + lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) ); + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED; + aEvent.Source = Reference< XAccessible >( this ); + aEvent.NewValue <<= aModelChange; + CommitChange( aEvent ); + } +} + +void ScAccessibleCsvGrid::SendRemoveColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn ) +{ + if( nFirstColumn <= nLastColumn ) + { + AccessibleTableModelChange aModelChange( + AccessibleTableModelChangeType::DELETE, 0, implGetRowCount() - 1, + lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) ); + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED; + aEvent.Source = Reference< XAccessible >( this ); + aEvent.NewValue <<= aModelChange; + CommitChange( aEvent ); + } +} + + +// helpers -------------------------------------------------------------------- + +OUString SAL_CALL ScAccessibleCsvGrid::createAccessibleName() throw( RuntimeException ) +{ + return String( ScResId( STR_ACC_CSVGRID_NAME ) ); +} + +OUString SAL_CALL ScAccessibleCsvGrid::createAccessibleDescription() throw( RuntimeException ) +{ + return String( ScResId( STR_ACC_CSVGRID_DESCR ) ); +} + +void ScAccessibleCsvGrid::ensureValidIndex( sal_Int32 nIndex ) const + throw( IndexOutOfBoundsException ) +{ + if( (nIndex < 0) || (nIndex >= implGetCellCount()) ) + throw IndexOutOfBoundsException(); +} + +void ScAccessibleCsvGrid::ensureValidPosition( sal_Int32 nRow, sal_Int32 nColumn ) const + throw( IndexOutOfBoundsException ) +{ + 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; +} + +String ScAccessibleCsvGrid::implGetCellText( sal_Int32 nRow, sal_Int32 nColumn ) const +{ + ScCsvGrid& rGrid = implGetGrid(); + sal_Int32 nLine = nRow + rGrid.GetFirstVisLine() - 1; + String aCellStr; + if( (nColumn > 0) && (nRow > 0) ) + aCellStr = rGrid.GetCellText( lcl_GetGridColumn( nColumn ), nLine ); + else if( nRow > 0 ) + aCellStr = String::CreateFromInt32( nLine + 1L ); + else if( nColumn > 0 ) + aCellStr = rGrid.GetColumnTypeName( lcl_GetGridColumn( nColumn ) ); + return aCellStr; +} + + +ScAccessibleCsvControl* ScAccessibleCsvGrid::implCreateCellObj( sal_Int32 nRow, sal_Int32 nColumn ) const +{ + return new ScAccessibleCsvCell( implGetGrid(), implGetCellText( nRow, nColumn ), nRow, nColumn ); +} + + +// ============================================================================ + +DBG_NAME( ScAccessibleCsvCell ) + +ScAccessibleCsvCell::ScAccessibleCsvCell( + ScCsvGrid& rGrid, + const String& rCellText, + sal_Int32 nRow, sal_Int32 nColumn ) : + ScAccessibleCsvControl( rGrid.GetAccessible(), rGrid, nCellRole ), + AccessibleStaticTextBase( SvxEditSourcePtr( NULL ) ), + maCellText( rCellText ), + mnLine( nRow ? (nRow + rGrid.GetFirstVisLine() - 1) : CSV_LINE_HEADER ), + mnColumn( lcl_GetGridColumn( nColumn ) ), + mnIndex( nRow * (rGrid.GetColumnCount() + 1) + nColumn ) +{ + DBG_CTOR( ScAccessibleCsvCell, NULL ); + SetEditSource( implCreateEditSource() ); +} + +ScAccessibleCsvCell::~ScAccessibleCsvCell() +{ + DBG_DTOR( ScAccessibleCsvCell, NULL ); +} + +void SAL_CALL ScAccessibleCsvCell::disposing() +{ + ScUnoGuard aGuard; + SetEditSource( SvxEditSourcePtr( NULL ) ); + ScAccessibleCsvControl::disposing(); +} + + +// XAccessibleComponent ------------------------------------------------------- + +void SAL_CALL ScAccessibleCsvCell::grabFocus() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + ScCsvGrid& rGrid = implGetGrid(); + rGrid.Execute( CSVCMD_MOVEGRIDCURSOR, rGrid.GetColumnPos( mnColumn ) ); +} + +sal_Int32 SAL_CALL ScAccessibleCsvCell::getForeground( ) +throw (RuntimeException) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetGrid().GetSettings().GetStyleSettings().GetButtonTextColor().GetColor(); +} + +sal_Int32 SAL_CALL ScAccessibleCsvCell::getBackground( ) +throw (RuntimeException) +{ + ScUnoGuard aGuard; + ensureAlive(); + return SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor; +} + +// XAccessibleContext ----------------------------------------------------- + +sal_Int32 SAL_CALL ScAccessibleCsvCell::getAccessibleChildCount() throw( RuntimeException ) +{ + return AccessibleStaticTextBase::getAccessibleChildCount(); +} + +Reference< XAccessible > SAL_CALL ScAccessibleCsvCell::getAccessibleChild( sal_Int32 nIndex ) + throw( IndexOutOfBoundsException, RuntimeException ) +{ + return AccessibleStaticTextBase::getAccessibleChild( nIndex ); +} + +sal_Int32 SAL_CALL ScAccessibleCsvCell::getAccessibleIndexInParent() throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return mnIndex; +} + +Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvCell::getAccessibleRelationSet() + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return new AccessibleRelationSetHelper(); +} + +Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvCell::getAccessibleStateSet() + throw( RuntimeException ) +{ + ScUnoGuard aGuard; + AccessibleStateSetHelper* pStateSet = implCreateStateSet(); + if( implIsAlive() ) + { + 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 ) + +// XServiceInfo --------------------------------------------------------------- + +OUString SAL_CALL ScAccessibleCsvCell::getImplementationName() throw( RuntimeException ) +{ + return CREATE_OUSTRING( CELL_IMPL_NAME ); +} + +// helpers -------------------------------------------------------------------- + +Rectangle ScAccessibleCsvCell::GetBoundingBoxOnScreen() const throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + Rectangle aRect( implGetBoundingBox() ); + aRect.SetPos( implGetAbsPos( aRect.TopLeft() ) ); + return aRect; +} + +Rectangle ScAccessibleCsvCell::GetBoundingBox() const throw( RuntimeException ) +{ + ScUnoGuard aGuard; + ensureAlive(); + return implGetBoundingBox(); +} + +OUString SAL_CALL ScAccessibleCsvCell::createAccessibleName() throw( RuntimeException ) +{ + return maCellText; +} + +OUString SAL_CALL ScAccessibleCsvCell::createAccessibleDescription() throw( RuntimeException ) +{ + 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() ); +} + +Rectangle ScAccessibleCsvCell::implGetBoundingBox() const +{ + ScCsvGrid& rGrid = implGetGrid(); + Rectangle aClipRect( Point( 0, 0 ), rGrid.GetSizePixel() ); + if( mnColumn != CSV_COLUMN_HEADER ) + { + aClipRect.Left() = rGrid.GetFirstX(); + aClipRect.Right() = rGrid.GetLastX(); + } + if( mnLine != CSV_LINE_HEADER ) + aClipRect.Top() = rGrid.GetHdrHeight(); + + Rectangle aRect( implGetRealPos(), implGetRealSize() ); + aRect.Intersection( aClipRect ); + if( (aRect.GetWidth() <= 0) || (aRect.GetHeight() <= 0) ) + aRect.SetSize( Size( -1, -1 ) ); + return aRect; +} + +::std::auto_ptr< SvxEditSource > ScAccessibleCsvCell::implCreateEditSource() +{ + ScCsvGrid& rGrid = implGetGrid(); + Rectangle aBoundRect( implGetBoundingBox() ); + aBoundRect -= implGetRealPos(); + + ::std::auto_ptr< ScAccessibleTextData > pCsvTextData( new ScAccessibleCsvTextData( + &rGrid, rGrid.GetEditEngine(), maCellText, aBoundRect, implGetRealSize() ) ); + + ::std::auto_ptr< SvxEditSource > pEditSource( new ScAccessibilityEditSource( pCsvTextData ) ); + return pEditSource; +} + + +// ============================================================================ + diff --git a/sc/source/ui/Accessibility/AccessibleDataPilotControl.cxx b/sc/source/ui/Accessibility/AccessibleDataPilotControl.cxx new file mode 100644 index 000000000000..1848c7bfefc0 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleDataPilotControl.cxx @@ -0,0 +1,739 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" +#include "AccessibleDataPilotControl.hxx" +#include "unoguard.hxx" +#include "fieldwnd.hxx" + +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#include <com/sun/star/accessibility/AccessibleEventId.hpp> + +#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX +#include <unotools/accessiblestatesethelper.hxx> +#endif +#include <rtl/uuid.h> +#include <tools/gen.hxx> +#include <toolkit/helper/convert.hxx> +#include <tools/debug.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +class ScAccessibleDataPilotButton + : public ScAccessibleContextBase +{ +public: + //===== internal ======================================================== + ScAccessibleDataPilotButton( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, + ScDPFieldWindow* pDPFieldWindow, + sal_Int32 nIndex); + + virtual void Init(); + + using ScAccessibleContextBase::disposing; + virtual void SAL_CALL disposing(); + + void SetIndex(sal_Int32 nIndex) { mnIndex = nIndex; } + void NameChanged(); + void SetFocused(); + void ResetFocused(); +protected: + virtual ~ScAccessibleDataPilotButton(void); +public: + ///===== XAccessibleComponent ============================================ + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + SAL_CALL getAccessibleAtPoint( + const ::com::sun::star::awt::Point& rPoint ) + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Bool SAL_CALL isVisible( ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL grabFocus( ) + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getForeground( ) + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getBackground( ) + throw (::com::sun::star::uno::RuntimeException); + + ///===== XAccessibleContext ============================================== + + /// Return the number of currently visible children. + virtual sal_Int32 SAL_CALL + getAccessibleChildCount(void) throw (::com::sun::star::uno::RuntimeException); + + /// Return the specified child or NULL if index is invalid. + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL + getAccessibleChild(sal_Int32 nIndex) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IndexOutOfBoundsException); + + /// Return this objects index among the parents children. + virtual sal_Int32 SAL_CALL + getAccessibleIndexInParent(void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the set of current states. + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleStateSet> SAL_CALL + getAccessibleStateSet(void) + throw (::com::sun::star::uno::RuntimeException); + + ///===== XServiceInfo ==================================================== + + /** Returns an identifier for the implementation of this object. + */ + virtual ::rtl::OUString SAL_CALL + getImplementationName(void) + throw (::com::sun::star::uno::RuntimeException); + + ///===== XTypeProvider =================================================== + + /** Returns a implementation id. + */ + virtual ::com::sun::star::uno::Sequence<sal_Int8> SAL_CALL + getImplementationId(void) + throw (::com::sun::star::uno::RuntimeException); + +protected: + /// Return this object's description. + virtual ::rtl::OUString SAL_CALL + createAccessibleDescription(void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the object's current name. + virtual ::rtl::OUString SAL_CALL + createAccessibleName(void) + throw (::com::sun::star::uno::RuntimeException); + + /// Return the object's current bounding box relative to the desktop. + virtual Rectangle GetBoundingBoxOnScreen(void) const + throw (::com::sun::star::uno::RuntimeException); + + /// Return the object's current bounding box relative to the parent object. + virtual Rectangle GetBoundingBox(void) const + throw (::com::sun::star::uno::RuntimeException); + +private: + ScDPFieldWindow* mpDPFieldWindow; + sal_Int32 mnIndex; +}; + + //===== internal ======================================================== +ScAccessibleDataPilotControl::ScAccessibleDataPilotControl( + const uno::Reference<XAccessible>& rxParent, + ScDPFieldWindow* pDPFieldWindow) + : + ScAccessibleContextBase(rxParent, AccessibleRole::GROUP_BOX), + mpDPFieldWindow(pDPFieldWindow) +{ + if (mpDPFieldWindow) + maChildren.resize(mpDPFieldWindow->GetFieldCount()); +} + +ScAccessibleDataPilotControl::~ScAccessibleDataPilotControl(void) +{ + if (!IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + // call dispose to inform object wich have a weak reference to this object + dispose(); + } +} + +void ScAccessibleDataPilotControl::Init() +{ +} + +void SAL_CALL ScAccessibleDataPilotControl::disposing() +{ + ScUnoGuard aGuard; + mpDPFieldWindow = NULL; + + ScAccessibleContextBase::disposing(); +} + +void ScAccessibleDataPilotControl::AddField(sal_Int32 nNewIndex) +{ + sal_Bool bAdded(sal_False); + if (static_cast<sal_uInt32>(nNewIndex) == maChildren.size()) + { + maChildren.push_back(AccessibleWeak()); + bAdded = sal_True; + } + else if (static_cast<sal_uInt32>(nNewIndex) < maChildren.size()) + { + ::std::vector < AccessibleWeak >::iterator aItr = maChildren.begin() + nNewIndex; + maChildren.insert(aItr, AccessibleWeak()); + + ::std::vector < AccessibleWeak >::iterator aEndItr = maChildren.end(); + aItr = maChildren.begin() + nNewIndex + 1; + uno::Reference< XAccessible > xTempAcc; + sal_Int32 nIndex = nNewIndex + 1; + while (aItr != aEndItr) + { + xTempAcc = aItr->xWeakAcc; + if (xTempAcc.is() && aItr->pAcc) + aItr->pAcc->SetIndex(nIndex); + ++nIndex; + ++aItr; + } + bAdded = sal_True; + } + else + { + DBG_ERRORFILE("did not recognize a child count change"); + } + + if (bAdded) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.NewValue <<= getAccessibleChild(nNewIndex); + + CommitChange(aEvent); // new child - event + } +} + +void ScAccessibleDataPilotControl::RemoveField(sal_Int32 nOldIndex) +{ + sal_Bool bRemoved(sal_False); + uno::Reference< XAccessible > xTempAcc; + ScAccessibleDataPilotButton* pField = NULL; + if (static_cast<sal_uInt32>(nOldIndex) < maChildren.size()) + { + xTempAcc = getAccessibleChild(nOldIndex); + pField = maChildren[nOldIndex].pAcc; + + ::std::vector < AccessibleWeak >::iterator aItr = maChildren.begin() + nOldIndex; + aItr = maChildren.erase(aItr); + + ::std::vector < AccessibleWeak >::iterator aEndItr = maChildren.end(); + uno::Reference< XAccessible > xItrAcc; + while (aItr != aEndItr) + { + xItrAcc = aItr->xWeakAcc; + if (xItrAcc.is() && aItr->pAcc) + aItr->pAcc->SetIndex(nOldIndex); + ++nOldIndex; + ++aItr; + } + bRemoved = sal_True; + } + else + { + DBG_ERRORFILE("did not recognize a child count change"); + } + + if (bRemoved) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.NewValue <<= xTempAcc; + + CommitChange(aEvent); // gone child - event + + if (pField) + pField->dispose(); + } +} + +void ScAccessibleDataPilotControl::FieldFocusChange(sal_Int32 nOldIndex, sal_Int32 nNewIndex) +{ + DBG_ASSERT(static_cast<sal_uInt32>(nOldIndex) < maChildren.size() && + static_cast<sal_uInt32>(nNewIndex) < maChildren.size(), "did not recognize a child count change"); + + uno::Reference < XAccessible > xTempAcc = maChildren[nOldIndex].xWeakAcc; + if (xTempAcc.is() && maChildren[nOldIndex].pAcc) + maChildren[nOldIndex].pAcc->ResetFocused(); + + xTempAcc = maChildren[nNewIndex].xWeakAcc; + if (xTempAcc.is() && maChildren[nNewIndex].pAcc) + maChildren[nNewIndex].pAcc->SetFocused(); +} + +void ScAccessibleDataPilotControl::FieldNameChange(sal_Int32 nIndex) +{ + DBG_ASSERT(static_cast<sal_uInt32>(nIndex) < maChildren.size(), "did not recognize a child count change"); + + uno::Reference < XAccessible > xTempAcc = maChildren[nIndex].xWeakAcc; + if (xTempAcc.is() && maChildren[nIndex].pAcc) + maChildren[nIndex].pAcc->ChangeName(); +} + +void ScAccessibleDataPilotControl::GotFocus() +{ + if (mpDPFieldWindow) + { + DBG_ASSERT(static_cast<sal_uInt32>(mpDPFieldWindow->GetFieldCount()) == maChildren.size(), "did not recognize a child count change"); + + sal_Int32 nIndex(mpDPFieldWindow->GetSelectedField()); + uno::Reference < XAccessible > xTempAcc = maChildren[nIndex].xWeakAcc; + if (xTempAcc.is() && maChildren[nIndex].pAcc) + maChildren[nIndex].pAcc->SetFocused(); + } +} + +void ScAccessibleDataPilotControl::LostFocus() +{ + if (mpDPFieldWindow) + { + DBG_ASSERT(static_cast<sal_uInt32>(mpDPFieldWindow->GetFieldCount()) == maChildren.size(), "did not recognize a child count change"); + + sal_Int32 nIndex(mpDPFieldWindow->GetSelectedField()); + uno::Reference < XAccessible > xTempAcc = maChildren[nIndex].xWeakAcc; + if (xTempAcc.is() && maChildren[nIndex].pAcc) + maChildren[nIndex].pAcc->ResetFocused(); + } +} + + ///===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessibleDataPilotControl::getAccessibleAtPoint( + const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xAcc; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + if (mpDPFieldWindow) + { + Point aAbsPoint(VCLPoint(rPoint)); + Point aControlEdge(GetBoundingBoxOnScreen().TopLeft()); + Point aRelPoint(aAbsPoint - aControlEdge); + size_t nChildIndex(0); + if (mpDPFieldWindow->GetFieldIndex(aRelPoint, nChildIndex)) + xAcc = getAccessibleChild(static_cast< long >( nChildIndex )); + } + } + return xAcc; +} + +sal_Bool SAL_CALL ScAccessibleDataPilotControl::isVisible( ) + throw (uno::RuntimeException) +{ + return sal_True; +} + +void SAL_CALL ScAccessibleDataPilotControl::grabFocus( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpDPFieldWindow) + mpDPFieldWindow->GrabFocus(); +} + +sal_Int32 SAL_CALL ScAccessibleDataPilotControl::getForeground( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nColor(0); + if (mpDPFieldWindow) + { + nColor = mpDPFieldWindow->GetSettings().GetStyleSettings().GetWindowTextColor().GetColor(); + } + return nColor; +} + +sal_Int32 SAL_CALL ScAccessibleDataPilotControl::getBackground( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nColor(0); + if (mpDPFieldWindow) + { + if (mpDPFieldWindow->GetType() == TYPE_SELECT) + { + nColor = mpDPFieldWindow->GetSettings().GetStyleSettings().GetFaceColor().GetColor(); + } + else + { + nColor = mpDPFieldWindow->GetSettings().GetStyleSettings().GetWindowColor().GetColor(); + } + } + return nColor; +} + + ///===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL ScAccessibleDataPilotControl::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpDPFieldWindow) + return mpDPFieldWindow->GetFieldCount(); + else + return 0; +} + +uno::Reference< XAccessible> SAL_CALL ScAccessibleDataPilotControl::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Reference<XAccessible> xAcc; + if (mpDPFieldWindow) + { + if (nIndex < 0 || static_cast< size_t >( nIndex ) >= mpDPFieldWindow->GetFieldCount()) + throw lang::IndexOutOfBoundsException(); + + DBG_ASSERT(static_cast<sal_uInt32>(mpDPFieldWindow->GetFieldCount()) == maChildren.size(), "did not recognize a child count change"); + + uno::Reference < XAccessible > xTempAcc = maChildren[nIndex].xWeakAcc; + if (!xTempAcc.is()) + { + maChildren[nIndex].pAcc = new ScAccessibleDataPilotButton(this, mpDPFieldWindow, nIndex); + xTempAcc = maChildren[nIndex].pAcc; + maChildren[nIndex].xWeakAcc = xTempAcc; + } + + xAcc = xTempAcc; + } + return xAcc; +} + +uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessibleDataPilotControl::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + + if (IsDefunc()) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::OPAQUE); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + + return pStateSet; +} + + ///===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleDataPilotControl::getImplementationName(void) + throw (uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleDataPilotControl")); +} + + ///===== XTypeProvider =================================================== + +uno::Sequence<sal_Int8> SAL_CALL ScAccessibleDataPilotControl::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + + //===== internal ======================================================== + +::rtl::OUString SAL_CALL ScAccessibleDataPilotControl::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpDPFieldWindow) + return mpDPFieldWindow->GetDescription(); + + return rtl::OUString(); +} + +::rtl::OUString SAL_CALL ScAccessibleDataPilotControl::createAccessibleName(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpDPFieldWindow) + return mpDPFieldWindow->GetName(); + + return rtl::OUString(); +} + +Rectangle ScAccessibleDataPilotControl::GetBoundingBoxOnScreen(void) const + throw (uno::RuntimeException) +{ + if (mpDPFieldWindow) + return mpDPFieldWindow->GetWindowExtentsRelative(NULL); + else + return Rectangle(); +} + +Rectangle ScAccessibleDataPilotControl::GetBoundingBox(void) const + throw (uno::RuntimeException) +{ + if (mpDPFieldWindow) + return mpDPFieldWindow->GetWindowExtentsRelative(mpDPFieldWindow->GetAccessibleParentWindow()); + else + return Rectangle(); +} + + +//=============================================================================== + +ScAccessibleDataPilotButton::ScAccessibleDataPilotButton( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, + ScDPFieldWindow* pDPFieldWindow, + sal_Int32 nIndex) + : ScAccessibleContextBase(rxParent, AccessibleRole::PUSH_BUTTON), + mpDPFieldWindow(pDPFieldWindow), + mnIndex(nIndex) +{ +} + +ScAccessibleDataPilotButton::~ScAccessibleDataPilotButton(void) +{ + if (!IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + // call dispose to inform object wich have a weak reference to this object + dispose(); + } +} + +void ScAccessibleDataPilotButton::Init() +{ +} + +void SAL_CALL ScAccessibleDataPilotButton::disposing() +{ + ScUnoGuard aGuard; + mpDPFieldWindow = NULL; + + ScAccessibleContextBase::disposing(); +} + +void ScAccessibleDataPilotButton::SetFocused() +{ + CommitFocusGained(); +} + +void ScAccessibleDataPilotButton::ResetFocused() +{ + CommitFocusLost(); +} + + ///===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessibleDataPilotButton::getAccessibleAtPoint( + const ::com::sun::star::awt::Point& /* rPoint */ ) + throw (::com::sun::star::uno::RuntimeException) +{ + return NULL; +} + +sal_Bool SAL_CALL ScAccessibleDataPilotButton::isVisible( ) + throw (::com::sun::star::uno::RuntimeException) +{ + return sal_True; +} + +void SAL_CALL ScAccessibleDataPilotButton::grabFocus( ) + throw (::com::sun::star::uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpDPFieldWindow) + { + mpDPFieldWindow->GrabFocusWithSel(getAccessibleIndexInParent()); + } +} + +sal_Int32 SAL_CALL ScAccessibleDataPilotButton::getForeground( ) +throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nColor(0); + if (mpDPFieldWindow) + { + nColor = mpDPFieldWindow->GetSettings().GetStyleSettings().GetButtonTextColor().GetColor(); + } + return nColor; +} + +sal_Int32 SAL_CALL ScAccessibleDataPilotButton::getBackground( ) +throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nColor(0); + if (mpDPFieldWindow) + { + nColor = mpDPFieldWindow->GetSettings().GetStyleSettings().GetFaceColor().GetColor(); + } + return nColor; +} + + ///===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL ScAccessibleDataPilotButton::getAccessibleChildCount(void) + throw (::com::sun::star::uno::RuntimeException) +{ + return 0; +} + +uno::Reference< XAccessible> SAL_CALL ScAccessibleDataPilotButton::getAccessibleChild(sal_Int32 /* nIndex */) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IndexOutOfBoundsException) +{ + throw lang::IndexOutOfBoundsException(); +} + +sal_Int32 SAL_CALL ScAccessibleDataPilotButton::getAccessibleIndexInParent(void) + throw (::com::sun::star::uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return mnIndex; +} + +uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessibleDataPilotButton::getAccessibleStateSet(void) + throw (::com::sun::star::uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + + if (IsDefunc()) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::OPAQUE); + pStateSet->AddState(AccessibleStateType::FOCUSABLE); + if (mpDPFieldWindow && (sal::static_int_cast<sal_Int32>(mpDPFieldWindow->GetSelectedField()) == mnIndex)) + pStateSet->AddState(AccessibleStateType::FOCUSED); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + + return pStateSet; +} + + ///===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleDataPilotButton::getImplementationName(void) + throw (::com::sun::star::uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleDataPilotButton")); +} + + ///===== XTypeProvider =================================================== + +uno::Sequence<sal_Int8> SAL_CALL ScAccessibleDataPilotButton::getImplementationId(void) + throw (::com::sun::star::uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +::rtl::OUString SAL_CALL ScAccessibleDataPilotButton::createAccessibleDescription(void) + throw (::com::sun::star::uno::RuntimeException) +{ + return rtl::OUString(); +} + +::rtl::OUString SAL_CALL ScAccessibleDataPilotButton::createAccessibleName(void) + throw (::com::sun::star::uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpDPFieldWindow) + return mpDPFieldWindow->GetFieldText(getAccessibleIndexInParent()); + + return rtl::OUString(); +} + +Rectangle ScAccessibleDataPilotButton::GetBoundingBoxOnScreen(void) const + throw (::com::sun::star::uno::RuntimeException) +{ + Rectangle aRect(GetBoundingBox()); + + if (mpDPFieldWindow) + { + Point aParentPos(mpDPFieldWindow->GetWindowExtentsRelative(NULL).TopLeft()); + aRect.Move(aParentPos.getX(), aParentPos.getY()); + } + + return aRect; +} + +Rectangle ScAccessibleDataPilotButton::GetBoundingBox(void) const + throw (::com::sun::star::uno::RuntimeException) +{ + if (mpDPFieldWindow) + return Rectangle (mpDPFieldWindow->GetFieldPosition(const_cast<ScAccessibleDataPilotButton*> (this)->getAccessibleIndexInParent()), mpDPFieldWindow->GetFieldSize()); + else + return Rectangle(); +} diff --git a/sc/source/ui/Accessibility/AccessibleDocument.cxx b/sc/source/ui/Accessibility/AccessibleDocument.cxx new file mode 100644 index 000000000000..4c65632fb45e --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleDocument.cxx @@ -0,0 +1,2120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include "AccessibleDocument.hxx" +#include "AccessibleSpreadsheet.hxx" +#include "tabvwsh.hxx" +#include "AccessibilityHints.hxx" +#include "document.hxx" +#include "drwlayer.hxx" +#include "unoguard.hxx" +#include "shapeuno.hxx" +#include "DrawModelBroadcaster.hxx" +#include "drawview.hxx" +#include "gridwin.hxx" +#include "AccessibleEditObject.hxx" +#include "scresid.hxx" +#ifndef SC_SC_HRC +#include "sc.hrc" +#endif +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLERELATIONTYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#endif +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XShapes.hpp> + +#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX +#include <unotools/accessiblestatesethelper.hxx> +#endif +#include <tools/debug.hxx> +#include <tools/gen.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdobj.hxx> +#include <svx/ShapeTypeHandler.hxx> +#include <svx/AccessibleShape.hxx> +#include <svx/AccessibleShapeTreeInfo.hxx> +#include <svx/AccessibleShapeInfo.hxx> +#include <comphelper/sequence.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/unoshcol.hxx> +#include <svx/unoshape.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <toolkit/helper/convert.hxx> + +#include <list> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::std::for_each; + + //===== internal ======================================================== + +struct ScAccessibleShapeData +{ + ScAccessibleShapeData() : pAccShape(NULL), pRelationCell(NULL), bSelected(sal_False), bSelectable(sal_True) {} + ~ScAccessibleShapeData(); + mutable ::accessibility::AccessibleShape* pAccShape; + mutable ScAddress* pRelationCell; // if it is NULL this shape is anchored on the table +// SdrObject* pShape; + com::sun::star::uno::Reference< com::sun::star::drawing::XShape > xShape; + mutable sal_Bool bSelected; + sal_Bool bSelectable; +}; + +ScAccessibleShapeData::~ScAccessibleShapeData() +{ + if (pAccShape) + { + pAccShape->dispose(); + pAccShape->release(); + } +} + +struct ScShapeDataLess +{ + rtl::OUString msLayerId; + rtl::OUString msZOrder; + ScShapeDataLess() + : msLayerId(RTL_CONSTASCII_USTRINGPARAM( "LayerID" )), + msZOrder(RTL_CONSTASCII_USTRINGPARAM( "ZOrder" )) + { + } + void ConvertLayerId(sal_Int16& rLayerID) const // changes the number of the LayerId so it the accessibility order + { + switch (rLayerID) + { + case SC_LAYER_FRONT: + rLayerID = 1; + break; + case SC_LAYER_BACK: + rLayerID = 0; + break; + case SC_LAYER_INTERN: + rLayerID = 2; + break; + case SC_LAYER_CONTROLS: + rLayerID = 3; + break; + } + } + sal_Bool LessThanSheet(const ScAccessibleShapeData* pData) const + { + sal_Bool bResult(sal_False); + uno::Reference< beans::XPropertySet> xProps(pData->xShape, uno::UNO_QUERY); + if (xProps.is()) + { + uno::Any aPropAny = xProps->getPropertyValue(msLayerId); + sal_Int16 nLayerID = 0; + if( (aPropAny >>= nLayerID) ) + { + if (nLayerID == SC_LAYER_BACK) + bResult = sal_True; + } + } + return bResult; + } + sal_Bool operator()(const ScAccessibleShapeData* pData1, const ScAccessibleShapeData* pData2) const + { + sal_Bool bResult(sal_False); + if (pData1 && pData2) + { + uno::Reference< beans::XPropertySet> xProps1(pData1->xShape, uno::UNO_QUERY); + uno::Reference< beans::XPropertySet> xProps2(pData2->xShape, uno::UNO_QUERY); + if (xProps1.is() && xProps2.is()) + { + uno::Any aPropAny1 = xProps1->getPropertyValue(msLayerId); + uno::Any aPropAny2 = xProps2->getPropertyValue(msLayerId); + sal_Int16 nLayerID1(0); + sal_Int16 nLayerID2(0); + if( (aPropAny1 >>= nLayerID1) && (aPropAny2 >>= nLayerID2) ) + { + if (nLayerID1 == nLayerID2) + { + uno::Any aAny1 = xProps1->getPropertyValue(msZOrder); + sal_Int32 nZOrder1 = 0; + uno::Any aAny2 = xProps2->getPropertyValue(msZOrder); + sal_Int32 nZOrder2 = 0; + if ( (aAny1 >>= nZOrder1) && (aAny2 >>= nZOrder2) ) + bResult = (nZOrder1 < nZOrder2); + } + else + { + ConvertLayerId(nLayerID1); + ConvertLayerId(nLayerID2); + bResult = (nLayerID1 < nLayerID2); + } + } + } + } + else if (pData1 && !pData2) + bResult = LessThanSheet(pData1); + else if (!pData1 && pData2) + bResult = !LessThanSheet(pData2); + else + bResult = sal_False; + return bResult; + } +}; + +struct DeselectShape +{ + void operator() (const ScAccessibleShapeData* pAccShapeData) const + { + if (pAccShapeData) + { + pAccShapeData->bSelected = sal_False; + if (pAccShapeData->pAccShape) + pAccShapeData->pAccShape->ResetState(AccessibleStateType::SELECTED); + } + } +}; + +struct SelectShape +{ + uno::Reference < drawing::XShapes > xShapes; + SelectShape(uno::Reference<drawing::XShapes>& xTemp) : xShapes(xTemp) {} + void operator() (const ScAccessibleShapeData* pAccShapeData) const + { + if (pAccShapeData && pAccShapeData->bSelectable) + { + pAccShapeData->bSelected = sal_True; + if (pAccShapeData->pAccShape) + pAccShapeData->pAccShape->SetState(AccessibleStateType::SELECTED); + if (xShapes.is()) + xShapes->add(pAccShapeData->xShape); + } + } +}; + +struct Destroy +{ + void operator() (ScAccessibleShapeData* pData) + { + if (pData) + DELETEZ(pData); + } +}; + +class ScChildrenShapes : public SfxListener, + public ::accessibility::IAccessibleParent +{ +public: + ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos); + ~ScChildrenShapes(); + + ///===== SfxListener ===================================================== + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + + ///===== IAccessibleParent =============================================== + + virtual sal_Bool ReplaceChild ( + ::accessibility::AccessibleShape* pCurrentChild, + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape, + const long _nIndex, + const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo + ) throw (::com::sun::star::uno::RuntimeException); + + ///===== Internal ======================================================== + void SetDrawBroadcaster(); + + sal_Int32 GetCount() const; + uno::Reference< XAccessible > Get(const ScAccessibleShapeData* pData) const; + uno::Reference< XAccessible > Get(sal_Int32 nIndex) const; + uno::Reference< XAccessible > GetAt(const awt::Point& rPoint) const; + + // gets the index of the shape starting on 0 (without the index of the table) + // returns the selected shape + sal_Bool IsSelected(sal_Int32 nIndex, + com::sun::star::uno::Reference<com::sun::star::drawing::XShape>& rShape) const; + + sal_Bool SelectionChanged(); + + void Select(sal_Int32 nIndex); + void DeselectAll(); // deselect also the table + void SelectAll(); + sal_Int32 GetSelectedCount() const; + uno::Reference< XAccessible > GetSelected(sal_Int32 nSelectedChildIndex, sal_Bool bTabSelected) const; + void Deselect(sal_Int32 nChildIndex); + + SdrPage* GetDrawPage() const; + + utl::AccessibleRelationSetHelper* GetRelationSet(const ScAddress* pAddress) const; + + void VisAreaChanged() const; +private: + typedef std::vector<ScAccessibleShapeData*> SortedShapes; + + mutable SortedShapes maZOrderedShapes; // a null pointer represents the sheet in the correct order + + mutable ::accessibility::AccessibleShapeTreeInfo maShapeTreeInfo; + mutable com::sun::star::uno::Reference<com::sun::star::view::XSelectionSupplier> xSelectionSupplier; + mutable sal_uInt32 mnSdrObjCount; + mutable sal_uInt32 mnShapesSelected; + ScTabViewShell* mpViewShell; + ScAccessibleDocument* mpAccessibleDocument; + ScSplitPos meSplitPos; + + void FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const; + sal_Bool FindSelectedShapesChanges(const com::sun::star::uno::Reference<com::sun::star::drawing::XShapes>& xShapes, sal_Bool bCommitChange) const; + void FillSelectionSupplier() const; + + ScAddress* GetAnchor(const uno::Reference<drawing::XShape>& xShape) const; + uno::Reference<XAccessibleRelationSet> GetRelationSet(const ScAccessibleShapeData* pData) const; + void CheckWhetherAnchorChanged(const uno::Reference<drawing::XShape>& xShape) const; + void SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const; + void AddShape(const uno::Reference<drawing::XShape>& xShape, sal_Bool bCommitChange) const; + void RemoveShape(const uno::Reference<drawing::XShape>& xShape) const; + + sal_Bool FindShape(const uno::Reference<drawing::XShape>& xShape, SortedShapes::iterator& rItr) const; + + sal_Int8 Compare(const ScAccessibleShapeData* pData1, + const ScAccessibleShapeData* pData2) const; +}; + +ScChildrenShapes::ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos) + : + mnShapesSelected(0), + mpViewShell(pViewShell), + mpAccessibleDocument(pAccessibleDocument), + meSplitPos(eSplitPos) +{ + FillSelectionSupplier(); + maZOrderedShapes.push_back(NULL); // add an element which represents the table + + GetCount(); // fill list with filtered shapes (no internal shapes) + + if (mnShapesSelected) + { + //set flag on every selected shape + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + uno::Reference<drawing::XShapes> xShapes(xSelectionSupplier->getSelection(), uno::UNO_QUERY); + if (xShapes.is()) + FindSelectedShapesChanges(xShapes, sal_False); + } + if (pViewShell) + { + SfxBroadcaster* pDrawBC = pViewShell->GetViewData()->GetDocument()->GetDrawBroadcaster(); + if (pDrawBC) + { + StartListening(*pDrawBC); + + maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(pViewShell->GetViewData()->GetDocument()->GetDrawLayer()) ); + maShapeTreeInfo.SetSdrView(pViewShell->GetViewData()->GetScDrawView()); + maShapeTreeInfo.SetController(NULL); + maShapeTreeInfo.SetWindow(pViewShell->GetWindowByPos(meSplitPos)); + maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument); + } + } +} + +ScChildrenShapes::~ScChildrenShapes() +{ + std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), Destroy()); + if (mpViewShell) + { + SfxBroadcaster* pDrawBC = mpViewShell->GetViewData()->GetDocument()->GetDrawBroadcaster(); + if (pDrawBC) + EndListening(*pDrawBC); + } +} + +void ScChildrenShapes::SetDrawBroadcaster() +{ + if (mpViewShell) + { + SfxBroadcaster* pDrawBC = mpViewShell->GetViewData()->GetDocument()->GetDrawBroadcaster(); + if (pDrawBC) + { + StartListening(*pDrawBC, TRUE); + + maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(mpViewShell->GetViewData()->GetDocument()->GetDrawLayer()) ); + maShapeTreeInfo.SetSdrView(mpViewShell->GetViewData()->GetScDrawView()); + maShapeTreeInfo.SetController(NULL); + maShapeTreeInfo.SetWindow(mpViewShell->GetWindowByPos(meSplitPos)); + maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument); + } + } +} + +void ScChildrenShapes::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + if ( rHint.ISA( SdrHint ) ) + { + const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); + if (pSdrHint) + { + SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject()); + if (pObj && /*(pObj->GetLayer() != SC_LAYER_INTERN) && */(pObj->GetPage() == GetDrawPage()) && + (pObj->GetPage() == pObj->GetObjList()) ) //#108480# only do something if the object lies direct on the page + { + switch (pSdrHint->GetKind()) + { + case HINT_OBJCHG : // Objekt geaendert + { + uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); + if (xShape.is()) + { + ScShapeDataLess aLess; + std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), aLess); // sort, because the z index or layer could be changed + CheckWhetherAnchorChanged(xShape); + } + } + break; + case HINT_OBJINSERTED : // Neues Zeichenobjekt eingefuegt + { + uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); + if (xShape.is()) + AddShape(xShape, sal_True); + } + break; + case HINT_OBJREMOVED : // Zeichenobjekt aus Liste entfernt + { + uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); + if (xShape.is()) + RemoveShape(xShape); + } + break; + default : + { + // other events are not interesting + } + break; + } + } + } + } +} + +sal_Bool ScChildrenShapes::ReplaceChild (::accessibility::AccessibleShape* pCurrentChild, + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape, + const long _nIndex, const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo) + throw (uno::RuntimeException) +{ + // create the new child + ::accessibility::AccessibleShape* pReplacement = ::accessibility::ShapeTypeHandler::Instance().CreateAccessibleObject ( + ::accessibility::AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this, _nIndex ), + _rShapeTreeInfo + ); + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xNewChild( pReplacement ); // keep this alive (do this before calling Init!) + if ( pReplacement ) + pReplacement->Init(); + + sal_Bool bResult(sal_False); + if (pCurrentChild && pReplacement) + { + DBG_ASSERT(pCurrentChild->GetXShape().get() == pReplacement->GetXShape().get(), "XShape changes and should be inserted sorted"); + SortedShapes::iterator aItr; + FindShape(pCurrentChild->GetXShape(), aItr); + if (aItr != maZOrderedShapes.end() && (*aItr)) + { + if ((*aItr)->pAccShape) + { + DBG_ASSERT((*aItr)->pAccShape == pCurrentChild, "wrong child found"); + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); + aEvent.OldValue <<= uno::makeAny(uno::Reference<XAccessible>(pCurrentChild)); + + mpAccessibleDocument->CommitChange(aEvent); // child is gone - event + + pCurrentChild->dispose(); + } + (*aItr)->pAccShape = pReplacement; + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); + aEvent.NewValue <<= uno::makeAny(uno::Reference<XAccessible>(pReplacement)); + + mpAccessibleDocument->CommitChange(aEvent); // child is new - event + bResult = sal_True; + } + } + return bResult; +} + +sal_Int32 ScChildrenShapes::GetCount() const +{ + SdrPage* pDrawPage = GetDrawPage(); + if (pDrawPage && (maZOrderedShapes.size() == 1)) // the table is always in + { + mnSdrObjCount = pDrawPage->GetObjCount(); + maZOrderedShapes.reserve(mnSdrObjCount + 1); // the table is always in + for (sal_uInt32 i = 0; i < mnSdrObjCount; ++i) + { + SdrObject* pObj = pDrawPage->GetObj(i); + if (pObj/* && (pObj->GetLayer() != SC_LAYER_INTERN)*/) + { + uno::Reference< drawing::XShape > xShape (pObj->getUnoShape(), uno::UNO_QUERY); + AddShape(xShape, sal_False); //inserts in the correct order + } + } + } + return maZOrderedShapes.size(); +} + +uno::Reference< XAccessible > ScChildrenShapes::Get(const ScAccessibleShapeData* pData) const +{ + if (!pData) + return NULL; + + if (!pData->pAccShape) + { + ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance(); + ::accessibility::AccessibleShapeInfo aShapeInfo(pData->xShape, mpAccessibleDocument, const_cast<ScChildrenShapes*>(this)); + pData->pAccShape = rShapeHandler.CreateAccessibleObject( + aShapeInfo, maShapeTreeInfo); + if (pData->pAccShape) + { + pData->pAccShape->acquire(); + pData->pAccShape->Init(); + if (pData->bSelected) + pData->pAccShape->SetState(AccessibleStateType::SELECTED); + if (!pData->bSelectable) + pData->pAccShape->ResetState(AccessibleStateType::SELECTABLE); + pData->pAccShape->SetRelationSet(GetRelationSet(pData)); + } + } + return pData->pAccShape; + } + +uno::Reference< XAccessible > ScChildrenShapes::Get(sal_Int32 nIndex) const +{ + if (maZOrderedShapes.size() <= 1) + GetCount(); // fill list with filtered shapes (no internal shapes) + + if (static_cast<sal_uInt32>(nIndex) >= maZOrderedShapes.size()) + return NULL; + + return Get(maZOrderedShapes[nIndex]); +} + +uno::Reference< XAccessible > ScChildrenShapes::GetAt(const awt::Point& rPoint) const +{ + uno::Reference<XAccessible> xAccessible; + if(mpViewShell) + { + sal_Int32 i(maZOrderedShapes.size() - 1); + sal_Bool bFound(sal_False); + while (!bFound && i >= 0) + { + ScAccessibleShapeData* pShape = maZOrderedShapes[i]; + if (pShape) + { + if (!pShape->pAccShape) + Get(pShape); + + if (pShape->pAccShape) + { + Point aPoint(VCLPoint(rPoint)); + aPoint -= VCLRectangle(pShape->pAccShape->getBounds()).TopLeft(); + if (pShape->pAccShape->containsPoint(AWTPoint(aPoint))) + { + xAccessible = pShape->pAccShape; + bFound = sal_True; + } + } + else + { + DBG_ERRORFILE("I should have an accessible shape now!"); + } + } + else + bFound = sal_True; // this is the sheet and it lies before the rest of the shapes which are background shapes + + --i; + } + } + return xAccessible; +} + +sal_Bool ScChildrenShapes::IsSelected(sal_Int32 nIndex, + uno::Reference<drawing::XShape>& rShape) const +{ + sal_Bool bResult (sal_False); + if (maZOrderedShapes.size() <= 1) + GetCount(); // fill list with filtered shapes (no internal shapes) + + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + if (!maZOrderedShapes[nIndex]) + return sal_False; + + bResult = maZOrderedShapes[nIndex]->bSelected; + rShape = maZOrderedShapes[nIndex]->xShape; + +#ifdef DBG_UTIL // test whether it is truly selected by a slower method + uno::Reference< drawing::XShape > xReturnShape; + sal_Bool bDebugResult(sal_False); + uno::Reference<container::XIndexAccess> xIndexAccess; + xSelectionSupplier->getSelection() >>= xIndexAccess; + + if (xIndexAccess.is()) + { + sal_Int32 nCount(xIndexAccess->getCount()); + if (nCount) + { + uno::Reference< drawing::XShape > xShape; + uno::Reference< drawing::XShape > xIndexShape = maZOrderedShapes[nIndex]->xShape; + sal_Int32 i(0); + while (!bDebugResult && (i < nCount)) + { + xIndexAccess->getByIndex(i) >>= xShape; + if (xShape.is() && (xIndexShape.get() == xShape.get())) + { + bDebugResult = sal_True; + xReturnShape = xShape; + } + else + ++i; + } + } + } + DBG_ASSERT((bResult == bDebugResult) && ((bResult && (rShape.get() == xReturnShape.get())) || !bResult), "found the wrong shape or result"); +#endif + + return bResult; +} + +sal_Bool ScChildrenShapes::SelectionChanged() +{ + sal_Bool bResult(sal_False); + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + uno::Reference<drawing::XShapes> xShapes(xSelectionSupplier->getSelection(), uno::UNO_QUERY); + + bResult = FindSelectedShapesChanges(xShapes, sal_True); + + return bResult; +} + +void ScChildrenShapes::Select(sal_Int32 nIndex) +{ + if (maZOrderedShapes.size() <= 1) + GetCount(); // fill list with filtered shapes (no internal shapes) + + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + if (!maZOrderedShapes[nIndex]) + return; + + uno::Reference<drawing::XShape> xShape; + if (!IsSelected(nIndex, xShape) && maZOrderedShapes[nIndex]->bSelectable) + { + uno::Reference<drawing::XShapes> xShapes; + xSelectionSupplier->getSelection() >>= xShapes; + + if (!xShapes.is()) + xShapes = new SvxShapeCollection(); + + xShapes->add(maZOrderedShapes[nIndex]->xShape); + + try + { + xSelectionSupplier->select(uno::makeAny(xShapes)); + maZOrderedShapes[nIndex]->bSelected = sal_True; + if (maZOrderedShapes[nIndex]->pAccShape) + maZOrderedShapes[nIndex]->pAccShape->SetState(AccessibleStateType::SELECTED); + } + catch (lang::IllegalArgumentException&) + { + } + } +} + +void ScChildrenShapes::DeselectAll() +{ + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + sal_Bool bSomethingSelected(sal_True); + try + { + xSelectionSupplier->select(uno::Any()); //deselects all + } + catch (lang::IllegalArgumentException&) + { + DBG_ERRORFILE("nothing selected before"); + bSomethingSelected = sal_False; + } + + if (bSomethingSelected) + std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), DeselectShape()); +} + +void ScChildrenShapes::SelectAll() +{ + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + if (maZOrderedShapes.size() <= 1) + GetCount(); // fill list with filtered shapes (no internal shapes) + + if (maZOrderedShapes.size() > 1) + { + uno::Reference<drawing::XShapes> xShapes; + xShapes = new SvxShapeCollection(); + + try + { + std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), SelectShape(xShapes)); + xSelectionSupplier->select(uno::makeAny(xShapes)); + } + catch (lang::IllegalArgumentException&) + { + SelectionChanged(); // find all selected shapes and set the flags + } + } +} + +void ScChildrenShapes::FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const +{ + uno::Reference<container::XIndexAccess> xIndexAccess; + xSelectionSupplier->getSelection() >>= xIndexAccess; + + if (xIndexAccess.is()) + { + sal_uInt32 nCount(xIndexAccess->getCount()); + for (sal_uInt32 i = 0; i < nCount; ++i) + { + uno::Reference<drawing::XShape> xShape; + xIndexAccess->getByIndex(i) >>= xShape; + if (xShape.is()) + rShapes.push_back(xShape); + } + } +} + +sal_Int32 ScChildrenShapes::GetSelectedCount() const +{ + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + std::vector < uno::Reference < drawing::XShape > > aShapes; + FillShapes(aShapes); + + return aShapes.size(); +} + +uno::Reference< XAccessible > ScChildrenShapes::GetSelected(sal_Int32 nSelectedChildIndex, sal_Bool bTabSelected) const +{ + uno::Reference< XAccessible > xAccessible; + + if (maZOrderedShapes.size() <= 1) + GetCount(); // fill list with shapes + + if (!bTabSelected) + { + std::vector < uno::Reference < drawing::XShape > > aShapes; + FillShapes(aShapes); + + SortedShapes::iterator aItr; + if (FindShape(aShapes[nSelectedChildIndex], aItr)) + xAccessible = Get(aItr - maZOrderedShapes.begin()); + } + else + { + SortedShapes::iterator aItr = maZOrderedShapes.begin(); + SortedShapes::iterator aEndItr = maZOrderedShapes.end(); + sal_Bool bFound(sal_False); + while(!bFound && aItr != aEndItr) + { + if (*aItr) + { + if ((*aItr)->bSelected) + { + if (nSelectedChildIndex == 0) + bFound = sal_True; + else + --nSelectedChildIndex; + } + } + else + { + if (nSelectedChildIndex == 0) + bFound = sal_True; + else + --nSelectedChildIndex; + } + if (!bFound) + ++aItr; + } + if (bFound && *aItr) + xAccessible = (*aItr)->pAccShape; + } + + return xAccessible; +} + +void ScChildrenShapes::Deselect(sal_Int32 nChildIndex) +{ + uno::Reference<drawing::XShape> xShape; + if (IsSelected(nChildIndex, xShape)) // returns false if it is the sheet + { + if (xShape.is()) + { + uno::Reference<drawing::XShapes> xShapes; + xSelectionSupplier->getSelection() >>= xShapes; + if (xShapes.is()) + xShapes->remove(xShape); + + try + { + xSelectionSupplier->select(uno::makeAny(xShapes)); + } + catch (lang::IllegalArgumentException&) + { + DBG_ERRORFILE("something not selectable"); + } + + maZOrderedShapes[nChildIndex]->bSelected = sal_False; + if (maZOrderedShapes[nChildIndex]->pAccShape) + maZOrderedShapes[nChildIndex]->pAccShape->ResetState(AccessibleStateType::SELECTED); + } + } +} + + +SdrPage* ScChildrenShapes::GetDrawPage() const +{ + SCTAB nTab(mpAccessibleDocument->getVisibleTable()); + SdrPage* pDrawPage = NULL; + if (mpViewShell) + { + ScDocument* pDoc = mpViewShell->GetViewData()->GetDocument(); + if (pDoc && pDoc->GetDrawLayer()) + { + ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer(); + if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab)) + pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab))); + } + } + return pDrawPage; +} + +struct SetRelation +{ + const ScChildrenShapes* mpChildrenShapes; + mutable utl::AccessibleRelationSetHelper* mpRelationSet; + const ScAddress* mpAddress; + SetRelation(const ScChildrenShapes* pChildrenShapes, const ScAddress* pAddress) + : + mpChildrenShapes(pChildrenShapes), + mpRelationSet(NULL), + mpAddress(pAddress) + { + } + void operator() (const ScAccessibleShapeData* pAccShapeData) const + { + if (pAccShapeData && + ((!pAccShapeData->pRelationCell && !mpAddress) || + (pAccShapeData->pRelationCell && mpAddress && (*(pAccShapeData->pRelationCell) == *mpAddress)))) + { + if (!mpRelationSet) + mpRelationSet = new utl::AccessibleRelationSetHelper(); + + AccessibleRelation aRelation; + aRelation.TargetSet.realloc(1); + aRelation.TargetSet[0] = mpChildrenShapes->Get(pAccShapeData); + aRelation.RelationType = AccessibleRelationType::CONTROLLER_FOR; + + mpRelationSet->AddRelation(aRelation); + } + } +}; + +utl::AccessibleRelationSetHelper* ScChildrenShapes::GetRelationSet(const ScAddress* pAddress) const +{ + SetRelation aSetRelation(this, pAddress); + ::std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), aSetRelation); + return aSetRelation.mpRelationSet; +} + +sal_Bool ScChildrenShapes::FindSelectedShapesChanges(const uno::Reference<drawing::XShapes>& xShapes, sal_Bool /* bCommitChange */) const +{ + sal_Bool bResult(sal_False); + SortedShapes aShapesList; + uno::Reference<container::XIndexAccess> xIndexAcc(xShapes, uno::UNO_QUERY); + if (xIndexAcc.is()) + { + mnShapesSelected = xIndexAcc->getCount(); + for (sal_uInt32 i = 0; i < mnShapesSelected; ++i) + { + uno::Reference< drawing::XShape > xShape; + xIndexAcc->getByIndex(i) >>= xShape; + if (xShape.is()) + { + ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData(); + pShapeData->xShape = xShape; + aShapesList.push_back(pShapeData); + } + } + } + else + mnShapesSelected = 0; + ScShapeDataLess aLess; + std::sort(aShapesList.begin(), aShapesList.end(), aLess); + + SortedShapes::iterator aXShapesItr(aShapesList.begin()); + SortedShapes::const_iterator aXShapesEndItr(aShapesList.end()); + SortedShapes::iterator aDataItr(maZOrderedShapes.begin()); + SortedShapes::const_iterator aDataEndItr(maZOrderedShapes.end()); + SortedShapes::const_iterator aFocusedItr = aDataEndItr; + while((aDataItr != aDataEndItr)) + { + if (*aDataItr) // is it realy a shape or only the sheet + { + sal_Int8 nComp(0); + if (aXShapesItr == aXShapesEndItr) + nComp = -1; // simulate that the Shape is lower, so the selction state will be removed + else + nComp = Compare(*aDataItr, *aXShapesItr); + if (nComp == 0) + { + if (!(*aDataItr)->bSelected) + { + (*aDataItr)->bSelected = sal_True; + if ((*aDataItr)->pAccShape) + { + (*aDataItr)->pAccShape->SetState(AccessibleStateType::SELECTED); + (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED); + bResult = sal_True; + } + aFocusedItr = aDataItr; + } + ++aDataItr; + ++aXShapesItr; + } + else if (nComp < 0) + { + if ((*aDataItr)->bSelected) + { + (*aDataItr)->bSelected = sal_False; + if ((*aDataItr)->pAccShape) + { + (*aDataItr)->pAccShape->ResetState(AccessibleStateType::SELECTED); + (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED); + bResult = sal_True; + } + } + ++aDataItr; + } + else + { + DBG_ERRORFILE("here is a selected shape which is not in the childlist"); + ++aXShapesItr; + --mnShapesSelected; + } + } + else + ++aDataItr; + } + if ((aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape && (mnShapesSelected == 1)) + (*aFocusedItr)->pAccShape->SetState(AccessibleStateType::FOCUSED); + + std::for_each(aShapesList.begin(), aShapesList.end(), Destroy()); + + return bResult; +} + +void ScChildrenShapes::FillSelectionSupplier() const +{ + if (!xSelectionSupplier.is() && mpViewShell) + { + SfxViewFrame* pViewFrame = mpViewShell->GetViewFrame(); + if (pViewFrame) + { + xSelectionSupplier = uno::Reference<view::XSelectionSupplier>(pViewFrame->GetFrame().GetController(), uno::UNO_QUERY); + if (xSelectionSupplier.is()) + { + if (mpAccessibleDocument) + xSelectionSupplier->addSelectionChangeListener(mpAccessibleDocument); + uno::Reference<drawing::XShapes> xShapes (xSelectionSupplier->getSelection(), uno::UNO_QUERY); + if (xShapes.is()) + mnShapesSelected = xShapes->getCount(); + } + } + } +} + +ScAddress* ScChildrenShapes::GetAnchor(const uno::Reference<drawing::XShape>& xShape) const +{ + ScAddress* pAddress = NULL; + if (mpViewShell) + { + SvxShape* pShapeImp = SvxShape::getImplementation(xShape); + uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY); + if (pShapeImp && xShapeProp.is()) + { + SdrObject *pSdrObj = pShapeImp->GetSdrObject(); + if (pSdrObj) + { + if (ScDrawLayer::GetAnchor(pSdrObj) == SCA_CELL) + { + ScDocument* pDoc = mpViewShell->GetViewData()->GetDocument(); + if (pDoc) + { + rtl::OUString sCaptionShape(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.CaptionShape")); + awt::Point aPoint(xShape->getPosition()); + awt::Size aSize(xShape->getSize()); + rtl::OUString sType(xShape->getShapeType()); + Rectangle aRectangle(aPoint.X, aPoint.Y, aPoint.X + aSize.Width, aPoint.Y + aSize.Height); + if ( sType.equals(sCaptionShape) ) + { + awt::Point aRelativeCaptionPoint; + rtl::OUString sCaptionPoint( RTL_CONSTASCII_USTRINGPARAM( "CaptionPoint" )); + xShapeProp->getPropertyValue( sCaptionPoint ) >>= aRelativeCaptionPoint; + Point aCoreRelativeCaptionPoint(aRelativeCaptionPoint.X, aRelativeCaptionPoint.Y); + Point aCoreAbsoluteCaptionPoint(aPoint.X, aPoint.Y); + aCoreAbsoluteCaptionPoint += aCoreRelativeCaptionPoint; + aRectangle.Union(Rectangle(aCoreAbsoluteCaptionPoint, aCoreAbsoluteCaptionPoint)); + } + ScRange aRange = pDoc->GetRange(mpAccessibleDocument->getVisibleTable(), aRectangle); + pAddress = new ScAddress(aRange.aStart); + } + } +// else +// do nothing, because it is always a NULL Pointer + } + } + } + + return pAddress; +} + +uno::Reference<XAccessibleRelationSet> ScChildrenShapes::GetRelationSet(const ScAccessibleShapeData* pData) const +{ + utl::AccessibleRelationSetHelper* pRelationSet = new utl::AccessibleRelationSetHelper(); + + if(pData && pRelationSet && mpAccessibleDocument) + { + uno::Reference<XAccessible> xAccessible = mpAccessibleDocument->GetAccessibleSpreadsheet(); // should be the current table + if (pData->pRelationCell && xAccessible.is()) + { + uno::Reference<XAccessibleTable> xAccTable (xAccessible->getAccessibleContext(), uno::UNO_QUERY); + if (xAccTable.is()) + xAccessible = xAccTable->getAccessibleCellAt(pData->pRelationCell->Row(), pData->pRelationCell->Col()); + } + AccessibleRelation aRelation; + aRelation.TargetSet.realloc(1); + aRelation.TargetSet[0] = xAccessible; + aRelation.RelationType = AccessibleRelationType::CONTROLLED_BY; + pRelationSet->AddRelation(aRelation); + } + + return pRelationSet; +} + +void ScChildrenShapes::CheckWhetherAnchorChanged(const uno::Reference<drawing::XShape>& xShape) const +{ + SortedShapes::iterator aItr; + if (FindShape(xShape, aItr)) + SetAnchor(xShape, *aItr); +} + +void ScChildrenShapes::SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const +{ + if (pData) + { + ScAddress* pAddress = GetAnchor(xShape); + if ((pAddress && pData->pRelationCell && (*pAddress != *(pData->pRelationCell))) || + (!pAddress && pData->pRelationCell) || (pAddress && !pData->pRelationCell)) + { + if (pData->pRelationCell) + delete pData->pRelationCell; + pData->pRelationCell = pAddress; + if (pData->pAccShape) + pData->pAccShape->SetRelationSet(GetRelationSet(pData)); + } + } +} + +void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, sal_Bool bCommitChange) const +{ + SortedShapes::iterator aFindItr; + if (!FindShape(xShape, aFindItr)) + { + ScAccessibleShapeData* pShape = new ScAccessibleShapeData(); + pShape->xShape = xShape; + SortedShapes::iterator aNewItr = maZOrderedShapes.insert(aFindItr, pShape); + SetAnchor(xShape, pShape); + + uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY); + if (xShapeProp.is()) + { + uno::Any aPropAny = xShapeProp->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "LayerID" ))); + sal_Int16 nLayerID = 0; + if( aPropAny >>= nLayerID ) + { + if( (nLayerID == SC_LAYER_INTERN) || (nLayerID == SC_LAYER_HIDDEN) ) + pShape->bSelectable = sal_False; + else + pShape->bSelectable = sal_True; + } + } + + + if (!xSelectionSupplier.is()) + throw uno::RuntimeException(); + + uno::Reference<container::XEnumerationAccess> xEnumAcc(xSelectionSupplier->getSelection(), uno::UNO_QUERY); + if (xEnumAcc.is()) + { + uno::Reference<container::XEnumeration> xEnum = xEnumAcc->createEnumeration(); + if (xEnum.is()) + { + uno::Reference<drawing::XShape> xSelectedShape; + sal_Bool bFound(sal_False); + while (!bFound && xEnum->hasMoreElements()) + { + xEnum->nextElement() >>= xSelectedShape; + if (xShape.is() && (xShape.get() == xSelectedShape.get())) + { + pShape->bSelected = sal_True; + bFound = sal_True; + } + } + } + } + if (mpAccessibleDocument && bCommitChange) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); + aEvent.NewValue <<= Get(aNewItr - maZOrderedShapes.begin()); + + mpAccessibleDocument->CommitChange(aEvent); // new child - event + } + } + else + { + DBG_ERRORFILE("shape is always in the list"); + } +} + +void ScChildrenShapes::RemoveShape(const uno::Reference<drawing::XShape>& xShape) const +{ + SortedShapes::iterator aItr; + if (FindShape(xShape, aItr)) + { + if (mpAccessibleDocument) + { + uno::Reference<XAccessible> xOldAccessible (Get(aItr - maZOrderedShapes.begin())); + + delete *aItr; + maZOrderedShapes.erase(aItr); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument); + aEvent.OldValue <<= uno::makeAny(xOldAccessible); + + mpAccessibleDocument->CommitChange(aEvent); // child is gone - event + } + else + { + delete *aItr; + maZOrderedShapes.erase(aItr); + } + } + else + { + DBG_ERRORFILE("shape was not in internal list"); + } +} + +sal_Bool ScChildrenShapes::FindShape(const uno::Reference<drawing::XShape>& xShape, ScChildrenShapes::SortedShapes::iterator& rItr) const +{ + sal_Bool bResult(sal_False); + ScAccessibleShapeData aShape; + aShape.xShape = xShape; + ScShapeDataLess aLess; + rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, aLess); + if ((rItr != maZOrderedShapes.end()) && (*rItr != NULL) && ((*rItr)->xShape.get() == xShape.get())) + bResult = sal_True; // if the shape is found + +#ifdef DBG_UTIL // test whether it finds truly the correct shape (perhaps it is not really sorted) + SortedShapes::iterator aDebugItr = maZOrderedShapes.begin(); + SortedShapes::iterator aEndItr = maZOrderedShapes.end(); + sal_Bool bFound(sal_False); + while (!bFound && aDebugItr != aEndItr) + { + if (*aDebugItr && ((*aDebugItr)->xShape.get() == xShape.get())) + bFound = sal_True; + else + ++aDebugItr; + } + sal_Bool bResult2 = (aDebugItr != maZOrderedShapes.end()); + DBG_ASSERT((bResult == bResult2) && ((bResult && (rItr == aDebugItr)) || !bResult), "wrong Shape found"); +#endif + return bResult; +} + +sal_Int8 ScChildrenShapes::Compare(const ScAccessibleShapeData* pData1, + const ScAccessibleShapeData* pData2) const +{ + ScShapeDataLess aLess; + + sal_Bool bResult1(aLess(pData1, pData2)); + sal_Bool bResult2(aLess(pData2, pData1)); + + sal_Int8 nResult(0); + if (!bResult1 && bResult2) + nResult = 1; + else if (bResult1 && !bResult2) + nResult = -1; + + return nResult; +} + +struct ScVisAreaChanged +{ + ScAccessibleDocument* mpAccDoc; + ScVisAreaChanged(ScAccessibleDocument* pAccDoc) : mpAccDoc(pAccDoc) {} + void operator() (const ScAccessibleShapeData* pAccShapeData) const + { + if (pAccShapeData && pAccShapeData->pAccShape) + { + pAccShapeData->pAccShape->ViewForwarderChanged(::accessibility::IAccessibleViewForwarderListener::VISIBLE_AREA, mpAccDoc); + } + } +}; + +void ScChildrenShapes::VisAreaChanged() const +{ + ScVisAreaChanged aVisAreaChanged(mpAccessibleDocument); + std::for_each(maZOrderedShapes.begin(), maZOrderedShapes.end(), aVisAreaChanged); +} + +// ============================================================================ + +ScAccessibleDocument::ScAccessibleDocument( + const uno::Reference<XAccessible>& rxParent, + ScTabViewShell* pViewShell, + ScSplitPos eSplitPos) + : ScAccessibleDocumentBase(rxParent), + mpViewShell(pViewShell), + meSplitPos(eSplitPos), + mpAccessibleSpreadsheet(NULL), + mpChildrenShapes(NULL), + mpTempAccEdit(NULL), + mbCompleteSheetSelected(sal_False) +{ + if (pViewShell) + { + pViewShell->AddAccessibilityObject(*this); + Window *pWin = pViewShell->GetWindowByPos(eSplitPos); + if( pWin ) + { + pWin->AddChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener )); + USHORT nCount = pWin->GetChildCount(); + for( sal_uInt16 i=0; i < nCount; ++i ) + { + Window *pChildWin = pWin->GetChild( i ); + if( pChildWin && + AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) + AddChild( pChildWin->GetAccessible(), sal_False ); + } + } + if (pViewShell->GetViewData()->HasEditView( eSplitPos )) + { + uno::Reference<XAccessible> xAcc = new ScAccessibleEditObject(this, pViewShell->GetViewData()->GetEditView(eSplitPos), + pViewShell->GetWindowByPos(eSplitPos), GetCurrentCellName(), GetCurrentCellDescription(), + CellInEditMode); + AddChild(xAcc, sal_False); + } + } + maVisArea = GetVisibleArea_Impl(); +} + +void ScAccessibleDocument::Init() +{ + if(!mpChildrenShapes) + mpChildrenShapes = new ScChildrenShapes(this, mpViewShell, meSplitPos); +} + +ScAccessibleDocument::~ScAccessibleDocument(void) +{ + if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + dispose(); + } +} + +void SAL_CALL ScAccessibleDocument::disposing() +{ + ScUnoGuard aGuard; + FreeAccessibleSpreadsheet(); + if (mpViewShell) + { + Window *pWin = mpViewShell->GetWindowByPos(meSplitPos); + if( pWin ) + pWin->RemoveChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener )); + + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + if (mpChildrenShapes) + DELETEZ(mpChildrenShapes); + + ScAccessibleDocumentBase::disposing(); +} + +void SAL_CALL ScAccessibleDocument::disposing( const lang::EventObject& /* Source */ ) + throw (uno::RuntimeException) +{ + disposing(); +} + + //===== SfxListener ===================================================== + +IMPL_LINK( ScAccessibleDocument, WindowChildEventListener, VclSimpleEvent*, pEvent ) +{ + DBG_ASSERT( pEvent && pEvent->ISA( VclWindowEvent ), "Unknown WindowEvent!" ); + if ( pEvent && pEvent->ISA( VclWindowEvent ) ) + { + VclWindowEvent *pVclEvent = static_cast< VclWindowEvent * >( pEvent ); + DBG_ASSERT( pVclEvent->GetWindow(), "Window???" ); + switch ( pVclEvent->GetId() ) + { + case VCLEVENT_WINDOW_SHOW: // send create on show for direct accessible children + { + Window* pChildWin = static_cast < Window * >( pVclEvent->GetData() ); + if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) + { + AddChild( pChildWin->GetAccessible(), sal_True ); + } + } + break; + case VCLEVENT_WINDOW_HIDE: // send destroy on hide for direct accessible children + { + Window* pChildWin = static_cast < Window * >( pVclEvent->GetData() ); + if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() ) + { + RemoveChild( pChildWin->GetAccessible(), sal_True ); + } + } + break; + } + } + return 0; +} + +void ScAccessibleDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.ISA( ScAccGridWinFocusLostHint ) ) + { + const ScAccGridWinFocusLostHint& rRef = (const ScAccGridWinFocusLostHint&)rHint; + if (rRef.GetOldGridWin() == meSplitPos) + { + if (mxTempAcc.is() && mpTempAccEdit) + mpTempAccEdit->LostFocus(); + else if (mpAccessibleSpreadsheet) + mpAccessibleSpreadsheet->LostFocus(); + else + CommitFocusLost(); + } + } + else if (rHint.ISA( ScAccGridWinFocusGotHint ) ) + { + const ScAccGridWinFocusGotHint& rRef = (const ScAccGridWinFocusGotHint&)rHint; + if (rRef.GetNewGridWin() == meSplitPos) + { + if (mxTempAcc.is() && mpTempAccEdit) + mpTempAccEdit->GotFocus(); + else if (mpAccessibleSpreadsheet) + mpAccessibleSpreadsheet->GotFocus(); + else + CommitFocusGained(); + } + } + else if (rHint.ISA( SfxSimpleHint )) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + // only notify if child exist, otherwise it is not necessary + if ((rRef.GetId() == SC_HINT_ACC_TABLECHANGED) && + mpAccessibleSpreadsheet) + { + FreeAccessibleSpreadsheet(); + if (mpChildrenShapes) + DELETEZ(mpChildrenShapes); + + // #124567# Accessibility: Shapes / form controls after reload not accessible + if ( !mpChildrenShapes ) + { + mpChildrenShapes = new ScChildrenShapes( this, mpViewShell, meSplitPos ); + } + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::INVALIDATE_ALL_CHILDREN; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + CommitChange(aEvent); // all childs changed + } + else if (rRef.GetId() == SC_HINT_ACC_MAKEDRAWLAYER) + { + if (mpChildrenShapes) + mpChildrenShapes->SetDrawBroadcaster(); + } + else if ((rRef.GetId() == SC_HINT_ACC_ENTEREDITMODE)) // this event comes only on creating edit field of a cell + { + if (mpViewShell && mpViewShell->GetViewData()->HasEditView(meSplitPos)) + { + mpTempAccEdit = new ScAccessibleEditObject(this, mpViewShell->GetViewData()->GetEditView(meSplitPos), + mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), + rtl::OUString(String(ScResId(STR_ACC_EDITLINE_DESCR))), CellInEditMode); + uno::Reference<XAccessible> xAcc = mpTempAccEdit; + + AddChild(xAcc, sal_True); + + if (mpAccessibleSpreadsheet) + mpAccessibleSpreadsheet->LostFocus(); + else + CommitFocusLost(); + + mpTempAccEdit->GotFocus(); + } + } + else if (rRef.GetId() == SC_HINT_ACC_LEAVEEDITMODE) + { + if (mxTempAcc.is()) + { + if (mpTempAccEdit) + mpTempAccEdit->LostFocus(); + + mpTempAccEdit = NULL; + RemoveChild(mxTempAcc, sal_True); + + if (mpAccessibleSpreadsheet) + mpAccessibleSpreadsheet->GotFocus(); + else + CommitFocusGained(); + } + } + else if ((rRef.GetId() == SC_HINT_ACC_VISAREACHANGED) || (rRef.GetId() == SC_HINT_ACC_WINDOWRESIZED)) + { + Rectangle aOldVisArea(maVisArea); + maVisArea = GetVisibleArea_Impl(); + + if (maVisArea != aOldVisArea) + { + if (maVisArea.GetSize() != aOldVisArea.GetSize()) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + CommitChange(aEvent); + + if (mpAccessibleSpreadsheet) + mpAccessibleSpreadsheet->BoundingBoxChanged(); + } + else if (mpAccessibleSpreadsheet) + { + mpAccessibleSpreadsheet->VisAreaChanged(); + } + if (mpChildrenShapes) + mpChildrenShapes->VisAreaChanged(); + } + } + } + + ScAccessibleDocumentBase::Notify(rBC, rHint); +} + +void SAL_CALL ScAccessibleDocument::selectionChanged( const lang::EventObject& /* aEvent */ ) + throw (uno::RuntimeException) +{ + sal_Bool bSelectionChanged(sal_False); + if (mpAccessibleSpreadsheet) + { + sal_Bool bOldSelected(mbCompleteSheetSelected); + mbCompleteSheetSelected = IsTableSelected(); + if (bOldSelected != mbCompleteSheetSelected) + { + mpAccessibleSpreadsheet->CompleteSelectionChanged(mbCompleteSheetSelected); + bSelectionChanged = sal_True; + } + } + + if (mpChildrenShapes && mpChildrenShapes->SelectionChanged()) + bSelectionChanged = sal_True; + + if (bSelectionChanged) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + CommitChange(aEvent); + } +} + + //===== XInterface ===================================================== + +uno::Any SAL_CALL ScAccessibleDocument::queryInterface( uno::Type const & rType ) + throw (uno::RuntimeException) +{ + uno::Any aAny (ScAccessibleDocumentImpl::queryInterface(rType)); + return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType); +} + +void SAL_CALL ScAccessibleDocument::acquire() + throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessibleDocument::release() + throw () +{ + ScAccessibleContextBase::release(); +} + + //===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessibleDocument::getAccessibleAtPoint( + const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xAccessible = NULL; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + if (mpChildrenShapes) + xAccessible = mpChildrenShapes->GetAt(rPoint); + if(!xAccessible.is()) + { + if (mxTempAcc.is()) + { + uno::Reference< XAccessibleContext > xCont(mxTempAcc->getAccessibleContext()); + uno::Reference< XAccessibleComponent > xComp(xCont, uno::UNO_QUERY); + if (xComp.is()) + { + Rectangle aBound(VCLRectangle(xComp->getBounds())); + if (aBound.IsInside(VCLPoint(rPoint))) + xAccessible = mxTempAcc; + } + } + if (!xAccessible.is()) + xAccessible = GetAccessibleSpreadsheet(); + } + } + return xAccessible; +} + +void SAL_CALL ScAccessibleDocument::grabFocus( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + { + xAccessibleComponent->grabFocus(); + // grab only focus if it does not have the focus and it is not hidden + if (mpViewShell && mpViewShell->GetViewData() && + (mpViewShell->GetViewData()->GetActivePart() != meSplitPos) && + mpViewShell->GetWindowByPos(meSplitPos)->IsVisible()) + { + mpViewShell->ActivatePart(meSplitPos); + } + } + } +} + + //===== XAccessibleContext ============================================== + + /// Return the number of currently visible children. +sal_Int32 SAL_CALL + ScAccessibleDocument::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nCount(1); + if (mpChildrenShapes) + nCount = mpChildrenShapes->GetCount(); // returns the count of the shapes inclusive the table + + if (mxTempAcc.is()) + ++nCount; + + return nCount; +} + + /// Return the specified child or NULL if index is invalid. +uno::Reference<XAccessible> SAL_CALL + ScAccessibleDocument::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, + lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Reference<XAccessible> xAccessible; + if (nIndex >= 0) + { + sal_Int32 nCount(1); + if (mpChildrenShapes) + { + xAccessible = mpChildrenShapes->Get(nIndex); // returns NULL if it is the table or out of range + nCount = mpChildrenShapes->GetCount(); //there is always a table + } + if (!xAccessible.is()) + { + if (nIndex < nCount) + xAccessible = GetAccessibleSpreadsheet(); + else if (nIndex == nCount && mxTempAcc.is()) + xAccessible = mxTempAcc; + } + } + + if (!xAccessible.is()) + throw lang::IndexOutOfBoundsException(); + + return xAccessible; +} + + /// Return the set of current states. +uno::Reference<XAccessibleStateSet> SAL_CALL + ScAccessibleDocument::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc(xParentStates)) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + if (IsEditable(xParentStates)) + pStateSet->AddState(AccessibleStateType::EDITABLE); + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::OPAQUE); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + + ///===== XAccessibleSelection =========================================== + +void SAL_CALL + ScAccessibleDocument::selectAccessibleChild( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (mpChildrenShapes) + { + sal_Int32 nCount(mpChildrenShapes->GetCount()); //all shapes and the table + if (mxTempAcc.is()) + ++nCount; + if (nChildIndex < 0 || nChildIndex >= nCount) + throw lang::IndexOutOfBoundsException(); + + uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex); + if (xAccessible.is()) + { + sal_Bool bWasTableSelected(IsTableSelected()); + + if (mpChildrenShapes) + mpChildrenShapes->Select(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is to high + + if (bWasTableSelected) + mpViewShell->SelectAll(); + } + else + { + if (mpViewShell) + mpViewShell->SelectAll(); + } + } +} + +sal_Bool SAL_CALL + ScAccessibleDocument::isAccessibleChildSelected( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Bool bResult(sal_False); + + if (mpChildrenShapes) + { + sal_Int32 nCount(mpChildrenShapes->GetCount()); //all shapes and the table + if (mxTempAcc.is()) + ++nCount; + if (nChildIndex < 0 || nChildIndex >= nCount) + throw lang::IndexOutOfBoundsException(); + + uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex); + if (xAccessible.is()) + { + uno::Reference<drawing::XShape> xShape; + bResult = mpChildrenShapes->IsSelected(nChildIndex, xShape); // throws no lang::IndexOutOfBoundsException if Index is to high + } + else + { + if (mxTempAcc.is() && nChildIndex == nCount) + bResult = sal_True; + else + bResult = IsTableSelected(); + } + } + return bResult; +} + +void SAL_CALL + ScAccessibleDocument::clearAccessibleSelection( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (mpChildrenShapes) + mpChildrenShapes->DeselectAll(); //deselects all (also the table) +} + +void SAL_CALL + ScAccessibleDocument::selectAllAccessibleChildren( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (mpChildrenShapes) + mpChildrenShapes->SelectAll(); + + // select table after shapes, because while selecting shapes the table will be deselected + if (mpViewShell) + { + mpViewShell->SelectAll(); + } +} + +sal_Int32 SAL_CALL + ScAccessibleDocument::getSelectedAccessibleChildCount( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nCount(0); + + if (mpChildrenShapes) + nCount = mpChildrenShapes->GetSelectedCount(); + + if (IsTableSelected()) + ++nCount; + + if (mxTempAcc.is()) + ++nCount; + + return nCount; +} + +uno::Reference<XAccessible > SAL_CALL + ScAccessibleDocument::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Reference<XAccessible> xAccessible; + if (mpChildrenShapes) + { + sal_Int32 nCount(getSelectedAccessibleChildCount()); //all shapes and the table + if (nSelectedChildIndex < 0 || nSelectedChildIndex >= nCount) + throw lang::IndexOutOfBoundsException(); + + sal_Bool bTabMarked(IsTableSelected()); + + if (mpChildrenShapes) + xAccessible = mpChildrenShapes->GetSelected(nSelectedChildIndex, bTabMarked); // throws no lang::IndexOutOfBoundsException if Index is to high + if (mxTempAcc.is() && nSelectedChildIndex == nCount - 1) + xAccessible = mxTempAcc; + else if (bTabMarked) + xAccessible = GetAccessibleSpreadsheet(); + } + + DBG_ASSERT(xAccessible.is(), "here should always be an accessible object or a exception throwed"); + + return xAccessible; +} + +void SAL_CALL + ScAccessibleDocument::deselectAccessibleChild( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (mpChildrenShapes) + { + sal_Int32 nCount(mpChildrenShapes->GetCount()); //all shapes and the table + if (mxTempAcc.is()) + ++nCount; + if (nChildIndex < 0 || nChildIndex >= nCount) + throw lang::IndexOutOfBoundsException(); + + sal_Bool bTabMarked(IsTableSelected()); + + uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex); + if (xAccessible.is()) + { + if (mpChildrenShapes) + mpChildrenShapes->Deselect(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is to high + + if (bTabMarked) + mpViewShell->SelectAll(); // select the table again + } + else if (bTabMarked) + mpViewShell->Unmark(); + } +} + + //===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL + ScAccessibleDocument::getImplementationName(void) + throw (uno::RuntimeException) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleDocument")); +} + +uno::Sequence< ::rtl::OUString> SAL_CALL + ScAccessibleDocument::getSupportedServiceNames(void) + throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.AccessibleSpreadsheetDocumentView")); + + return aSequence; +} + +//===== XTypeProvider ======================================================= + +uno::Sequence< uno::Type > SAL_CALL ScAccessibleDocument::getTypes() + throw (uno::RuntimeException) +{ + return comphelper::concatSequences(ScAccessibleDocumentImpl::getTypes(), ScAccessibleContextBase::getTypes()); +} + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessibleDocument::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +///===== IAccessibleViewForwarder ======================================== + +sal_Bool ScAccessibleDocument::IsValid (void) const +{ + ScUnoGuard aGuard; + IsObjectValid(); + return (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose); +} + +Rectangle ScAccessibleDocument::GetVisibleArea_Impl() const +{ + Rectangle aVisRect(GetBoundingBox()); + + Point aPoint(mpViewShell->GetViewData()->GetPixPos(meSplitPos)); // returns a negative Point + aPoint.setX(-aPoint.getX()); + aPoint.setY(-aPoint.getY()); + aVisRect.SetPos(aPoint); + + ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); + if (pWin) + aVisRect = pWin->PixelToLogic(aVisRect, pWin->GetDrawMapMode()); + + return aVisRect; +} + +Rectangle ScAccessibleDocument::GetVisibleArea() const +{ + ScUnoGuard aGuard; + IsObjectValid(); + return maVisArea; +} + +Point ScAccessibleDocument::LogicToPixel (const Point& rPoint) const +{ + ScUnoGuard aGuard; + IsObjectValid(); + Point aPoint; + ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); + if (pWin) + { + aPoint = pWin->LogicToPixel(rPoint, pWin->GetDrawMapMode()); + aPoint += pWin->GetWindowExtentsRelative(NULL).TopLeft(); + } + return aPoint; +} + +Size ScAccessibleDocument::LogicToPixel (const Size& rSize) const +{ + ScUnoGuard aGuard; + IsObjectValid(); + Size aSize; + ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); + if (pWin) + aSize = pWin->LogicToPixel(rSize, pWin->GetDrawMapMode()); + return aSize; +} + +Point ScAccessibleDocument::PixelToLogic (const Point& rPoint) const +{ + ScUnoGuard aGuard; + IsObjectValid(); + Point aPoint; + ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); + if (pWin) + { + aPoint -= pWin->GetWindowExtentsRelative(NULL).TopLeft(); + aPoint = pWin->PixelToLogic(rPoint, pWin->GetDrawMapMode()); + } + return aPoint; +} + +Size ScAccessibleDocument::PixelToLogic (const Size& rSize) const +{ + ScUnoGuard aGuard; + IsObjectValid(); + Size aSize; + ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos)); + if (pWin) + aSize = pWin->PixelToLogic(rSize, pWin->GetDrawMapMode()); + return aSize; +} + + //===== internal ======================================================== + +utl::AccessibleRelationSetHelper* ScAccessibleDocument::GetRelationSet(const ScAddress* pAddress) const +{ + utl::AccessibleRelationSetHelper* pRelationSet = NULL; + if (mpChildrenShapes) + pRelationSet = mpChildrenShapes->GetRelationSet(pAddress); + return pRelationSet; +} + +::rtl::OUString SAL_CALL + ScAccessibleDocument::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + rtl::OUString sDescription = String(ScResId(STR_ACC_DOC_DESCR)); + return sDescription; +} + +::rtl::OUString SAL_CALL + ScAccessibleDocument::createAccessibleName(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + rtl::OUString sName = String(ScResId(STR_ACC_DOC_NAME)); + sal_Int32 nNumber(sal_Int32(meSplitPos) + 1); + sName += rtl::OUString::valueOf(nNumber); + return sName; +} + +Rectangle ScAccessibleDocument::GetBoundingBoxOnScreen() const + throw (uno::RuntimeException) +{ + Rectangle aRect; + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + aRect = pWindow->GetWindowExtentsRelative(NULL); + } + return aRect; +} + +Rectangle ScAccessibleDocument::GetBoundingBox() const + throw (uno::RuntimeException) +{ + Rectangle aRect; + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow()); + } + return aRect; +} + +SCTAB ScAccessibleDocument::getVisibleTable() const +{ + SCTAB nVisibleTable(0); + if (mpViewShell && mpViewShell->GetViewData()) + nVisibleTable = mpViewShell->GetViewData()->GetTabNo(); + return nVisibleTable; +} + +uno::Reference < XAccessible > + ScAccessibleDocument::GetAccessibleSpreadsheet() +{ + if (!mpAccessibleSpreadsheet && mpViewShell) + { + mpAccessibleSpreadsheet = new ScAccessibleSpreadsheet(this, mpViewShell, getVisibleTable(), meSplitPos); + mpAccessibleSpreadsheet->acquire(); + mpAccessibleSpreadsheet->Init(); + mbCompleteSheetSelected = IsTableSelected(); + } + return mpAccessibleSpreadsheet; +} + +void ScAccessibleDocument::FreeAccessibleSpreadsheet() +{ + if (mpAccessibleSpreadsheet) + { + mpAccessibleSpreadsheet->dispose(); + mpAccessibleSpreadsheet->release(); + mpAccessibleSpreadsheet = NULL; + } +} + +sal_Bool ScAccessibleDocument::IsTableSelected() const +{ + sal_Bool bResult (sal_False); + if(mpViewShell) + { + SCTAB nTab(getVisibleTable()); + //#103800#; use a copy of MarkData + ScMarkData aMarkData(mpViewShell->GetViewData()->GetMarkData()); + aMarkData.MarkToMulti(); + if (aMarkData.IsAllMarked(ScRange(ScAddress(0, 0, nTab),ScAddress(MAXCOL, MAXROW, nTab)))) + bResult = sal_True; + } + return bResult; +} + +sal_Bool ScAccessibleDocument::IsDefunc( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +sal_Bool ScAccessibleDocument::IsEditable( + const uno::Reference<XAccessibleStateSet>& /* rxParentStates */) +{ + // what is with document protection or readonly documents? + return sal_True; +} + +void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, sal_Bool bFireEvent) +{ + DBG_ASSERT(!mxTempAcc.is(), "this object should be removed before"); + if (xAcc.is()) + { + mxTempAcc = xAcc; + if( bFireEvent ) + { + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext>(this); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.NewValue <<= mxTempAcc; + CommitChange( aEvent ); + } + } +} + +void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, sal_Bool bFireEvent) +{ + DBG_ASSERT(mxTempAcc.is(), "this object should be added before"); + if (xAcc.is()) + { + DBG_ASSERT(xAcc.get() == mxTempAcc.get(), "only the same object should be removed"); + if( bFireEvent ) + { + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext>(this); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.OldValue <<= mxTempAcc; + CommitChange( aEvent ); + } + mxTempAcc = NULL; + } +} + +rtl::OUString ScAccessibleDocument::GetCurrentCellName() const +{ + String sName( ScResId(STR_ACC_CELL_NAME) ); + if (mpViewShell) + { + String sAddress; + // Document not needed, because only the cell address, but not the tablename is needed + mpViewShell->GetViewData()->GetCurPos().Format( sAddress, SCA_VALID, NULL ); + sName.SearchAndReplaceAscii("%1", sAddress); + } + return rtl::OUString(sName); +} + +rtl::OUString ScAccessibleDocument::GetCurrentCellDescription() const +{ + return rtl::OUString(); +} diff --git a/sc/source/ui/Accessibility/AccessibleDocumentBase.cxx b/sc/source/ui/Accessibility/AccessibleDocumentBase.cxx new file mode 100644 index 000000000000..76be8e67aa07 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleDocumentBase.cxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include "AccessibleDocumentBase.hxx" + +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + + //===== internal ======================================================== + +ScAccessibleDocumentBase::ScAccessibleDocumentBase( + const uno::Reference<XAccessible>& rxParent) + : ScAccessibleContextBase(rxParent, AccessibleRole::DOCUMENT) +{ +} + +ScAccessibleDocumentBase::~ScAccessibleDocumentBase(void) +{ +} diff --git a/sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx b/sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx new file mode 100644 index 000000000000..894e57d3802e --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx @@ -0,0 +1,1942 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +#include "AccessibleDocumentPagePreview.hxx" +#include "AccessiblePreviewTable.hxx" +#include "AccessiblePageHeader.hxx" +#include "AccessibilityHints.hxx" +#include "AccessibleText.hxx" +#include "document.hxx" +#include "prevwsh.hxx" +#include "prevloc.hxx" +#include "unoguard.hxx" +#include "drwlayer.hxx" +#include "editsrc.hxx" +#include "scresid.hxx" +#include "sc.hrc" +#include "DrawModelBroadcaster.hxx" +#include "docsh.hxx" +#include "drawview.hxx" +#include "preview.hxx" +#include "postit.hxx" + +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> + +#include <unotools/accessiblestatesethelper.hxx> +#include <tools/debug.hxx> +#include <tools/gen.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdobj.hxx> +#include <svx/AccessibleTextHelper.hxx> +#include <svx/AccessibleShape.hxx> +#include <svx/ShapeTypeHandler.hxx> +#include <toolkit/helper/convert.hxx> +#include <svx/unoshape.hxx> +#include <unotools/accessiblerelationsethelper.hxx> + +#include <vector> +#include <list> +#include <algorithm> +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//========================================================================= + +typedef std::list< uno::Reference< XAccessible > > ScXAccList; + + +struct ScAccNote +{ + String maNoteText; + Rectangle maRect; + ScAddress maNoteCell; + ::accessibility::AccessibleTextHelper* mpTextHelper; + sal_Int32 mnParaCount; + sal_Bool mbMarkNote; + + ScAccNote() : mpTextHelper(NULL), mnParaCount(0) {} +}; + +class ScNotesChilds +{ +public: + ScNotesChilds(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc); + ~ScNotesChilds(); + void Init(const Rectangle& rVisRect, sal_Int32 nOffset); + + sal_Int32 GetChildsCount() const; + uno::Reference<XAccessible> GetChild(sal_Int32 nIndex) const; + uno::Reference<XAccessible> GetAt(const awt::Point& rPoint) const; + + void DataChanged(const Rectangle& rVisRect); + void SetOffset(sal_Int32 nNewOffset); +private: + ScPreviewShell* mpViewShell; + ScAccessibleDocumentPagePreview* mpAccDoc; + typedef std::vector<ScAccNote> ScAccNotes; + mutable ScAccNotes maNotes; + mutable ScAccNotes maMarks; + sal_Int32 mnParagraphs; + sal_Int32 mnOffset; + + ::accessibility::AccessibleTextHelper* CreateTextHelper(const String& rString, const Rectangle& rVisRect, const ScAddress& aCellPos, sal_Bool bMarkNote, sal_Int32 nChildOffset) const; + sal_Int32 AddNotes(const ScPreviewLocationData& rData, const Rectangle& rVisRect, sal_Bool bMark, ScAccNotes& rNotes); + + sal_Int8 CompareCell(const ScAddress& aCell1, const ScAddress& aCell2); + void CollectChilds(const ScAccNote& rNote, ScXAccList& rList); + sal_Int32 CheckChanges(const ScPreviewLocationData& rData, const Rectangle& rVisRect, + sal_Bool bMark, ScAccNotes& rOldNotes, ScAccNotes& rNewNotes, + ScXAccList& rOldParas, ScXAccList& rNewParas); + + inline ScDocument* GetDocument() const; +}; + +ScNotesChilds::ScNotesChilds(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc) + : mpViewShell(pViewShell), + mpAccDoc(pAccDoc), + mnParagraphs(0), + mnOffset(0) +{ +} + +struct DeleteAccNote +{ + void operator()(ScAccNote& rNote) + { + if (rNote.mpTextHelper) + DELETEZ( rNote.mpTextHelper); + } +}; + +ScNotesChilds::~ScNotesChilds() +{ + std::for_each(maNotes.begin(), maNotes.end(), DeleteAccNote()); + std::for_each(maMarks.begin(), maMarks.end(), DeleteAccNote()); +} + +::accessibility::AccessibleTextHelper* ScNotesChilds::CreateTextHelper(const String& rString, const Rectangle& rVisRect, const ScAddress& aCellPos, sal_Bool bMarkNote, sal_Int32 nChildOffset) const +{ + ::accessibility::AccessibleTextHelper* pTextHelper = NULL; + + ::std::auto_ptr < ScAccessibleTextData > pAccessiblePreviewHeaderCellTextData + (new ScAccessibleNoteTextData(mpViewShell, rString, aCellPos, bMarkNote)); + ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessiblePreviewHeaderCellTextData)); + + pTextHelper = new ::accessibility::AccessibleTextHelper(pEditSource); + + if (pTextHelper) + { + pTextHelper->SetEventSource(mpAccDoc); + pTextHelper->SetStartIndex(nChildOffset); + pTextHelper->SetOffset(rVisRect.TopLeft()); + } + + return pTextHelper; +} + +sal_Int32 ScNotesChilds::AddNotes(const ScPreviewLocationData& rData, const Rectangle& rVisRect, sal_Bool bMark, ScAccNotes& rNotes) +{ + sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark); + + rNotes.reserve(nCount); + + sal_Int32 nParagraphs(0); + ScDocument* pDoc = GetDocument(); + if (pDoc) + { + ScAccNote aNote; + aNote.mbMarkNote = bMark; + if (bMark) + aNote.mnParaCount = 1; + for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex) + { + if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect)) + { + if (bMark) + { + // Document not needed, because only the cell address, but not the tablename is needed + aNote.maNoteCell.Format( aNote.maNoteText, SCA_VALID, NULL ); + } + else + { + if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) ) + aNote.maNoteText = pNote->GetText(); + aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset); + if (aNote.mpTextHelper) + aNote.mnParaCount = aNote.mpTextHelper->GetChildCount(); + } + nParagraphs += aNote.mnParaCount; + rNotes.push_back(aNote); + } + } + } + return nParagraphs; +} + +void ScNotesChilds::Init(const Rectangle& rVisRect, sal_Int32 nOffset) +{ + if (mpViewShell && !mnParagraphs) + { + mnOffset = nOffset; + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + + mnParagraphs = AddNotes(rData, rVisRect, sal_False, maMarks); + mnParagraphs += AddNotes(rData, rVisRect, sal_True, maNotes); + } +} + +sal_Int32 ScNotesChilds::GetChildsCount() const +{ + return mnParagraphs; +} + +struct ScParaFound +{ + sal_Int32 mnIndex; + ScParaFound(sal_Int32 nIndex) : mnIndex(nIndex) {} + sal_Bool operator() (const ScAccNote& rNote) + { + sal_Bool bResult(sal_False); + if (rNote.mnParaCount > mnIndex) + bResult = sal_True; + else + mnIndex -= rNote.mnParaCount; + return bResult; + } +}; + +uno::Reference<XAccessible> ScNotesChilds::GetChild(sal_Int32 nIndex) const +{ + uno::Reference<XAccessible> xAccessible; + + if (nIndex < mnParagraphs) + { + if (nIndex < static_cast<sal_Int32>(maMarks.size())) + { + ScAccNotes::iterator aEndItr = maMarks.end(); + ScParaFound aParaFound(nIndex); + ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aParaFound); + if (aItr != aEndItr) + { + DBG_ASSERT((aItr->maNoteCell == maMarks[nIndex].maNoteCell) && (aItr->mbMarkNote == maMarks[nIndex].mbMarkNote), "wrong note found"); + } + else + { + DBG_ERRORFILE("wrong note found"); + } + if (!aItr->mpTextHelper) + aItr->mpTextHelper = CreateTextHelper(maMarks[nIndex].maNoteText, maMarks[nIndex].maRect, maMarks[nIndex].maNoteCell, maMarks[nIndex].mbMarkNote, nIndex + mnOffset); // the marks are the first and every mark has only one paragraph + xAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex()); + } + else + { + nIndex -= maMarks.size(); + ScAccNotes::iterator aEndItr = maNotes.end(); + ScParaFound aParaFound(nIndex); + ScAccNotes::iterator aItr = std::find_if(maNotes.begin(), aEndItr, aParaFound); + if (aEndItr != aItr) + { + if (!aItr->mpTextHelper) + aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, (nIndex - aParaFound.mnIndex) + mnOffset + maMarks.size()); + xAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex()); + } + } + } + + return xAccessible; +} + +struct ScPointFound +{ + Rectangle maPoint; + sal_Int32 mnParagraphs; + ScPointFound(const Point& rPoint) : maPoint(rPoint, Size(0, 0)), mnParagraphs(0) {} + sal_Bool operator() (const ScAccNote& rNote) + { + sal_Bool bResult(sal_False); + if (maPoint.IsInside(rNote.maRect)) + bResult = sal_True; + else + mnParagraphs += rNote.mnParaCount; + return bResult; + } +}; + +uno::Reference<XAccessible> ScNotesChilds::GetAt(const awt::Point& rPoint) const +{ + uno::Reference<XAccessible> xAccessible; + + ScPointFound aPointFound(Point(rPoint.X, rPoint.Y)); + + ScAccNotes::iterator aEndItr = maMarks.end(); + ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aPointFound); + if (aEndItr == aItr) + { + aEndItr = maNotes.end(); + aItr = std::find_if(maNotes.begin(), aEndItr, aPointFound); + } + if (aEndItr != aItr) + { + if (!aItr->mpTextHelper) + aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, aPointFound.mnParagraphs + mnOffset); + xAccessible = aItr->mpTextHelper->GetAt(rPoint); + } + + return xAccessible; +} + +sal_Int8 ScNotesChilds::CompareCell(const ScAddress& aCell1, const ScAddress& aCell2) +{ + DBG_ASSERT(aCell1.Tab() == aCell2.Tab(), "the notes should be on the same table"); + sal_Int8 nResult(0); + if (aCell1 != aCell2) + { + if (aCell1.Row() == aCell2.Row()) + nResult = (aCell1.Col() < aCell2.Col()) ? -1 : 1; + else + nResult = (aCell1.Row() < aCell2.Row()) ? -1 : 1; + } + return nResult; +} + +void ScNotesChilds::CollectChilds(const ScAccNote& rNote, ScXAccList& rList) +{ + if (rNote.mpTextHelper) + for (sal_Int32 i = 0; i < rNote.mnParaCount; ++i) + rList.push_back(rNote.mpTextHelper->GetChild(i + rNote.mpTextHelper->GetStartIndex())); +} + +sal_Int32 ScNotesChilds::CheckChanges(const ScPreviewLocationData& rData, + const Rectangle& rVisRect, sal_Bool bMark, ScAccNotes& rOldNotes, + ScAccNotes& rNewNotes, ScXAccList& rOldParas, ScXAccList& rNewParas) +{ + sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark); + + rNewNotes.reserve(nCount); + + sal_Int32 nParagraphs(0); + ScDocument* pDoc = GetDocument(); + if (pDoc) + { + ScAccNote aNote; + aNote.mbMarkNote = bMark; + if (bMark) + aNote.mnParaCount = 1; + ScAccNotes::iterator aItr = rOldNotes.begin(); + ScAccNotes::iterator aEndItr = rOldNotes.end(); + sal_Bool bAddNote(sal_False); + for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex) + { + if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect)) + { + if (bMark) + { + // Document not needed, because only the cell address, but not the tablename is needed + aNote.maNoteCell.Format( aNote.maNoteText, SCA_VALID, NULL ); + } + else + { + if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) ) + aNote.maNoteText = pNote->GetText(); + } + + sal_Int8 nCompare(-1); // if there are no more old childs it is always a new one + if (aItr != aEndItr) + nCompare = CompareCell(aNote.maNoteCell, aItr->maNoteCell); + if (nCompare == 0) + { + if (aNote.maNoteText == aItr->maNoteText) + { + aNote.mpTextHelper = aItr->mpTextHelper; + if (aNote.maRect != aItr->maRect) //neue VisArea setzen + { + aNote.mpTextHelper->SetOffset(aNote.maRect.TopLeft()); + aNote.mpTextHelper->UpdateChildren(); + //DBG_ASSERT(aItr->maRect.GetSize() == aNote.maRect.GetSize(), "size should be the same, because the text is not changed"); + // could be changed, because only a part of the note is visible + } + } + else + { + aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset); + if (aNote.mpTextHelper) + aNote.mnParaCount = aNote.mpTextHelper->GetChildCount(); + // collect removed childs + CollectChilds(*aItr, rOldParas); + DELETEZ(aItr->mpTextHelper); + // collect new childs + CollectChilds(aNote, rNewParas); + } + bAddNote = sal_True; + // not necessary, because this branch should not be reached if it is the end + //if (aItr != aEndItr) + ++aItr; + } + else if (nCompare < 0) + { + aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset); + if (aNote.mpTextHelper) + aNote.mnParaCount = aNote.mpTextHelper->GetChildCount(); + // collect new childs + CollectChilds(aNote, rNewParas); + bAddNote = sal_True; + } + else + { + // collect removed childs + CollectChilds(*aItr, rOldParas); + DELETEZ(aItr->mpTextHelper); + + // no note to add + // not necessary, because this branch should not be reached if it is the end + //if (aItr != aEndItr) + ++aItr; + } + if (bAddNote) + { + nParagraphs += aNote.mnParaCount; + rNewNotes.push_back(aNote); + bAddNote = sal_False; + } + } + } + } + return nParagraphs; +} + +struct ScChildGone +{ + ScAccessibleDocumentPagePreview* mpAccDoc; + ScChildGone(ScAccessibleDocumentPagePreview* pAccDoc) : mpAccDoc(pAccDoc) {} + void operator() (const uno::Reference<XAccessible>& xAccessible) const + { + if (mpAccDoc) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(mpAccDoc); + aEvent.OldValue <<= xAccessible; + + mpAccDoc->CommitChange(aEvent); // gone child - event + } + } +}; + +struct ScChildNew +{ + ScAccessibleDocumentPagePreview* mpAccDoc; + ScChildNew(ScAccessibleDocumentPagePreview* pAccDoc) : mpAccDoc(pAccDoc) {} + void operator() (const uno::Reference<XAccessible>& xAccessible) const + { + if (mpAccDoc) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(mpAccDoc); + aEvent.NewValue <<= xAccessible; + + mpAccDoc->CommitChange(aEvent); // new child - event + } + } +}; + +void ScNotesChilds::DataChanged(const Rectangle& rVisRect) +{ + if (mpViewShell && mpAccDoc) + { + ScXAccList aNewParas; + ScXAccList aOldParas; + ScAccNotes aNewMarks; + mnParagraphs = CheckChanges(mpViewShell->GetLocationData(), rVisRect, sal_True, maMarks, aNewMarks, aOldParas, aNewParas); + maMarks = aNewMarks; + ScAccNotes aNewNotes; + mnParagraphs += CheckChanges(mpViewShell->GetLocationData(), rVisRect, sal_False, maNotes, aNewNotes, aOldParas, aNewParas); + maNotes = aNewNotes; + + std::for_each(aOldParas.begin(), aOldParas.end(), ScChildGone(mpAccDoc)); + std::for_each(aNewParas.begin(), aNewParas.end(), ScChildNew(mpAccDoc)); + } +} + +struct ScChangeOffset +{ + sal_Int32 mnDiff; + ScChangeOffset(sal_Int32 nDiff) : mnDiff(nDiff) {} + void operator() (const ScAccNote& rNote) + { + if (rNote.mpTextHelper) + rNote.mpTextHelper->SetStartIndex(rNote.mpTextHelper->GetStartIndex() + mnDiff); + } +}; + +void ScNotesChilds::SetOffset(sal_Int32 nNewOffset) +{ + sal_Int32 nDiff(nNewOffset - mnOffset); + if (nDiff != 0) + { + std::for_each(maMarks.begin(), maMarks.end(), ScChangeOffset(nDiff)); + std::for_each(maNotes.begin(), maNotes.end(), ScChangeOffset(nDiff)); + mnOffset = nNewOffset; + } +} + +inline ScDocument* ScNotesChilds::GetDocument() const +{ + ScDocument* pDoc = NULL; + if (mpViewShell) + pDoc = mpViewShell->GetDocument(); + return pDoc; +} + +class ScIAccessibleViewForwarder : public ::accessibility::IAccessibleViewForwarder +{ +public: + ScIAccessibleViewForwarder(); + ScIAccessibleViewForwarder(ScPreviewShell* pViewShell, + ScAccessibleDocumentPagePreview* pAccDoc, + const MapMode& aMapMode); + ~ScIAccessibleViewForwarder(); + + ///===== IAccessibleViewForwarder ======================================== + + virtual sal_Bool IsValid (void) const; + virtual Rectangle GetVisibleArea() const; + virtual Point LogicToPixel (const Point& rPoint) const; + virtual Size LogicToPixel (const Size& rSize) const; + virtual Point PixelToLogic (const Point& rPoint) const; + virtual Size PixelToLogic (const Size& rSize) const; + +private: + ScPreviewShell* mpViewShell; + ScAccessibleDocumentPagePreview* mpAccDoc; + MapMode maMapMode; + sal_Bool mbValid; +}; + +ScIAccessibleViewForwarder::ScIAccessibleViewForwarder() + : mbValid(sal_False) +{ +} + +ScIAccessibleViewForwarder::ScIAccessibleViewForwarder(ScPreviewShell* pViewShell, + ScAccessibleDocumentPagePreview* pAccDoc, + const MapMode& aMapMode) + : mpViewShell(pViewShell), + mpAccDoc(pAccDoc), + maMapMode(aMapMode), + mbValid(sal_True) +{ +} + +ScIAccessibleViewForwarder::~ScIAccessibleViewForwarder() +{ +} + +///===== IAccessibleViewForwarder ======================================== + +sal_Bool ScIAccessibleViewForwarder::IsValid (void) const +{ + ScUnoGuard aGuard; + return mbValid; +} + +Rectangle ScIAccessibleViewForwarder::GetVisibleArea() const +{ + ScUnoGuard aGuard; + Rectangle aVisRect; + Window* pWin = mpViewShell->GetWindow(); + if (pWin) + { + aVisRect.SetSize(pWin->GetOutputSizePixel()); + aVisRect.SetPos(Point(0, 0)); + + aVisRect = pWin->PixelToLogic(aVisRect, maMapMode); + } + + return aVisRect; +} + +Point ScIAccessibleViewForwarder::LogicToPixel (const Point& rPoint) const +{ + ScUnoGuard aGuard; + Point aPoint; + Window* pWin = mpViewShell->GetWindow(); + if (pWin && mpAccDoc) + { + Rectangle aRect(mpAccDoc->GetBoundingBoxOnScreen()); + aPoint = pWin->LogicToPixel(rPoint, maMapMode) + aRect.TopLeft(); + } + + return aPoint; +} + +Size ScIAccessibleViewForwarder::LogicToPixel (const Size& rSize) const +{ + ScUnoGuard aGuard; + Size aSize; + Window* pWin = mpViewShell->GetWindow(); + if (pWin) + aSize = pWin->LogicToPixel(rSize, maMapMode); + return aSize; +} + +Point ScIAccessibleViewForwarder::PixelToLogic (const Point& rPoint) const +{ + ScUnoGuard aGuard; + Point aPoint; + Window* pWin = mpViewShell->GetWindow(); + if (pWin && mpAccDoc) + { + Rectangle aRect(mpAccDoc->GetBoundingBoxOnScreen()); + aPoint = pWin->PixelToLogic(rPoint - aRect.TopLeft(), maMapMode); + } + return aPoint; +} + +Size ScIAccessibleViewForwarder::PixelToLogic (const Size& rSize) const +{ + ScUnoGuard aGuard; + Size aSize; + Window* pWin = mpViewShell->GetWindow(); + if (pWin) + aSize = pWin->PixelToLogic(rSize, maMapMode); + return aSize; +} + +struct ScShapeChild +{ + ScShapeChild() : mpAccShape(NULL) {} + ScShapeChild(const ScShapeChild& rOld); + ~ScShapeChild(); + mutable ::accessibility::AccessibleShape* mpAccShape; + com::sun::star::uno::Reference< com::sun::star::drawing::XShape > mxShape; + sal_Int32 mnRangeId; +}; + +ScShapeChild::ScShapeChild(const ScShapeChild& rOld) +: +mpAccShape(rOld.mpAccShape), +mxShape(rOld.mxShape), +mnRangeId(rOld.mnRangeId) +{ + if (mpAccShape) + mpAccShape->acquire(); +} + +ScShapeChild::~ScShapeChild() +{ + if (mpAccShape) + { + mpAccShape->dispose(); + mpAccShape->release(); + } +} + +struct ScShapeChildLess +{ + sal_Bool operator()(const ScShapeChild& rChild1, const ScShapeChild& rChild2) const + { + sal_Bool bResult(sal_False); + if (rChild1.mxShape.is() && rChild2.mxShape.is()) + bResult = (rChild1.mxShape.get() < rChild2.mxShape.get()); + return bResult; + } +}; + +typedef std::vector<ScShapeChild> ScShapeChildVec; + +struct ScShapeRange +{ + ScShapeChildVec maBackShapes; + ScShapeChildVec maForeShapes; // inclusive internal shapes + ScShapeChildVec maControls; + Rectangle maPixelRect; + MapMode maMapMode; + ScIAccessibleViewForwarder maViewForwarder; +}; + +typedef std::vector<ScShapeRange> ScShapeRangeVec; + +class ScShapeChilds : public SfxListener, + public ::accessibility::IAccessibleParent +{ +public: + ScShapeChilds(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc); + ~ScShapeChilds(); + + ///===== SfxListener ===================================================== + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + + ///===== IAccessibleParent ============================================== + + virtual sal_Bool ReplaceChild ( + ::accessibility::AccessibleShape* pCurrentChild, + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape, + const long _nIndex, + const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo + ) throw (::com::sun::star::uno::RuntimeException); + + ///===== Internal ======================================================== + + void Init(); + + sal_Int32 GetBackShapeCount() const; + uno::Reference<XAccessible> GetBackShape(sal_Int32 nIndex) const; + sal_Int32 GetForeShapeCount() const; + uno::Reference<XAccessible> GetForeShape(sal_Int32 nIndex) const; + sal_Int32 GetControlCount() const; + uno::Reference<XAccessible> GetControl(sal_Int32 nIndex) const; + uno::Reference<XAccessible> GetForegroundShapeAt(const awt::Point& rPoint) const; // inclusive controls + uno::Reference<XAccessible> GetBackgroundShapeAt(const awt::Point& rPoint) const; + + void DataChanged(); + void VisAreaChanged() const; + + void SetDrawBroadcaster(); +private: + ScAccessibleDocumentPagePreview* mpAccDoc; + ScPreviewShell* mpViewShell; + ScShapeRangeVec maShapeRanges; + + void FindChanged(ScShapeChildVec& aOld, ScShapeChildVec& aNew) const; + void FindChanged(ScShapeRange& aOld, ScShapeRange& aNew) const; + ::accessibility::AccessibleShape* GetAccShape(const ScShapeChild& rShape) const; + ::accessibility::AccessibleShape* GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const; + void FillShapes(const Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId); +//UNUSED2008-05 sal_Bool FindShape(ScShapeChildVec& rShapes, const uno::Reference <drawing::XShape>& xShape, ScShapeChildVec::iterator& rItr) const; + +// void AddShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID); +// void RemoveShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID); + SdrPage* GetDrawPage() const; +}; + +ScShapeChilds::ScShapeChilds(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc) + : + mpAccDoc(pAccDoc), + mpViewShell(pViewShell), + maShapeRanges(SC_PREVIEW_MAXRANGES) +{ + if (pViewShell) + { + SfxBroadcaster* pDrawBC = pViewShell->GetDocument()->GetDrawBroadcaster(); + if (pDrawBC) + StartListening(*pDrawBC); + } +} + +ScShapeChilds::~ScShapeChilds() +{ + if (mpViewShell) + { + SfxBroadcaster* pDrawBC = mpViewShell->GetDocument()->GetDrawBroadcaster(); + if (pDrawBC) + EndListening(*pDrawBC); + } +} + +void ScShapeChilds::SetDrawBroadcaster() +{ + if (mpViewShell) + { + SfxBroadcaster* pDrawBC = mpViewShell->GetDocument()->GetDrawBroadcaster(); + if (pDrawBC) + StartListening(*pDrawBC, TRUE); + } +} + +void ScShapeChilds::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + if ( rHint.ISA( SdrHint ) ) + { + const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); + if (pSdrHint) + { + SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject()); + if (pObj && (pObj->GetPage() == GetDrawPage())) + { + switch (pSdrHint->GetKind()) + { + case HINT_OBJCHG : // Objekt geaendert + { + } + break; + // no longer necessary +/* case HINT_OBJINSERTED : // Neues Zeichenobjekt eingefuegt + { + uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); + if (xShape.is()) + AddShape(xShape, pObj->GetLayer()); + } + break; + case HINT_OBJREMOVED : // Zeichenobjekt aus Liste entfernt + { + uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY); + if (xShape.is()) + RemoveShape(xShape, pObj->GetLayer()); + } + break;*/ + default : + { + // other events are not interesting + } + break; + } + } + } + } +} + +void ScShapeChilds::FindChanged(ScShapeChildVec& rOld, ScShapeChildVec& rNew) const +{ + ScShapeChildVec::iterator aOldItr = rOld.begin(); + ScShapeChildVec::iterator aOldEnd = rOld.end(); + ScShapeChildVec::const_iterator aNewItr = rNew.begin(); + ScShapeChildVec::const_iterator aNewEnd = rNew.begin(); + uno::Reference<XAccessible> xAcc; + while ((aNewItr != aNewEnd) && (aOldItr != aOldEnd)) + { + if (aNewItr->mxShape.get() == aOldItr->mxShape.get()) + { + ++aOldItr; + ++aNewItr; + } + else if (aNewItr->mxShape.get() < aOldItr->mxShape.get()) + { + xAcc = GetAccShape(*aNewItr); + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.NewValue <<= xAcc; + mpAccDoc->CommitChange(aEvent); + ++aNewItr; + } + else + { + xAcc = GetAccShape(*aOldItr); + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.OldValue <<= xAcc; + mpAccDoc->CommitChange(aEvent); + ++aOldItr; + } + } + while (aOldItr != aOldEnd) + { + xAcc = GetAccShape(*aOldItr); + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.OldValue <<= xAcc; + mpAccDoc->CommitChange(aEvent); + ++aOldItr; + } + while (aNewItr != aNewEnd) + { + xAcc = GetAccShape(*aNewItr); + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.NewValue <<= xAcc; + mpAccDoc->CommitChange(aEvent); + ++aNewItr; + } +} + +void ScShapeChilds::FindChanged(ScShapeRange& rOld, ScShapeRange& rNew) const +{ + FindChanged(rOld.maBackShapes, rNew.maBackShapes); + FindChanged(rOld.maForeShapes, rNew.maForeShapes); + FindChanged(rOld.maControls, rNew.maControls); +} + +void ScShapeChilds::DataChanged() +{ + ScShapeRangeVec aOldShapeRanges(maShapeRanges); + maShapeRanges.clear(); + maShapeRanges.resize(SC_PREVIEW_MAXRANGES); + Init(); + for (sal_Int32 i = 0; i < SC_PREVIEW_MAXRANGES; ++i) + { + FindChanged(aOldShapeRanges[i], maShapeRanges[i]); + } +} + +struct ScVisAreaChanged +{ + const ScIAccessibleViewForwarder* mpViewForwarder; + ScVisAreaChanged(const ScIAccessibleViewForwarder* pViewForwarder) : mpViewForwarder(pViewForwarder) {} + void operator() (const ScShapeChild& rAccShapeData) const + { + if (rAccShapeData.mpAccShape) + { + rAccShapeData.mpAccShape->ViewForwarderChanged(::accessibility::IAccessibleViewForwarderListener::VISIBLE_AREA, mpViewForwarder); + } + } +}; + +void ScShapeChilds::VisAreaChanged() const +{ + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); + while (aItr != aEndItr) + { + ScVisAreaChanged aVisAreaChanged(&(aItr->maViewForwarder)); + std::for_each(aItr->maBackShapes.begin(), aItr->maBackShapes.end(), aVisAreaChanged); + std::for_each(aItr->maControls.begin(), aItr->maControls.end(), aVisAreaChanged); + std::for_each(aItr->maForeShapes.begin(), aItr->maForeShapes.end(), aVisAreaChanged); + ++aItr; + } +} + + ///===== IAccessibleParent ============================================== + +sal_Bool ScShapeChilds::ReplaceChild (::accessibility::AccessibleShape* /* pCurrentChild */, + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& /* _rxShape */, + const long /* _nIndex */, const ::accessibility::AccessibleShapeTreeInfo& /* _rShapeTreeInfo */) + throw (uno::RuntimeException) +{ + DBG_ERRORFILE("should not be called in the page preview"); + return sal_False; +} + + ///===== Internal ======================================================== + +void ScShapeChilds::Init() +{ + if(mpViewShell) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + MapMode aMapMode; + Rectangle aPixelPaintRect; + sal_uInt8 nRangeId; + sal_uInt16 nCount(rData.GetDrawRanges()); + for (sal_uInt16 i = 0; i < nCount; ++i) + { + rData.GetDrawRange(i, aPixelPaintRect, aMapMode, nRangeId); + FillShapes(aPixelPaintRect, aMapMode, nRangeId); + } + } +} + +sal_Int32 ScShapeChilds::GetBackShapeCount() const +{ + sal_Int32 nCount(0); + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + for ( ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); aItr != aEndItr; ++aItr ) + nCount += aItr->maBackShapes.size(); + return nCount; +} + +uno::Reference<XAccessible> ScShapeChilds::GetBackShape(sal_Int32 nIndex) const +{ + uno::Reference<XAccessible> xAccessible; + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); + while ((aItr != aEndItr) && !xAccessible.is()) + { + sal_Int32 nCount(aItr->maBackShapes.size()); + if(nIndex < nCount) + xAccessible = GetAccShape(aItr->maBackShapes, nIndex); + else + ++aItr; + nIndex -= nCount; + } + + if (nIndex >= 0) + throw lang::IndexOutOfBoundsException(); + + return xAccessible; +} + +sal_Int32 ScShapeChilds::GetForeShapeCount() const +{ + sal_Int32 nCount(0); + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + for ( ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); aItr != aEndItr; ++aItr ) + nCount += aItr->maForeShapes.size(); + return nCount; +} + +uno::Reference<XAccessible> ScShapeChilds::GetForeShape(sal_Int32 nIndex) const +{ + uno::Reference<XAccessible> xAccessible; + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); + while ((aItr != aEndItr) && !xAccessible.is()) + { + sal_Int32 nCount(aItr->maForeShapes.size()); + if(nIndex < nCount) + xAccessible = GetAccShape(aItr->maForeShapes, nIndex); + else + ++aItr; + nIndex -= nCount; + } + + if (nIndex >= 0) + throw lang::IndexOutOfBoundsException(); + + return xAccessible; +} + +sal_Int32 ScShapeChilds::GetControlCount() const +{ + sal_Int32 nCount(0); + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + for ( ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); aItr != aEndItr; ++aItr ) + nCount += aItr->maControls.size(); + return nCount; +} + +uno::Reference<XAccessible> ScShapeChilds::GetControl(sal_Int32 nIndex) const +{ + uno::Reference<XAccessible> xAccessible; + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); + while ((aItr != aEndItr) && !xAccessible.is()) + { + sal_Int32 nCount(aItr->maControls.size()); + if(nIndex < nCount) + xAccessible = GetAccShape(aItr->maControls, nIndex); + else + ++aItr; + nIndex -= nCount; + } + + if (nIndex >= 0) + throw lang::IndexOutOfBoundsException(); + + return xAccessible; +} + +struct ScShapePointFound +{ + Point maPoint; + ScShapePointFound(const awt::Point& rPoint) : maPoint(VCLPoint(rPoint)) {} + sal_Bool operator() (const ScShapeChild& rShape) + { + sal_Bool bResult(sal_False); + if ((VCLRectangle(rShape.mpAccShape->getBounds())).IsInside(maPoint)) + bResult = sal_True; + return bResult; + } +}; + +uno::Reference<XAccessible> ScShapeChilds::GetForegroundShapeAt(const awt::Point& rPoint) const //inclusive Controls +{ + uno::Reference<XAccessible> xAcc; + + ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + while((aItr != aEndItr) && !xAcc.is()) + { + ScShapeChildVec::const_iterator aFindItr = std::find_if(aItr->maForeShapes.begin(), aItr->maForeShapes.end(), ScShapePointFound(rPoint)); + if (aFindItr != aItr->maForeShapes.end()) + xAcc = GetAccShape(*aFindItr); + else + { + ScShapeChildVec::const_iterator aCtrlItr = std::find_if(aItr->maControls.begin(), aItr->maControls.end(), ScShapePointFound(rPoint)); + if (aCtrlItr != aItr->maControls.end()) + xAcc = GetAccShape(*aCtrlItr); + else + ++aItr; + } + } + + return xAcc; +} + +uno::Reference<XAccessible> ScShapeChilds::GetBackgroundShapeAt(const awt::Point& rPoint) const +{ + uno::Reference<XAccessible> xAcc; + + ScShapeRangeVec::const_iterator aItr = maShapeRanges.begin(); + ScShapeRangeVec::const_iterator aEndItr = maShapeRanges.end(); + while((aItr != aEndItr) && !xAcc.is()) + { + ScShapeChildVec::const_iterator aFindItr = std::find_if(aItr->maBackShapes.begin(), aItr->maBackShapes.end(), ScShapePointFound(rPoint)); + if (aFindItr != aItr->maBackShapes.end()) + xAcc = GetAccShape(*aFindItr); + else + ++aItr; + } + + return xAcc; +} + +::accessibility::AccessibleShape* ScShapeChilds::GetAccShape(const ScShapeChild& rShape) const +{ + if (!rShape.mpAccShape) + { + ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance(); + ::accessibility::AccessibleShapeInfo aShapeInfo(rShape.mxShape, mpAccDoc, const_cast<ScShapeChilds*>(this)); + + if (mpViewShell) + { + ::accessibility::AccessibleShapeTreeInfo aShapeTreeInfo; + aShapeTreeInfo.SetSdrView(mpViewShell->GetPreview()->GetDrawView()); + aShapeTreeInfo.SetController(NULL); + aShapeTreeInfo.SetWindow(mpViewShell->GetWindow()); + aShapeTreeInfo.SetViewForwarder(&(maShapeRanges[rShape.mnRangeId].maViewForwarder)); + rShape.mpAccShape = rShapeHandler.CreateAccessibleObject(aShapeInfo, aShapeTreeInfo); + if (rShape.mpAccShape) + { + rShape.mpAccShape->acquire(); + rShape.mpAccShape->Init(); + } + } + } + return rShape.mpAccShape; +} + +::accessibility::AccessibleShape* ScShapeChilds::GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const +{ + return (GetAccShape(rShapes[nIndex])); +} + +void ScShapeChilds::FillShapes(const Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId) +{ + DBG_ASSERT(nRangeId < maShapeRanges.size(), "this is not a valid range for draw objects"); + SdrPage* pPage = GetDrawPage(); + Window* pWin = mpViewShell->GetWindow(); + if (pPage && pWin) + { + sal_Bool bForeAdded(sal_False); + sal_Bool bBackAdded(sal_False); + sal_Bool bControlAdded(sal_False); + Rectangle aClippedPixelPaintRect(aPixelPaintRect); + if (mpAccDoc) + { + Rectangle aRect2(Point(0,0), mpAccDoc->GetBoundingBoxOnScreen().GetSize()); + aClippedPixelPaintRect = aPixelPaintRect.GetIntersection(aRect2); + } + maShapeRanges[nRangeId].maPixelRect = aClippedPixelPaintRect; + maShapeRanges[nRangeId].maMapMode = aMapMode; + ScIAccessibleViewForwarder aViewForwarder(mpViewShell, mpAccDoc, aMapMode); + maShapeRanges[nRangeId].maViewForwarder = aViewForwarder; + sal_uInt32 nCount(pPage->GetObjCount()); + for (sal_uInt32 i = 0; i < nCount; ++i) + { + SdrObject* pObj = pPage->GetObj(i); + if (pObj) + { + uno::Reference< drawing::XShape > xShape(pObj->getUnoShape(), uno::UNO_QUERY); + if (xShape.is()) + { + Rectangle aRect(pWin->LogicToPixel(VCLPoint(xShape->getPosition()), aMapMode), pWin->LogicToPixel(VCLSize(xShape->getSize()), aMapMode)); + if(!aClippedPixelPaintRect.GetIntersection(aRect).IsEmpty()) + { + ScShapeChild aShape; + aShape.mxShape = xShape; + aShape.mnRangeId = nRangeId; + switch (pObj->GetLayer()) + { + case SC_LAYER_INTERN: + case SC_LAYER_FRONT: + { + maShapeRanges[nRangeId].maForeShapes.push_back(aShape); + bForeAdded = sal_True; + } + break; + case SC_LAYER_BACK: + { + maShapeRanges[nRangeId].maBackShapes.push_back(aShape); + bBackAdded = sal_True; + } + break; + case SC_LAYER_CONTROLS: + { + maShapeRanges[nRangeId].maControls.push_back(aShape); + bControlAdded = sal_True; + } + break; + default: + { + DBG_ERRORFILE("I don't know this layer."); + } + break; + } + } + } + } + } + if (bForeAdded) + std::sort(maShapeRanges[nRangeId].maForeShapes.begin(), maShapeRanges[nRangeId].maForeShapes.end(),ScShapeChildLess()); + if (bBackAdded) + std::sort(maShapeRanges[nRangeId].maBackShapes.begin(), maShapeRanges[nRangeId].maBackShapes.end(),ScShapeChildLess()); + if (bControlAdded) + std::sort(maShapeRanges[nRangeId].maControls.begin(), maShapeRanges[nRangeId].maControls.end(),ScShapeChildLess()); + } +} + +//UNUSED2008-05 sal_Bool ScShapeChilds::FindShape(ScShapeChildVec& rShapes, const uno::Reference <drawing::XShape>& xShape, ScShapeChildVec::iterator& rItr) const +//UNUSED2008-05 { +//UNUSED2008-05 sal_Bool bResult(sal_False); +//UNUSED2008-05 ScShapeChild aShape; +//UNUSED2008-05 aShape.mxShape = xShape; +//UNUSED2008-05 rItr = std::lower_bound(rShapes.begin(), rShapes.end(), aShape, ScShapeChildLess()); +//UNUSED2008-05 if (rItr->mxShape.get() == xShape.get()) +//UNUSED2008-05 bResult = sal_True; // if the shape is found +//UNUSED2008-05 +//UNUSED2008-05 /*#ifdef DBG_UTIL // test whether it finds truly the correct shape (perhaps it is not really sorted) +//UNUSED2008-05 ScShapeChildVec::iterator aDebugItr = std::find(rShapes.begin(), rShapes.end(), aShape); +//UNUSED2008-05 DBG_ASSERT(rItr == aDebugItr, "wrong Shape found"); +//UNUSED2008-05 #endif*/ +//UNUSED2008-05 return bResult; +//UNUSED2008-05 } + +/*void ScShapeChilds::AddShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID) +{ + uno::Reference < XAccessible > xNew; + Window* pWin = mpViewShell->GetWindow(); + if (pWin) + { + ScShapeRangeVec::iterator aEndItr = maShapeRanges.end(); + ScShapeRangeVec::iterator aItr = maShapeRanges.begin(); + sal_Bool bNotify(sal_False); + uno::Reference <XAccessible> xAcc; + while (aItr != aEndItr) + { + Rectangle aLogicPaintRect(pWin->PixelToLogic(aItr->maPixelRect, aItr->maMapMode)); + Rectangle aRect(VCLPoint(xShape->getPosition()), VCLSize(xShape->getSize())); + if(!aRect.GetIntersection(aLogicPaintRect).IsEmpty()) + { + ScShapeChild aShape; + aShape.mxShape = xShape; + switch (aLayerID) + { + case SC_LAYER_INTERN: + case SC_LAYER_FRONT: + { + SetAnchor(aShape); + aItr->maForeShapes.push_back(aShape); + std::sort(aItr->maForeShapes.begin(), aItr->maForeShapes.end(),ScShapeChildLess()); + + } + break; + case SC_LAYER_BACK: + { + aItr->maBackShapes.push_back(aShape); + std::sort(aItr->maBackShapes.begin(), aItr->maBackShapes.end(),ScShapeChildLess()); + } + break; + case SC_LAYER_CONTROLS: + { + SetAnchor(aShape); + aItr->maControls.push_back(aShape); + std::sort(aItr->maControls.begin(), aItr->maControls.end(),ScShapeChildLess()); + } + break; + default: + { + DBG_ERRORFILE("I don't know this layer."); + } + break; + } + if (bNotify) + { + xAcc = GetAccShape(aShape); + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.NewValue <<= xAcc; + mpAccDoc->CommitChange(aEvent); + bNotify = sal_False; + } + xAcc = NULL; + } + ++aItr; + } + } +}*/ + +/*sal_Bool HaveToNotify(uno::Reference<XAccessible>& xAcc, ScShapeChildVec::iterator aItr) +{ + sal_Bool bResult(sal_False); + if (aItr->mpAccShape) + { + bResult = sal_True; + xAcc = aItr->mpAccShape; + } + else + DBG_ERRORFILE("No Accessible object found. Don't know how to notify."); + return bResult; +}*/ + +/*void ScShapeChilds::RemoveShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID) +{ + ScShapeRangeVec::iterator aEndItr = maShapeRanges.end(); + ScShapeRangeVec::iterator aItr = maShapeRanges.begin(); + ScShapeChildVec::iterator aEraseItr; + sal_Bool bNotify(sal_False); + uno::Reference <XAccessible> xAcc; + while (aItr != aEndItr) + { + switch (aLayerID) + { + case SC_LAYER_INTERN: + case SC_LAYER_FRONT: + { + if (FindShape(aItr->maForeShapes, xShape, aEraseItr)) + { + bNotify = HaveToNotify(xAcc, aEraseItr); + aItr->maForeShapes.erase(aEraseItr); + } + } + break; + case SC_LAYER_BACK: + { + if (FindShape(aItr->maBackShapes, xShape, aEraseItr)) + { + bNotify = HaveToNotify(xAcc, aEraseItr); + aItr->maBackShapes.erase(aEraseItr); + } + } + break; + case SC_LAYER_CONTROLS: + { + if (FindShape(aItr->maControls, xShape, aEraseItr)) + { + bNotify = HaveToNotify(xAcc, aEraseItr); + aItr->maControls.erase(aEraseItr); + } + } + break; + default: + { + DBG_ERRORFILE("I don't know this layer."); + } + break; + } + if (bNotify) + { + AccessibleEventObject aEvent; + aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc); + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.OldValue <<= xAcc; + mpAccDoc->CommitChange(aEvent); + bNotify = sal_False; + } + xAcc = NULL; + ++aItr; + } +}*/ + +SdrPage* ScShapeChilds::GetDrawPage() const +{ + SCTAB nTab( mpViewShell->GetLocationData().GetPrintTab() ); + SdrPage* pDrawPage = NULL; + if (mpViewShell) + { + ScDocument* pDoc = mpViewShell->GetDocument(); + if (pDoc && pDoc->GetDrawLayer()) + { + ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer(); + if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab)) + pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab))); + } + } + return pDrawPage; +} + +struct ScPagePreviewCountData +{ + // order is background shapes, header, table or notes, footer, foreground shapes, controls + + Rectangle aVisRect; + long nBackShapes; + long nHeaders; + long nTables; + long nNoteParagraphs; + long nFooters; + long nForeShapes; + long nControls; + + ScPagePreviewCountData( const ScPreviewLocationData& rData, Window* pSizeWindow, + ScNotesChilds* pNotesChilds, ScShapeChilds* pShapeChilds ); + + long GetTotal() const + { + return nBackShapes + nHeaders + nTables + nNoteParagraphs + nFooters + nForeShapes + nControls; + } +}; + +ScPagePreviewCountData::ScPagePreviewCountData( const ScPreviewLocationData& rData, + Window* pSizeWindow, ScNotesChilds* pNotesChilds, + ScShapeChilds* pShapeChilds) : + nBackShapes( 0 ), + nHeaders( 0 ), + nTables( 0 ), + nNoteParagraphs( 0 ), + nFooters( 0 ), + nForeShapes( 0 ), + nControls( 0 ) +{ + Size aOutputSize; + if ( pSizeWindow ) + aOutputSize = pSizeWindow->GetOutputSizePixel(); + Point aPoint; + aVisRect = Rectangle( aPoint, aOutputSize ); + + Rectangle aObjRect; + + if ( rData.GetHeaderPosition( aObjRect ) && aObjRect.IsOver( aVisRect ) ) + nHeaders = 1; + + if ( rData.GetFooterPosition( aObjRect ) && aObjRect.IsOver( aVisRect ) ) + nFooters = 1; + + if ( rData.HasCellsInRange( aVisRect ) ) + nTables = 1; + + //! shapes... + nBackShapes = pShapeChilds->GetBackShapeCount(); + nForeShapes = pShapeChilds->GetForeShapeCount(); + nControls = pShapeChilds->GetControlCount(); + + // there are only notes if there is no table + if (nTables == 0) + nNoteParagraphs = pNotesChilds->GetChildsCount(); +} + +//===== internal ======================================================== + +ScAccessibleDocumentPagePreview::ScAccessibleDocumentPagePreview( + const uno::Reference<XAccessible>& rxParent, ScPreviewShell* pViewShell ) : + ScAccessibleDocumentBase(rxParent), + mpViewShell(pViewShell), + mpNotesChilds(NULL), + mpShapeChilds(NULL), + mpTable(NULL), + mpHeader(NULL), + mpFooter(NULL) +{ + if (pViewShell) + pViewShell->AddAccessibilityObject(*this); + +// GetNotesChilds(); not neccessary and reduces the creation performance +// GetShapeChilds(); +} + +ScAccessibleDocumentPagePreview::~ScAccessibleDocumentPagePreview(void) +{ + if (!ScAccessibleDocumentBase::IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + // call dispose to inform object wich have a weak reference to this object + dispose(); + } +} + +void SAL_CALL ScAccessibleDocumentPagePreview::disposing() +{ + ScUnoGuard aGuard; + if (mpTable) + { + mpTable->release(); + mpTable = NULL; + } + if (mpHeader) + { + mpHeader->release(); + mpHeader = NULL; + } + if (mpFooter) + { + mpFooter->release(); + mpFooter = NULL; + } + + if (mpViewShell) + { + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + + // #100593# no need to Dispose the AccessibleTextHelper, + // as long as mpNotesChilds are destructed here + if (mpNotesChilds) + DELETEZ(mpNotesChilds); + + if (mpShapeChilds) + DELETEZ(mpShapeChilds); + + ScAccessibleDocumentBase::disposing(); +} + +//===== SfxListener ===================================================== + +void ScAccessibleDocumentPagePreview::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.ISA( SfxSimpleHint ) ) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + // only notify if child exist, otherwise it is not necessary + if ((rRef.GetId() == SC_HINT_DATACHANGED)) + { + if (mpTable) // if there is no table there is nothing to notify, because no one recongnizes the change + { + { + uno::Reference<XAccessible> xAcc = mpTable; + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.OldValue <<= xAcc; + CommitChange(aEvent); + } + + mpTable->dispose(); + mpTable->release(); + mpTable = NULL; + } + + Size aOutputSize; + Window* pSizeWindow = mpViewShell->GetWindow(); + if ( pSizeWindow ) + aOutputSize = pSizeWindow->GetOutputSizePixel(); + Point aPoint; + Rectangle aVisRect( aPoint, aOutputSize ); + GetNotesChilds()->DataChanged(aVisRect); + + GetShapeChilds()->DataChanged(); + + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); + + if (aCount.nTables > 0) + { + //! order is background shapes, header, table or notes, footer, foreground shapes, controls + sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders); + + mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex ); + mpTable->acquire(); + mpTable->Init(); + + { + uno::Reference<XAccessible> xAcc = mpTable; + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.NewValue <<= xAcc; + CommitChange(aEvent); + } + } + } + else if (rRef.GetId() == SC_HINT_ACC_MAKEDRAWLAYER) + { + GetShapeChilds()->SetDrawBroadcaster(); + } + else if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED) + { + Size aOutputSize; + Window* pSizeWindow = mpViewShell->GetWindow(); + if ( pSizeWindow ) + aOutputSize = pSizeWindow->GetOutputSizePixel(); + Point aPoint; + Rectangle aVisRect( aPoint, aOutputSize ); + GetNotesChilds()->DataChanged(aVisRect); + + GetShapeChilds()->VisAreaChanged(); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + CommitChange(aEvent); + } + } + else if ( rHint.ISA(ScAccWinFocusLostHint) ) + { + CommitFocusLost(); + } + else if ( rHint.ISA(ScAccWinFocusGotHint) ) + { + CommitFocusGained(); + } + ScAccessibleDocumentBase::Notify(rBC, rHint); +} + +//===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleAtPoint( const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xAccessible; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + + if ( mpViewShell ) + { + xAccessible = GetShapeChilds()->GetForegroundShapeAt(rPoint); + if (!xAccessible.is()) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); + +/* if ( rData.HasCellsInRange( Rectangle( rPoint, rPoint ) ) ) + { + if ( !mpTable && (aCount.nTables > 0) ) + { + //! order is background shapes, header, table or notes, footer, foreground shapes, controls + sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders); + + mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex ); + mpTable->acquire(); + mpTable->Init(); + } + xAccessible = mpTable; + }*/ + if ( !mpTable && (aCount.nTables > 0) ) + { + //! order is background shapes, header, table or notes, footer, foreground shapes, controls + sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders); + + mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex ); + mpTable->acquire(); + mpTable->Init(); + } + if (mpTable && VCLRectangle(mpTable->getBounds()).IsInside(VCLPoint(rPoint))) + xAccessible = mpTable; + } + if (!xAccessible.is()) + xAccessible = GetNotesChilds()->GetAt(rPoint); + if (!xAccessible.is()) + { + if (!mpHeader || !mpFooter) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); + + if (!mpHeader) + { + mpHeader = new ScAccessiblePageHeader( this, mpViewShell, sal_True, aCount.nBackShapes + aCount.nHeaders - 1); + mpHeader->acquire(); + } + if (!mpFooter) + { + mpFooter = new ScAccessiblePageHeader( this, mpViewShell, sal_False, aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters - 1 ); + mpFooter->acquire(); + } + } + + Point aPoint(VCLPoint(rPoint)); + + if (VCLRectangle(mpHeader->getBounds()).IsInside(aPoint)) + xAccessible = mpHeader; + else if (VCLRectangle(mpFooter->getBounds()).IsInside(aPoint)) + xAccessible = mpFooter; + } + if (!xAccessible.is()) + xAccessible = GetShapeChilds()->GetBackgroundShapeAt(rPoint); + } + } + + return xAccessible; +} + +void SAL_CALL ScAccessibleDocumentPagePreview::grabFocus() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + { + // just grab the focus for the window + xAccessibleComponent->grabFocus(); + } + } +} + +//===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChildCount(void) throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + long nRet = 0; + if ( mpViewShell ) + { + ScPagePreviewCountData aCount( mpViewShell->GetLocationData(), mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); + nRet = aCount.GetTotal(); + } + + return nRet; +} + +uno::Reference<XAccessible> SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Reference<XAccessible> xAccessible; + + if ( mpViewShell ) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); + + if ( nIndex < aCount.nBackShapes ) + { + xAccessible = GetShapeChilds()->GetBackShape(nIndex); + } + else if ( nIndex < aCount.nBackShapes + aCount.nHeaders ) + { + if ( !mpHeader ) + { + mpHeader = new ScAccessiblePageHeader( this, mpViewShell, sal_True, nIndex ); + mpHeader->acquire(); + } + + xAccessible = mpHeader; + } + else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables ) + { + if ( !mpTable ) + { + mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex ); + mpTable->acquire(); + mpTable->Init(); + } + xAccessible = mpTable; + } + else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nNoteParagraphs ) + { + xAccessible = GetNotesChilds()->GetChild(nIndex - aCount.nBackShapes - aCount.nHeaders); + } + else if ( (nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters) ) + { + if ( !mpFooter ) + { + mpFooter = new ScAccessiblePageHeader( this, mpViewShell, sal_False, nIndex ); + mpFooter->acquire(); + } + xAccessible = mpFooter; + } + else + { + sal_Int32 nIdx(nIndex - (aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters)); + if (nIdx < aCount.nForeShapes) + xAccessible = GetShapeChilds()->GetForeShape(nIdx); + else + xAccessible = GetShapeChilds()->GetControl(nIdx - aCount.nForeShapes); + } + } + + if ( !xAccessible.is() ) + throw lang::IndexOutOfBoundsException(); + + return xAccessible; +} + + /// Return the set of current states. +uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc(xParentStates)) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + // never editable + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::OPAQUE); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + + //===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleDocumentPagePreview::getImplementationName(void) + throw (uno::RuntimeException) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessibleDocumentPagePreview")); +} + +uno::Sequence< ::rtl::OUString> SAL_CALL ScAccessibleDocumentPagePreview::getSupportedServiceNames(void) + throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.AccessibleSpreadsheetPageView")); + + return aSequence; +} + +//===== XTypeProvider ======================================================= + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessibleDocumentPagePreview::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +//===== internal ======================================================== + +::rtl::OUString SAL_CALL ScAccessibleDocumentPagePreview::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + rtl::OUString sDescription = String(ScResId(STR_ACC_PREVIEWDOC_DESCR)); + return sDescription; +} + +::rtl::OUString SAL_CALL ScAccessibleDocumentPagePreview::createAccessibleName(void) + throw (uno::RuntimeException) +{ + rtl::OUString sName = String(ScResId(STR_ACC_PREVIEWDOC_NAME)); + return sName; +} + +Rectangle ScAccessibleDocumentPagePreview::GetBoundingBoxOnScreen() const throw (uno::RuntimeException) +{ + Rectangle aRect; + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindow(); + if (pWindow) + aRect = pWindow->GetWindowExtentsRelative(NULL); + } + return aRect; +} + +Rectangle ScAccessibleDocumentPagePreview::GetBoundingBox() const throw (uno::RuntimeException) +{ + Rectangle aRect; + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindow(); + if (pWindow) + aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow()); + } + return aRect; +} + +sal_Bool ScAccessibleDocumentPagePreview::IsDefunc( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +ScNotesChilds* ScAccessibleDocumentPagePreview::GetNotesChilds() +{ + if (!mpNotesChilds && mpViewShell) + { + mpNotesChilds = new ScNotesChilds(mpViewShell, this); + + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); + + //! order is background shapes, header, table or notes, footer, foreground shapes, controls + mpNotesChilds->Init(aCount.aVisRect, aCount.nBackShapes + aCount.nHeaders); + } + return mpNotesChilds; +} + +ScShapeChilds* ScAccessibleDocumentPagePreview::GetShapeChilds() +{ + if (!mpShapeChilds && mpViewShell) + { + mpShapeChilds = new ScShapeChilds(mpViewShell, this); + mpShapeChilds->Init(); + } + + return mpShapeChilds; +} + +//UNUSED2009-05 uno::Reference < XAccessible > ScAccessibleDocumentPagePreview::GetCurrentAccessibleTable() +//UNUSED2009-05 { +//UNUSED2009-05 if (!mpTable) +//UNUSED2009-05 { +//UNUSED2009-05 if ( mpViewShell ) +//UNUSED2009-05 { +//UNUSED2009-05 const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); +//UNUSED2009-05 ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); +//UNUSED2009-05 //! order is background shapes, header, table or notes, footer, foreground shapes, controls +//UNUSED2009-05 sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders); +//UNUSED2009-05 +//UNUSED2009-05 mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex ); +//UNUSED2009-05 mpTable->acquire(); +//UNUSED2009-05 mpTable->Init(); +//UNUSED2009-05 } +//UNUSED2009-05 } +//UNUSED2009-05 return mpTable; +//UNUSED2009-05 } + +//UNUSED2009-05 void ScAccessibleDocumentPagePreview::ChildCountChanged() +//UNUSED2009-05 { +//UNUSED2009-05 if (mpViewShell) +//UNUSED2009-05 { +//UNUSED2009-05 const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); +//UNUSED2009-05 ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChilds(), GetShapeChilds() ); +//UNUSED2009-05 //! order is background shapes, header, table or notes, footer, foreground shapes, controls +//UNUSED2009-05 if(mpHeader) +//UNUSED2009-05 mpHeader->SetCurrentIndexInParent(aCount.nBackShapes); +//UNUSED2009-05 if (mpTable) +//UNUSED2009-05 mpTable->SetCurrentIndexInParent(aCount.nBackShapes + aCount.nHeaders); +//UNUSED2009-05 if (mpFooter) +//UNUSED2009-05 mpFooter->SetCurrentIndexInParent(aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs); +//UNUSED2009-05 +//UNUSED2009-05 if (mpNotesChilds) +//UNUSED2009-05 mpNotesChilds->SetOffset(aCount.nBackShapes + aCount.nHeaders); +//UNUSED2009-05 } +//UNUSED2009-05 } diff --git a/sc/source/ui/Accessibility/AccessibleEditObject.cxx b/sc/source/ui/Accessibility/AccessibleEditObject.cxx new file mode 100644 index 000000000000..fd7cbaf454c1 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleEditObject.cxx @@ -0,0 +1,358 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" +#include "AccessibleEditObject.hxx" +#include "scitems.hxx" +#include <editeng/eeitem.hxx> +#include "unoguard.hxx" +#include "AccessibleText.hxx" +#include "editsrc.hxx" +#include "scmod.hxx" +#include "inputhdl.hxx" + +#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX +#include <unotools/accessiblestatesethelper.hxx> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#include <rtl/uuid.h> +#include <tools/debug.hxx> +#include <svx/AccessibleTextHelper.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> +#include <svx/svdmodel.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +ScAccessibleEditObject::ScAccessibleEditObject( + const uno::Reference<XAccessible>& rxParent, + EditView* pEditView, Window* pWin, const rtl::OUString& rName, + const rtl::OUString& rDescription, EditObjectType eObjectType) + : + ScAccessibleContextBase(rxParent, AccessibleRole::TEXT_FRAME), + mpTextHelper(NULL), + mpEditView(pEditView), + mpWindow(pWin), + meObjectType(eObjectType), + mbHasFocus(sal_False) +{ + CreateTextHelper(); + SetName(rName); + SetDescription(rDescription); +} + +ScAccessibleEditObject::~ScAccessibleEditObject() +{ + if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + // call dispose to inform object wich have a weak reference to this object + dispose(); + } +} + +void SAL_CALL ScAccessibleEditObject::disposing() +{ + ScUnoGuard aGuard; + if (mpTextHelper) + DELETEZ(mpTextHelper); + + ScAccessibleContextBase::disposing(); +} + +void ScAccessibleEditObject::LostFocus() +{ + mbHasFocus = sal_False; + if (mpTextHelper) + mpTextHelper->SetFocus(sal_False); + CommitFocusLost(); +} + +void ScAccessibleEditObject::GotFocus() +{ + mbHasFocus = sal_True; + CommitFocusGained(); + if (mpTextHelper) + mpTextHelper->SetFocus(sal_True); +} + + //===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessibleEditObject::getAccessibleAtPoint( + const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xRet; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + + if(!mpTextHelper) + CreateTextHelper(); + + xRet = mpTextHelper->GetAt(rPoint); + } + + return xRet; +} + +Rectangle ScAccessibleEditObject::GetBoundingBoxOnScreen(void) const + throw (uno::RuntimeException) +{ + Rectangle aScreenBounds; + + if ( mpWindow ) + { + if ( meObjectType == CellInEditMode ) + { + if ( mpEditView && mpEditView->GetEditEngine() ) + { + MapMode aMapMode( mpEditView->GetEditEngine()->GetRefMapMode() ); + aScreenBounds = mpWindow->LogicToPixel( mpEditView->GetOutputArea(), aMapMode ); + Point aCellLoc = aScreenBounds.TopLeft(); + Rectangle aWindowRect = mpWindow->GetWindowExtentsRelative( NULL ); + Point aWindowLoc = aWindowRect.TopLeft(); + Point aPos( aCellLoc.getX() + aWindowLoc.getX(), aCellLoc.getY() + aWindowLoc.getY() ); + aScreenBounds.SetPos( aPos ); + } + } + else + { + aScreenBounds = mpWindow->GetWindowExtentsRelative( NULL ); + } + } + + return aScreenBounds; +} + +Rectangle ScAccessibleEditObject::GetBoundingBox(void) const + throw (uno::RuntimeException) +{ + Rectangle aBounds( GetBoundingBoxOnScreen() ); + + if ( mpWindow ) + { + uno::Reference< XAccessible > xThis( mpWindow->GetAccessible() ); + if ( xThis.is() ) + { + uno::Reference< XAccessibleContext > xContext( xThis->getAccessibleContext() ); + if ( xContext.is() ) + { + uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() ); + if ( xParent.is() ) + { + uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY ); + if ( xParentComponent.is() ) + { + Point aScreenLoc = aBounds.TopLeft(); + awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen(); + Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y ); + aBounds.SetPos( aPos ); + } + } + } + } + } + + return aBounds; +} + + //===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL + ScAccessibleEditObject::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChildCount(); +} + +uno::Reference< XAccessible > SAL_CALL + ScAccessibleEditObject::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, + lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChild(nIndex); +} + +uno::Reference<XAccessibleStateSet> SAL_CALL + ScAccessibleEditObject::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc(xParentStates)) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + // all states are const, because this object exists only in one state + pStateSet->AddState(AccessibleStateType::EDITABLE); + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::SENSITIVE); + pStateSet->AddState(AccessibleStateType::MULTI_LINE); + pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE); + pStateSet->AddState(AccessibleStateType::SHOWING); + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + +::rtl::OUString SAL_CALL + ScAccessibleEditObject::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ +// DBG_ERRORFILE("Should never be called, because is set in the constructor.") + return rtl::OUString(); +} + +::rtl::OUString SAL_CALL + ScAccessibleEditObject::createAccessibleName(void) + throw (uno::RuntimeException) +{ + DBG_ERRORFILE("Should never be called, because is set in the constructor."); + return rtl::OUString(); +} + + ///===== XAccessibleEventBroadcaster ===================================== + +void SAL_CALL + ScAccessibleEditObject::addEventListener(const uno::Reference<XAccessibleEventListener>& xListener) + throw (uno::RuntimeException) +{ + if (!mpTextHelper) + CreateTextHelper(); + + mpTextHelper->AddEventListener(xListener); + + ScAccessibleContextBase::addEventListener(xListener); +} + +void SAL_CALL + ScAccessibleEditObject::removeEventListener(const uno::Reference<XAccessibleEventListener>& xListener) + throw (uno::RuntimeException) +{ + if (!mpTextHelper) + CreateTextHelper(); + + mpTextHelper->RemoveEventListener(xListener); + + ScAccessibleContextBase::removeEventListener(xListener); +} + + //===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleEditObject::getImplementationName(void) + throw (uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleEditObject")); +} + +//===== XTypeProvider ======================================================= + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessibleEditObject::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + + //==== internal ========================================================= + +sal_Bool ScAccessibleEditObject::IsDefunc( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +void ScAccessibleEditObject::CreateTextHelper() +{ + if (!mpTextHelper) + { + ::std::auto_ptr < ScAccessibleTextData > pAccessibleTextData; + if (meObjectType == CellInEditMode || meObjectType == EditControl) + { + pAccessibleTextData.reset + (new ScAccessibleEditObjectTextData(mpEditView, mpWindow)); + } + else + { + pAccessibleTextData.reset + (new ScAccessibleEditLineTextData(NULL, mpWindow)); + } + + ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleTextData)); + mpTextHelper = new ::accessibility::AccessibleTextHelper(pEditSource ); + mpTextHelper->SetEventSource(this); + mpTextHelper->SetFocus(mbHasFocus); + + // #i54814# activate cell in edit mode + if( meObjectType == CellInEditMode ) + { + // do not activate cell object, if top edit line is active + const ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(); + if( pInputHdl && !pInputHdl->IsTopMode() ) + { + SdrHint aHint( HINT_BEGEDIT ); + mpTextHelper->GetEditSource().GetBroadcaster().Broadcast( aHint ); + } + } + } +} + diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx new file mode 100644 index 000000000000..02fb5c12463e --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleFilterMenu.cxx @@ -0,0 +1,398 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleGlobal.hxx" +#include "AccessibleFilterMenu.hxx" +#include "AccessibleFilterMenuItem.hxx" +#include "unoguard.hxx" +#include "global.hxx" +#include "document.hxx" +#include "docpool.hxx" + +#include "tools/gen.hxx" +#include "editeng/unoedsrc.hxx" +#include "editeng/editdata.hxx" +#include "editeng/outliner.hxx" +#include "vcl/unohelp.hxx" +#include "dpcontrol.hxx" + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::accessibility::AccessibleStateType; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::uno::RuntimeException; +using ::rtl::OUString; +using ::std::for_each; +using ::std::vector; + +// ============================================================================ + +namespace { + +class AddRemoveEventListener : public ::std::unary_function<void, Reference<XAccessible> > +{ +public: + explicit AddRemoveEventListener(const Reference<XAccessibleEventListener>& rListener, bool bAdd) : + mxListener(rListener), mbAdd(bAdd) {} + + void operator() (const Reference<XAccessible>& xAccessible) const + { + if (!xAccessible.is()) + return; + + Reference<XAccessibleEventBroadcaster> xBc(xAccessible, UNO_QUERY); + if (xBc.is()) + { + if (mbAdd) + xBc->addEventListener(mxListener); + else + xBc->removeEventListener(mxListener); + } + } +private: + Reference<XAccessibleEventListener> mxListener; + bool mbAdd; +}; + +} + +// ============================================================================ + +ScAccessibleFilterMenu::ScAccessibleFilterMenu(const Reference<XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos, ScDocument* pDoc) : + ScAccessibleContextBase(rxParent, AccessibleRole::MENU), + mnMenuPos(nMenuPos), + mpWindow(pWin), + mpDoc(pDoc), + mbEnabled(true) +{ + SetName(rName); +} + +ScAccessibleFilterMenu::~ScAccessibleFilterMenu() +{ +} + +// XAccessibleComponent + +Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleAtPoint( const ::com::sun::star::awt::Point& /*rPoint*/ ) + throw (RuntimeException) +{ + return this; +} + +sal_Bool ScAccessibleFilterMenu::isVisible() throw (RuntimeException) +{ + return mpWindow->IsVisible(); +} + +void ScAccessibleFilterMenu::grabFocus() + throw (RuntimeException) +{ +} + +sal_Int32 ScAccessibleFilterMenu::getForeground() + throw (RuntimeException) +{ + return 0; +} + +sal_Int32 ScAccessibleFilterMenu::getBackground() + throw (RuntimeException) +{ + return 0; +} + +// XAccessibleContext + +OUString ScAccessibleFilterMenu::getAccessibleName() throw (RuntimeException) +{ + return ScAccessibleContextBase::getAccessibleName(); +} + +sal_Int32 ScAccessibleFilterMenu::getAccessibleChildCount() + throw (RuntimeException) +{ + return getMenuItemCount(); +} + +Reference<XAccessible> ScAccessibleFilterMenu::getAccessibleChild(sal_Int32 nIndex) + throw (RuntimeException, IndexOutOfBoundsException) +{ + if (maMenuItems.size() <= static_cast<size_t>(nIndex)) + throw IndexOutOfBoundsException(); + + return maMenuItems[nIndex]; +} + +Reference<XAccessibleStateSet> ScAccessibleFilterMenu::getAccessibleStateSet() + throw (RuntimeException) +{ + updateStates(); + return mxStateSet; +} + +OUString ScAccessibleFilterMenu::getImplementationName() + throw (RuntimeException) +{ + return OUString::createFromAscii("ScAccessibleFilterMenu"); +} + +// XAccessibleEventBroadcaster + +void ScAccessibleFilterMenu::addEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener>& xListener) + throw (com::sun::star::uno::RuntimeException) +{ + ScAccessibleContextBase::addEventListener(xListener); + for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, true)); +} + +void ScAccessibleFilterMenu::removeEventListener( + const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessibleEventListener>& xListener) + throw (com::sun::star::uno::RuntimeException) +{ + ScAccessibleContextBase::removeEventListener(xListener); + for_each(maMenuItems.begin(), maMenuItems.end(), AddRemoveEventListener(xListener, false)); +} + +// XAccessibleSelection + +void ScAccessibleFilterMenu::selectAccessibleChild(sal_Int32 nChildIndex) + throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + mpWindow->setSelectedMenuItem(nChildIndex, false, true); +} + +sal_Bool ScAccessibleFilterMenu::isAccessibleChildSelected(sal_Int32 nChildIndex) + throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + return mpWindow->isMenuItemSelected(static_cast<size_t>(nChildIndex)); +} + +void ScAccessibleFilterMenu::clearAccessibleSelection() throw (RuntimeException) +{ + mpWindow->clearSelectedMenuItem(); +} + +void ScAccessibleFilterMenu::selectAllAccessibleChildren() throw (RuntimeException) +{ + // not suported - this is a menu, you can't select all menu items. +} + +sal_Int32 ScAccessibleFilterMenu::getSelectedAccessibleChildCount() throw (RuntimeException) +{ + // Since this is a menu, either one menu item is selected, or none at all. + return mpWindow->getSelectedMenuItem() == ScMenuFloatingWindow::MENU_NOT_SELECTED ? 0 : 1; +} + +Reference<XAccessible> ScAccessibleFilterMenu::getSelectedAccessibleChild(sal_Int32 nChildIndex) + throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + return maMenuItems[nChildIndex]; +} + +void ScAccessibleFilterMenu::deselectAccessibleChild(sal_Int32 nChildIndex) throw (IndexOutOfBoundsException, RuntimeException) +{ + if (static_cast<size_t>(nChildIndex) >= maMenuItems.size()) + throw IndexOutOfBoundsException(); + + mpWindow->selectMenuItem(nChildIndex, false, false); +} + +// XInterface + +uno::Any SAL_CALL ScAccessibleFilterMenu::queryInterface( uno::Type const & rType ) + throw (RuntimeException) +{ + Any any = ScAccessibleContextBase::queryInterface(rType); + if (any.hasValue()) + return any; + + return ScAccessibleFilterMenu_BASE::queryInterface(rType); +} + +void SAL_CALL ScAccessibleFilterMenu::acquire() throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessibleFilterMenu::release() throw () +{ + ScAccessibleContextBase::release(); +} + +// XTypeProvider + +Sequence<sal_Int8> ScAccessibleFilterMenu::getImplementationId() + throw (RuntimeException) +{ + Sequence<sal_Int8> aId(16); + return aId; +} + +Rectangle ScAccessibleFilterMenu::GetBoundingBoxOnScreen() const + throw (RuntimeException) +{ + if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED) + return Rectangle(); + + // Menu object's bounding box is the bounding box of the menu item that + // launches the menu, which belongs to the parent window. + ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow(); + if (!pParentWin) + return Rectangle(); + + if (!pParentWin->IsVisible()) + return Rectangle(); + + Point aPos = pParentWin->OutputToAbsoluteScreenPixel(Point(0,0)); + Point aMenuPos; + Size aMenuSize; + pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aPos + aMenuPos, aMenuSize); + return aRect; +} + +Rectangle ScAccessibleFilterMenu::GetBoundingBox() const + throw (RuntimeException) +{ + if (mnMenuPos == ScMenuFloatingWindow::MENU_NOT_SELECTED) + return Rectangle(); + + // Menu object's bounding box is the bounding box of the menu item that + // launches the menu, which belongs to the parent window. + ScMenuFloatingWindow* pParentWin = mpWindow->getParentMenuWindow(); + if (!pParentWin) + return Rectangle(); + + if (!pParentWin->IsVisible()) + return Rectangle(); + + Point aMenuPos; + Size aMenuSize; + pParentWin->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aMenuPos, aMenuSize); + return aRect; +} + +void ScAccessibleFilterMenu::appendMenuItem(const OUString& rName, bool bEnabled, size_t nMenuPos) +{ + // Check weather this menu item is a sub menu or a regular menu item. + ScMenuFloatingWindow* pSubMenu = mpWindow->getSubMenuWindow(nMenuPos); + Reference<XAccessible> xAccessible; + if (pSubMenu) + { + xAccessible = pSubMenu->CreateAccessible(); + ScAccessibleFilterMenu* p = + static_cast<ScAccessibleFilterMenu*>(xAccessible.get()); + p->setEnabled(bEnabled); + p->setMenuPos(nMenuPos); + } + else + { + xAccessible.set(new ScAccessibleFilterMenuItem(this, mpWindow, rName, nMenuPos)); + ScAccessibleFilterMenuItem* p = + static_cast<ScAccessibleFilterMenuItem*>(xAccessible.get()); + p->setEnabled(bEnabled); + } + maMenuItems.push_back(xAccessible); +} + +void ScAccessibleFilterMenu::setMenuPos(size_t nMenuPos) +{ + mnMenuPos = nMenuPos; +} + +void ScAccessibleFilterMenu::setEnabled(bool bEnabled) +{ + mbEnabled = bEnabled; +} + +sal_Int32 ScAccessibleFilterMenu::getMenuItemCount() const +{ + return maMenuItems.size(); +} + +bool ScAccessibleFilterMenu::isSelected() const +{ + // Check to see if any of the child menu items is selected. + return mpWindow->isMenuItemSelected(mnMenuPos); +} + +bool ScAccessibleFilterMenu::isFocused() const +{ + return isSelected(); +} + +void ScAccessibleFilterMenu::updateStates() +{ + if (!mxStateSet.is()) + mxStateSet.set(new ScAccessibleStateSet); + + ScAccessibleStateSet* p = static_cast<ScAccessibleStateSet*>( + mxStateSet.get()); + + p->clear(); + + p->insert(ENABLED); + p->insert(FOCUSABLE); + p->insert(SELECTABLE); + p->insert(SENSITIVE); + p->insert(OPAQUE); + + if (isFocused()) + p->insert(FOCUSED); + + if (isSelected()) + p->insert(SELECTED); +} diff --git a/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx b/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx new file mode 100644 index 000000000000..0da1e6858a75 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleFilterMenuItem.cxx @@ -0,0 +1,205 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleGlobal.hxx" +#include "AccessibleFilterMenuItem.hxx" +#include "dpcontrol.hxx" + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleStateSet.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleEventObject.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/TextSegment.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::accessibility::AccessibleStateType; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::uno::RuntimeException; +using ::rtl::OUString; + +ScAccessibleFilterMenuItem::ScAccessibleFilterMenuItem( + const Reference<XAccessible>& rxParent, ScMenuFloatingWindow* pWin, const OUString& rName, size_t nMenuPos) : + ScAccessibleContextBase(rxParent, AccessibleRole::MENU_ITEM), + mpWindow(pWin), + maName(rName), + mnMenuPos(nMenuPos), + mbEnabled(true) +{ + SetName(rName); +} + +ScAccessibleFilterMenuItem::~ScAccessibleFilterMenuItem() +{ +} + +sal_Int32 ScAccessibleFilterMenuItem::getAccessibleChildCount() + throw (RuntimeException) +{ + return 0; +} + +Reference<XAccessible> ScAccessibleFilterMenuItem::getAccessibleChild(sal_Int32 /*nIndex*/) + throw (RuntimeException, IndexOutOfBoundsException) +{ + throw IndexOutOfBoundsException(); +} + +Reference<XAccessibleStateSet> ScAccessibleFilterMenuItem::getAccessibleStateSet() + throw (RuntimeException) +{ + updateStateSet(); + return mxStateSet; +} + +OUString ScAccessibleFilterMenuItem::getImplementationName() + throw (RuntimeException) +{ + return OUString::createFromAscii("ScAccessibleFilterMenuItem"); +} + +// XAccessibleAction + +sal_Int32 ScAccessibleFilterMenuItem::getAccessibleActionCount() throw (RuntimeException) +{ + return 1; +} + +sal_Bool ScAccessibleFilterMenuItem::doAccessibleAction(sal_Int32 /*nIndex*/) + throw (IndexOutOfBoundsException, RuntimeException) +{ + mpWindow->executeMenuItem(mnMenuPos); + return true; +} + +OUString ScAccessibleFilterMenuItem::getAccessibleActionDescription(sal_Int32 /*nIndex*/) + throw (IndexOutOfBoundsException, RuntimeException) +{ + return OUString::createFromAscii("click"); +} + +Reference<XAccessibleKeyBinding> ScAccessibleFilterMenuItem::getAccessibleActionKeyBinding( + sal_Int32 /*nIndex*/) throw (IndexOutOfBoundsException, RuntimeException) +{ + return Reference<XAccessibleKeyBinding>(); +} + +Any SAL_CALL ScAccessibleFilterMenuItem::queryInterface( uno::Type const & rType ) + throw (RuntimeException) +{ + Any any = ScAccessibleContextBase::queryInterface(rType); + if (any.hasValue()) + return any; + + return ScAccessibleFilterMenuItem_BASE::queryInterface(rType); +} + +void SAL_CALL ScAccessibleFilterMenuItem::acquire() throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessibleFilterMenuItem::release() throw () +{ + ScAccessibleContextBase::release(); +} + +bool ScAccessibleFilterMenuItem::isSelected() const +{ + return mpWindow->isMenuItemSelected(mnMenuPos); +} + +bool ScAccessibleFilterMenuItem::isFocused() const +{ + return isSelected(); +} + +void ScAccessibleFilterMenuItem::setEnabled(bool bEnabled) +{ + mbEnabled = bEnabled; +} + +Rectangle ScAccessibleFilterMenuItem::GetBoundingBoxOnScreen() const + throw (RuntimeException) +{ + if (!mpWindow->IsVisible()) + return Rectangle(); + + Point aPos = mpWindow->OutputToAbsoluteScreenPixel(Point(0,0)); + Point aMenuPos; + Size aMenuSize; + mpWindow->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aPos + aMenuPos, aMenuSize); + return aRect; +} + +Rectangle ScAccessibleFilterMenuItem::GetBoundingBox() const + throw (RuntimeException) +{ + if (!mpWindow->IsVisible()) + return Rectangle(); + + Point aMenuPos; + Size aMenuSize; + mpWindow->getMenuItemPosSize(mnMenuPos, aMenuPos, aMenuSize); + Rectangle aRect(aMenuPos, aMenuSize); + return aRect; +} + +void ScAccessibleFilterMenuItem::updateStateSet() +{ + if (!mxStateSet.is()) + mxStateSet.set(new ScAccessibleStateSet); + + ScAccessibleStateSet* p = static_cast<ScAccessibleStateSet*>( + mxStateSet.get()); + + p->clear(); + + p->insert(ENABLED); + p->insert(FOCUSABLE); + p->insert(SELECTABLE); + p->insert(SENSITIVE); + p->insert(OPAQUE); + + if (isFocused()) + p->insert(FOCUSED); + + if (isSelected()) + p->insert(SELECTED); +} + diff --git a/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx b/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx new file mode 100644 index 000000000000..2af69faa33c8 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleFilterTopWindow.cxx @@ -0,0 +1,127 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleFilterTopWindow.hxx" +#include "AccessibleFilterMenu.hxx" +#include "dpcontrol.hxx" + +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::RuntimeException; +using ::rtl::OUString; + +ScAccessibleFilterTopWindow::ScAccessibleFilterTopWindow( + const Reference<XAccessible>& rxParent, ScDPFieldPopupWindow* pWin, const OUString& rName, ScDocument* pDoc) : + ScAccessibleFilterMenu(rxParent, pWin, rName, ScMenuFloatingWindow::MENU_NOT_SELECTED, pDoc), + mpWindow(pWin), + mpDoc(pDoc) +{ + SetName(rName); +} + +ScAccessibleFilterTopWindow::~ScAccessibleFilterTopWindow() +{ +} + +// XAccessibleContext + +sal_Int32 ScAccessibleFilterTopWindow::getAccessibleChildCount() throw (RuntimeException) +{ + sal_Int32 nMenuCount = getMenuItemCount(); + return nMenuCount + 6; +} + +Reference<XAccessible> ScAccessibleFilterTopWindow::getAccessibleChild( + sal_Int32 nIndex) throw (RuntimeException, IndexOutOfBoundsException) +{ + if (nIndex >= getAccessibleChildCount()) + throw IndexOutOfBoundsException(); + + sal_Int32 nMenuCount = getMenuItemCount(); + if (nIndex < nMenuCount) + return ScAccessibleFilterMenu::getAccessibleChild(nIndex); + + nIndex -= nMenuCount; + switch (nIndex) + { + case 0: + return mxAccListBox; + case 1: + return mxAccToggleAll; + case 2: + return mxAccSingleOnBtn; + case 3: + return mxAccSingleOffBtn; + case 4: + return mxAccOkBtn; + case 5: + return mxAccCancelBtn; + default: + ; + } + + return Reference<XAccessible>(); +} + +OUString ScAccessibleFilterTopWindow::getImplementationName() throw (RuntimeException) +{ + return OUString::createFromAscii("ScAccessibleFilterTopWindow"); +} + +void ScAccessibleFilterTopWindow::setAccessibleChild( + const Reference<XAccessible>& rAccessible, ChildControlType eType) +{ + switch (eType) + { + case LISTBOX: + mxAccListBox = rAccessible; + break; + case TOGGLE_ALL: + mxAccToggleAll = rAccessible; + break; + case SINGLE_ON_BTN: + mxAccSingleOnBtn = rAccessible; + break; + case SINGLE_OFF_BTN: + mxAccSingleOffBtn = rAccessible; + break; + case OK_BTN: + mxAccOkBtn = rAccessible; + break; + case CANCEL_BTN: + mxAccCancelBtn = rAccessible; + break; + } +} + diff --git a/sc/source/ui/Accessibility/AccessibleGlobal.cxx b/sc/source/ui/Accessibility/AccessibleGlobal.cxx new file mode 100644 index 000000000000..ac2562fa9bd5 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleGlobal.cxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +#include "precompiled_sc.hxx" +#include "AccessibleGlobal.hxx" + +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::std::set; + +ScAccessibleStateSet::ScAccessibleStateSet() +{ +} + +ScAccessibleStateSet::~ScAccessibleStateSet() +{ +} + +// XAccessibleStateSet + +sal_Bool SAL_CALL ScAccessibleStateSet::isEmpty() throw (RuntimeException) +{ + return maStates.empty(); +} + +sal_Bool SAL_CALL ScAccessibleStateSet::contains(sal_Int16 nState) + throw (RuntimeException) +{ + return maStates.count(nState) != 0; +} + +sal_Bool SAL_CALL ScAccessibleStateSet::containsAll( + const Sequence<sal_Int16>& aStateSet) throw (RuntimeException) +{ + sal_Int32 n = aStateSet.getLength(); + for (sal_Int32 i = 0; i < n; ++i) + { + if (!maStates.count(aStateSet[i])) + // This state is not set. + return false; + } + // All specified states are set. + return true; +} + +Sequence<sal_Int16> SAL_CALL ScAccessibleStateSet::getStates() + throw (RuntimeException) +{ + Sequence<sal_Int16> aSeq(0); + set<sal_Int16>::const_iterator itr = maStates.begin(), itrEnd = maStates.end(); + for (size_t i = 0; itr != itrEnd; ++itr, ++i) + { + aSeq.realloc(i+1); + aSeq[i] = *itr; + } + return aSeq; +} + +void ScAccessibleStateSet::insert(sal_Int16 nState) +{ + maStates.insert(nState); +} + +void ScAccessibleStateSet::clear() +{ + maStates.clear(); +} + diff --git a/sc/source/ui/Accessibility/AccessiblePageHeader.cxx b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx new file mode 100644 index 000000000000..6c28d22b0236 --- /dev/null +++ b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx @@ -0,0 +1,441 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +#include "AccessiblePageHeader.hxx" +#include "AccessiblePageHeaderArea.hxx" +#include "AccessibilityHints.hxx" +#include "prevwsh.hxx" +#include "unoguard.hxx" +#include "miscuno.hxx" +#include "prevloc.hxx" +#include "document.hxx" +#include "stlpool.hxx" +#include "scitems.hxx" +#include "attrib.hxx" +#include "scresid.hxx" +#ifndef SC_SC_HRC +#include "sc.hrc" +#endif + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> + +#include <vcl/window.hxx> +#include <svl/smplhint.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <svl/style.hxx> +#include <svl/itempool.hxx> +#include <editeng/editobj.hxx> +#include <toolkit/helper/convert.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +const sal_uInt8 MAX_AREAS = 3; + +//===== internal ============================================================ +struct Acquire +{ + void operator() (ScAccessiblePageHeaderArea* pArea) + { + if (pArea) + pArea->acquire(); + } +}; + +struct Release +{ + void operator() (ScAccessiblePageHeaderArea*& pArea) + { + if (pArea) + pArea->release(); + } +}; + +struct Dispose +{ + void operator() (ScAccessiblePageHeaderArea*& pArea) + { + if (pArea) + { + pArea->dispose(); + pArea->release(); + } + pArea = NULL; + } +}; + +ScAccessiblePageHeader::ScAccessiblePageHeader( const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, + ScPreviewShell* pViewShell, sal_Bool bHeader, sal_Int32 nIndex ) : +ScAccessibleContextBase( rxParent, bHeader ? AccessibleRole::HEADER : AccessibleRole::FOOTER ), + mpViewShell( pViewShell ), + mnIndex( nIndex ), + mbHeader( bHeader ), + maAreas(MAX_AREAS, NULL), + mnChildCount(-1) +{ + if (mpViewShell) + mpViewShell->AddAccessibilityObject(*this); +} + +ScAccessiblePageHeader::~ScAccessiblePageHeader() +{ + if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + dispose(); + } +} + +void SAL_CALL ScAccessiblePageHeader::disposing() +{ + ScUnoGuard aGuard; + if (mpViewShell) + { + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + std::for_each(maAreas.begin(), maAreas.end(), Dispose()); + + ScAccessibleContextBase::disposing(); +} + +//===== SfxListener ===================================================== + +void ScAccessiblePageHeader::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.ISA( SfxSimpleHint ) ) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + // only notify if child exist, otherwise it is not necessary + if ((rRef.GetId() == SC_HINT_DATACHANGED)) + { + ScHFAreas aOldAreas(maAreas); + std::for_each(aOldAreas.begin(), aOldAreas.end(), Acquire()); + mnChildCount = -1; + getAccessibleChildCount(); + for (sal_uInt8 i = 0; i < MAX_AREAS; ++i) + { + if ((aOldAreas[i] && maAreas[i] && !ScGlobal::EETextObjEqual(aOldAreas[i]->GetEditTextObject(), maAreas[i]->GetEditTextObject())) || + (aOldAreas[i] && !maAreas[i]) || (!aOldAreas[i] && maAreas[i])) + { + if (aOldAreas[i] && aOldAreas[i]->GetEditTextObject()) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.OldValue = uno::makeAny(uno::Reference<XAccessible>(aOldAreas[i])); + + CommitChange(aEvent); // child gone - event + aOldAreas[i]->dispose(); + } + if (maAreas[i] && maAreas[i]->GetEditTextObject()) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::CHILD; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.NewValue = uno::makeAny(uno::Reference<XAccessible>(maAreas[i])); + + CommitChange(aEvent); // new child - event + } + } + } + std::for_each(aOldAreas.begin(), aOldAreas.end(), Release()); + } + 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); +} + +//===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleAtPoint( const awt::Point& aPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xRet; + + if (containsPoint(aPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + + sal_Int32 nCount(getAccessibleChildCount()); // fill the areas + + if (nCount) + { + // return the first with content, because they have all the same Bounding Box + sal_uInt8 i(0); + while(!xRet.is() && i < MAX_AREAS) + { + if (maAreas[i]) + xRet = maAreas[i]; + else + ++i; + } + } + } + + return xRet; +} + +void SAL_CALL ScAccessiblePageHeader::grabFocus() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + xAccessibleComponent->grabFocus(); + } +} + +//===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleChildCount() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if((mnChildCount < 0) && mpViewShell) + { + mnChildCount = 0; + ScDocument* pDoc = mpViewShell->GetDocument(); + if (pDoc) + { + // find out how many regions (left,center, right) are with content + + SfxStyleSheetBase* pStyle = pDoc->GetStyleSheetPool()->Find(pDoc->GetPageStyle(mpViewShell->GetLocationData().GetPrintTab()), SFX_STYLE_FAMILY_PAGE); + if (pStyle) + { + sal_uInt16 nPageWhichId(0); + if (mbHeader) + nPageWhichId = mpViewShell->GetLocationData().IsHeaderLeft() ? ATTR_PAGE_HEADERLEFT : ATTR_PAGE_HEADERRIGHT; + else + nPageWhichId = mpViewShell->GetLocationData().IsFooterLeft() ? ATTR_PAGE_FOOTERLEFT : ATTR_PAGE_FOOTERRIGHT; + + const ScPageHFItem& rPageItem = static_cast<const ScPageHFItem&>(pStyle->GetItemSet().Get(nPageWhichId)); + AddChild(rPageItem.GetLeftArea(), 0, SVX_ADJUST_LEFT); + AddChild(rPageItem.GetCenterArea(), 1, SVX_ADJUST_CENTER); + AddChild(rPageItem.GetRightArea(), 2, SVX_ADJUST_RIGHT); + } + } + } + + return mnChildCount; +} + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleChild( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + uno::Reference<XAccessible> xRet; + + if(mnChildCount < 0) + getAccessibleChildCount(); + + ScHFAreas::iterator aItr = maAreas.begin(); + ScHFAreas::iterator aEndItr = maAreas.end(); + while (!xRet.is() && (nIndex >= 0) && (aItr != aEndItr)) + { + if (*aItr) + { + if (nIndex == 0) + xRet = *aItr; + else + --nIndex; + } + else + ++aItr; + } + + if ( !xRet.is() ) + throw lang::IndexOutOfBoundsException(); + + return xRet; +} + +sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleIndexInParent() throw (uno::RuntimeException) +{ + return mnIndex; +} + +uno::Reference< XAccessibleStateSet > SAL_CALL ScAccessiblePageHeader::getAccessibleStateSet() + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc(xParentStates)) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::OPAQUE); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + +//===== XServiceInfo ==================================================== + +rtl::OUString SAL_CALL ScAccessiblePageHeader::getImplementationName() throw(uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessiblePageHeader")); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScAccessiblePageHeader::getSupportedServiceNames() + throw(uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.AccessibleHeaderFooterView")); + + return aSequence; +} + +//==== internal ========================================================= + +::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + String sDesc(ScResId(mbHeader ? STR_ACC_HEADER_DESCR : STR_ACC_FOOTER_DESCR)); + sDesc.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN))); + return rtl::OUString( sDesc ); +} + +::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleName(void) + throw (uno::RuntimeException) +{ + String sName(ScResId(mbHeader ? STR_ACC_HEADER_NAME : STR_ACC_FOOTER_NAME)); + sName.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN))); + return rtl::OUString( sName ); +} + +Rectangle ScAccessiblePageHeader::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 ScAccessiblePageHeader::GetBoundingBox() const throw (uno::RuntimeException) +{ + Rectangle aRect; + if (mpViewShell) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + if ( mbHeader ) + rData.GetHeaderPosition( aRect ); + else + rData.GetFooterPosition( aRect ); + + // the Rectangle could contain negative coordinates so it should be cliped + Rectangle aClipRect(Point(0, 0), aRect.GetSize()); + Window* pWindow = mpViewShell->GetWindow(); + if (pWindow) + aClipRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow()); + aRect = aClipRect.GetIntersection(aRect); + } + if (aRect.IsEmpty()) + aRect.SetSize(Size(-1, -1)); + + return aRect; +} + +sal_Bool ScAccessiblePageHeader::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates ) +{ + return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +void ScAccessiblePageHeader::AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust) +{ + if (pArea && (pArea->GetText(0).Len() || (pArea->GetParagraphCount() > 1))) + { + if (maAreas[nIndex]) + { + if (!ScGlobal::EETextObjEqual(maAreas[nIndex]->GetEditTextObject(), pArea)) + { + maAreas[nIndex]->release(); + maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust); + maAreas[nIndex]->acquire(); + } + } + else + { + maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust); + maAreas[nIndex]->acquire(); + } + ++mnChildCount; + } + else + { + if (maAreas[nIndex]) + { + maAreas[nIndex]->release(); + maAreas[nIndex] = NULL; + } + } +} diff --git a/sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx b/sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx new file mode 100644 index 000000000000..10c6a9eff13f --- /dev/null +++ b/sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx @@ -0,0 +1,330 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" +#include <tools/gen.hxx> +#include "AccessiblePageHeaderArea.hxx" +#include "AccessibleText.hxx" +#include "AccessibilityHints.hxx" +#include "unoguard.hxx" +#include "editsrc.hxx" +#include "prevwsh.hxx" +#include "prevloc.hxx" +#include "scresid.hxx" +#ifndef SC_SC_HRC +#include "sc.hrc" +#endif + +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <editeng/editobj.hxx> +#include <svx/AccessibleTextHelper.hxx> +#include <rtl/uuid.h> +#include <unotools/accessiblestatesethelper.hxx> +#include <rtl/ustrbuf.hxx> +#include <toolkit/helper/convert.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + + //===== internal ======================================================== + +ScAccessiblePageHeaderArea::ScAccessiblePageHeaderArea( + const uno::Reference<XAccessible>& rxParent, + ScPreviewShell* pViewShell, + const EditTextObject* pEditObj, + sal_Bool bHeader, + SvxAdjust eAdjust) + : ScAccessibleContextBase(rxParent, AccessibleRole::TEXT), + mpEditObj(pEditObj->Clone()), + mpTextHelper(NULL), + mpViewShell(pViewShell), + mbHeader(bHeader), + meAdjust(eAdjust) +{ + if (mpViewShell) + mpViewShell->AddAccessibilityObject(*this); +} + +ScAccessiblePageHeaderArea::~ScAccessiblePageHeaderArea(void) +{ + if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + dispose(); + } +} + +void SAL_CALL ScAccessiblePageHeaderArea::disposing() +{ + ScUnoGuard aGuard; + if (mpViewShell) + { + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + if (mpTextHelper) + DELETEZ(mpTextHelper); + if (mpEditObj) + DELETEZ(mpEditObj); + + ScAccessibleContextBase::disposing(); +} + +//===== SfxListener ===================================================== + +void ScAccessiblePageHeaderArea::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.ISA( SfxSimpleHint ) ) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + // only notify if child exist, otherwise it is not necessary + if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED) + { + if (mpTextHelper) + mpTextHelper->UpdateChildren(); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + CommitChange(aEvent); + } + } + ScAccessibleContextBase::Notify(rBC, rHint); +} + //===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeaderArea::getAccessibleAtPoint( + const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xRet; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + + if(!mpTextHelper) + CreateTextHelper(); + + xRet = mpTextHelper->GetAt(rPoint); + } + + return xRet; +} + + //===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL + ScAccessiblePageHeaderArea::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChildCount(); +} + +uno::Reference< XAccessible > SAL_CALL + ScAccessiblePageHeaderArea::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, + lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChild(nIndex); +} + +uno::Reference<XAccessibleStateSet> SAL_CALL + ScAccessiblePageHeaderArea::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc()) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::MULTI_LINE); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + +//===== XServiceInfo ======================================================== + +::rtl::OUString SAL_CALL + ScAccessiblePageHeaderArea::getImplementationName(void) + throw (uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessiblePageHeaderArea")); +} + +uno::Sequence< ::rtl::OUString> SAL_CALL + ScAccessiblePageHeaderArea::getSupportedServiceNames(void) + throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.AccessiblePageHeaderFooterAreasView")); + + return aSequence; +} + +//===== XTypeProvider ======================================================= + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessiblePageHeaderArea::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +//===== internal ============================================================== +rtl::OUString SAL_CALL ScAccessiblePageHeaderArea::createAccessibleDescription(void) + throw(uno::RuntimeException) +{ + rtl::OUString sDesc; + switch (meAdjust) + { + case SVX_ADJUST_LEFT : + sDesc = String(ScResId(STR_ACC_LEFTAREA_DESCR)); + break; + case SVX_ADJUST_RIGHT: + sDesc = String(ScResId(STR_ACC_RIGHTAREA_DESCR)); + break; + case SVX_ADJUST_CENTER: + sDesc = String(ScResId(STR_ACC_CENTERAREA_DESCR)); + break; + default: + DBG_ERRORFILE("wrong adjustment found"); + } + + return sDesc; +} + +rtl::OUString SAL_CALL ScAccessiblePageHeaderArea::createAccessibleName(void) + throw (uno::RuntimeException) +{ + rtl::OUString sName; + switch (meAdjust) + { + case SVX_ADJUST_LEFT : + sName = String(ScResId(STR_ACC_LEFTAREA_NAME)); + break; + case SVX_ADJUST_RIGHT: + sName = String(ScResId(STR_ACC_RIGHTAREA_NAME)); + break; + case SVX_ADJUST_CENTER: + sName = String(ScResId(STR_ACC_CENTERAREA_NAME)); + break; + default: + DBG_ERRORFILE("wrong adjustment found"); + } + + return sName; +} + +Rectangle ScAccessiblePageHeaderArea::GetBoundingBoxOnScreen(void) const + throw(::com::sun::star::uno::RuntimeException) +{ + Rectangle aRect; + if (mxParent.is()) + { + uno::Reference<XAccessibleContext> xContext = mxParent->getAccessibleContext(); + uno::Reference<XAccessibleComponent> xComp(xContext, uno::UNO_QUERY); + if (xComp.is()) + { + // has the same size and position on screen like the parent + aRect = Rectangle(VCLPoint(xComp->getLocationOnScreen()), VCLRectangle(xComp->getBounds()).GetSize()); + } + } + return aRect; +} + +Rectangle ScAccessiblePageHeaderArea::GetBoundingBox(void) const + throw (::com::sun::star::uno::RuntimeException) +{ + Rectangle aRect; + if (mxParent.is()) + { + uno::Reference<XAccessibleContext> xContext = mxParent->getAccessibleContext(); + uno::Reference<XAccessibleComponent> xComp(xContext, uno::UNO_QUERY); + if (xComp.is()) + { + // has the same size and position on screen like the parent and so the pos is (0, 0) + Rectangle aNewRect(Point(0, 0), VCLRectangle(xComp->getBounds()).GetSize()); + aRect = aNewRect; + } + } + + return aRect; +} + +void ScAccessiblePageHeaderArea::CreateTextHelper() +{ + if (!mpTextHelper) + { + ::std::auto_ptr < ScAccessibleTextData > pAccessibleHeaderTextData + (new ScAccessibleHeaderTextData(mpViewShell, mpEditObj, mbHeader, meAdjust)); + ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleHeaderTextData)); + + mpTextHelper = new ::accessibility::AccessibleTextHelper(pEditSource ); + mpTextHelper->SetEventSource(this); + } +} diff --git a/sc/source/ui/Accessibility/AccessiblePreviewCell.cxx b/sc/source/ui/Accessibility/AccessiblePreviewCell.cxx new file mode 100644 index 000000000000..c07eb0844b7f --- /dev/null +++ b/sc/source/ui/Accessibility/AccessiblePreviewCell.cxx @@ -0,0 +1,316 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" +#include "scitems.hxx" +#include <editeng/eeitem.hxx> +#include <tools/gen.hxx> +#include "AccessibleText.hxx" +#include "editsrc.hxx" +#include "AccessiblePreviewCell.hxx" +#include "AccessibilityHints.hxx" +#include "prevwsh.hxx" +#include "unoguard.hxx" +#include "prevloc.hxx" +#include "document.hxx" +#include <svx/AccessibleTextHelper.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <editeng/brshitem.hxx> +#include <vcl/window.hxx> +#include <toolkit/helper/convert.hxx> + +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +ScAccessiblePreviewCell::ScAccessiblePreviewCell( const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, + ScPreviewShell* pViewShell, /* const */ ScAddress& rCellAddress, + sal_Int32 nIndex ) : + ScAccessibleCellBase( rxParent, ( pViewShell ? pViewShell->GetDocument() : NULL ), rCellAddress, nIndex ), + mpViewShell( pViewShell ), + mpTextHelper(NULL) +{ + if (mpViewShell) + mpViewShell->AddAccessibilityObject(*this); +} + +ScAccessiblePreviewCell::~ScAccessiblePreviewCell() +{ + if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) + { + // increment refcount to prevent double call off dtor + osl_incrementInterlockedCount( &m_refCount ); + // call dispose to inform object wich have a weak reference to this object + dispose(); + } +} + +void SAL_CALL ScAccessiblePreviewCell::disposing() +{ + ScUnoGuard aGuard; + if (mpViewShell) + { + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + + if (mpTextHelper) + DELETEZ(mpTextHelper); + + ScAccessibleCellBase::disposing(); +} + +void ScAccessiblePreviewCell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.ISA( SfxSimpleHint )) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED) + { + if (mpTextHelper) + mpTextHelper->UpdateChildren(); + } + } + + ScAccessibleContextBase::Notify(rBC, rHint); +} + +//===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewCell::getAccessibleAtPoint( const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xRet; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + + if(!mpTextHelper) + CreateTextHelper(); + + xRet = mpTextHelper->GetAt(rPoint); + } + + return xRet; +} + +void SAL_CALL ScAccessiblePreviewCell::grabFocus() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + xAccessibleComponent->grabFocus(); + } +} + +//===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL ScAccessiblePreviewCell::getAccessibleChildCount() throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChildCount(); +} + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewCell::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChild(nIndex); +} + +uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessiblePreviewCell::getAccessibleStateSet() + throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc(xParentStates)) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::MULTI_LINE); + if (IsOpaque(xParentStates)) + pStateSet->AddState(AccessibleStateType::OPAQUE); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + pStateSet->AddState(AccessibleStateType::TRANSIENT); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + // #111635# MANAGES_DESCENDANTS (for paragraphs) + pStateSet->AddState(AccessibleStateType::MANAGES_DESCENDANTS); + } + return pStateSet; +} + +//===== XServiceInfo ==================================================== + +rtl::OUString SAL_CALL ScAccessiblePreviewCell::getImplementationName() throw(uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessiblePreviewCell")); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScAccessiblePreviewCell::getSupportedServiceNames() + throw(uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.table.AccessibleCellView")); + + return aSequence; +} + +//===== XTypeProvider ======================================================= + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessiblePreviewCell::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +//==== internal ========================================================= + +Rectangle ScAccessiblePreviewCell::GetBoundingBoxOnScreen() const throw (uno::RuntimeException) +{ + Rectangle aCellRect; + if (mpViewShell) + { + mpViewShell->GetLocationData().GetCellPosition( maCellAddress, aCellRect ); + 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 ScAccessiblePreviewCell::GetBoundingBox() const throw (uno::RuntimeException) +{ + Rectangle aCellRect; + if (mpViewShell) + { + mpViewShell->GetLocationData().GetCellPosition( maCellAddress, aCellRect ); + uno::Reference<XAccessible> xAccParent = const_cast<ScAccessiblePreviewCell*>(this)->getAccessibleParent(); + if (xAccParent.is()) + { + uno::Reference<XAccessibleContext> xAccParentContext = xAccParent->getAccessibleContext(); + uno::Reference<XAccessibleComponent> xAccParentComp (xAccParentContext, uno::UNO_QUERY); + if (xAccParentComp.is()) + { + Rectangle aParentRect (VCLRectangle(xAccParentComp->getBounds())); + aCellRect.setX(aCellRect.getX() - aParentRect.getX()); + aCellRect.setY(aCellRect.getY() - aParentRect.getY()); + } + } + } + return aCellRect; +} + +sal_Bool ScAccessiblePreviewCell::IsDefunc( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + return ScAccessibleContextBase::IsDefunc() || (mpDoc == NULL) || (mpViewShell == NULL) || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +sal_Bool ScAccessiblePreviewCell::IsEditable( + const uno::Reference<XAccessibleStateSet>& /* rxParentStates */) +{ + return sal_False; +} + +sal_Bool ScAccessiblePreviewCell::IsOpaque( + const uno::Reference<XAccessibleStateSet>& /* rxParentStates */) +{ + // test whether there is a background color + //! could be moved to ScAccessibleCellBase + + sal_Bool bOpaque(sal_True); + if (mpDoc) + { + const SvxBrushItem* pItem = (const SvxBrushItem*)mpDoc->GetAttr( + maCellAddress.Col(), maCellAddress.Row(), maCellAddress.Tab(), ATTR_BACKGROUND); + if (pItem) + bOpaque = pItem->GetColor() != COL_TRANSPARENT; + } + return bOpaque; +} + +void ScAccessiblePreviewCell::CreateTextHelper() +{ + if (!mpTextHelper) + { + ::std::auto_ptr < ScAccessibleTextData > pAccessiblePreviewCellTextData + (new ScAccessiblePreviewCellTextData(mpViewShell, maCellAddress)); + ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessiblePreviewCellTextData)); + + mpTextHelper = new ::accessibility::AccessibleTextHelper( pEditSource ); + mpTextHelper->SetEventSource( this ); + + // #111635# paragraphs in preview are transient + ::accessibility::AccessibleTextHelper::VectorOfStates aChildStates; + aChildStates.push_back( AccessibleStateType::TRANSIENT ); + mpTextHelper->SetAdditionalChildStates( aChildStates ); + } +} + diff --git a/sc/source/ui/Accessibility/AccessiblePreviewHeaderCell.cxx b/sc/source/ui/Accessibility/AccessiblePreviewHeaderCell.cxx new file mode 100644 index 000000000000..3bb66ae01d4f --- /dev/null +++ b/sc/source/ui/Accessibility/AccessiblePreviewHeaderCell.cxx @@ -0,0 +1,443 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" +#include "scitems.hxx" +#include <editeng/eeitem.hxx> +#include <tools/gen.hxx> +#include "AccessibleText.hxx" +#include "editsrc.hxx" +#include <svx/AccessibleTextHelper.hxx> +#include "AccessiblePreviewHeaderCell.hxx" +#include "AccessibilityHints.hxx" +#include "prevwsh.hxx" +#include "unoguard.hxx" +#include "miscuno.hxx" +#include "prevloc.hxx" +#include "scresid.hxx" +#ifndef SC_SC_HRC +#include "sc.hrc" +#endif + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <vcl/window.hxx> +#include <svl/smplhint.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <comphelper/sequence.hxx> +#include <toolkit/helper/convert.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +ScAccessiblePreviewHeaderCell::ScAccessiblePreviewHeaderCell( const ::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible>& rxParent, + ScPreviewShell* pViewShell, + const ScAddress& rCellPos, sal_Bool bIsColHdr, sal_Bool bIsRowHdr, + sal_Int32 nIndex ) : + ScAccessibleContextBase( rxParent, AccessibleRole::TABLE_CELL ), + mpViewShell( pViewShell ), + mpTextHelper( NULL ), + mnIndex( nIndex ), + maCellPos( rCellPos ), + mbColumnHeader( bIsColHdr ), + mbRowHeader( bIsRowHdr ), + mpTableInfo( NULL ) +{ + if (mpViewShell) + mpViewShell->AddAccessibilityObject(*this); +} + +ScAccessiblePreviewHeaderCell::~ScAccessiblePreviewHeaderCell() +{ + if (mpViewShell) + mpViewShell->RemoveAccessibilityObject(*this); +} + +void SAL_CALL ScAccessiblePreviewHeaderCell::disposing() +{ + ScUnoGuard aGuard; + if (mpViewShell) + { + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + + if (mpTableInfo) + DELETEZ (mpTableInfo); + + ScAccessibleContextBase::disposing(); +} + +//===== SfxListener ===================================================== + +void ScAccessiblePreviewHeaderCell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.ISA( SfxSimpleHint )) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + ULONG nId = rRef.GetId(); + if (nId == SC_HINT_ACC_VISAREACHANGED) + { + if (mpTextHelper) + mpTextHelper->UpdateChildren(); + } + else if ( nId == SFX_HINT_DATACHANGED ) + { + // column / row layout may change with any document change, + // so it must be invalidated + DELETEZ( mpTableInfo ); + } + } + + ScAccessibleContextBase::Notify(rBC, rHint); +} + +//===== XInterface ===================================================== + +uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::queryInterface( uno::Type const & rType ) + throw (uno::RuntimeException) +{ + uno::Any aAny (ScAccessiblePreviewHeaderCellImpl::queryInterface(rType)); + return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType); +} + +void SAL_CALL ScAccessiblePreviewHeaderCell::acquire() + throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessiblePreviewHeaderCell::release() + throw () +{ + ScAccessibleContextBase::release(); +} + +//===== XAccessibleValue ================================================ + +uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::getCurrentValue() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + double fValue(0.0); + if (mbColumnHeader) + fValue = maCellPos.Col(); + else + fValue = maCellPos.Row(); + + uno::Any aAny; + aAny <<= fValue; + return aAny; +} + +sal_Bool SAL_CALL ScAccessiblePreviewHeaderCell::setCurrentValue( const uno::Any& /* aNumber */ ) + throw (uno::RuntimeException) +{ + // it is not possible to set a value + return sal_False; +} + +uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::getMaximumValue() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + double fValue(0.0); + if (mbColumnHeader) + fValue = MAXCOL; + else + fValue = MAXROW; + uno::Any aAny; + aAny <<= fValue; + return aAny; +} + +uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::getMinimumValue() throw (uno::RuntimeException) +{ + double fValue(0.0); + uno::Any aAny; + aAny <<= fValue; + return aAny; +} + +//===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleAtPoint( const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference<XAccessible> xRet; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + + if(!mpTextHelper) + CreateTextHelper(); + + xRet = mpTextHelper->GetAt(rPoint); + } + + return xRet; +} + +void SAL_CALL ScAccessiblePreviewHeaderCell::grabFocus() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + xAccessibleComponent->grabFocus(); + } +} + +//===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleChildCount() throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChildCount(); +} + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (!mpTextHelper) + CreateTextHelper(); + return mpTextHelper->GetChild(nIndex); +} + +sal_Int32 SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleIndexInParent() throw (uno::RuntimeException) +{ + return mnIndex; +} + +uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleStateSet() + throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); + xParentStates = xParentContext->getAccessibleStateSet(); + } + utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); + if (IsDefunc(xParentStates)) + pStateSet->AddState(AccessibleStateType::DEFUNC); + else + { + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::MULTI_LINE); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + pStateSet->AddState(AccessibleStateType::TRANSIENT); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + +//===== XServiceInfo ==================================================== + +rtl::OUString SAL_CALL ScAccessiblePreviewHeaderCell::getImplementationName() throw(uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessiblePreviewHeaderCell")); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScAccessiblePreviewHeaderCell::getSupportedServiceNames() + throw(uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.table.AccessibleCellView")); + + return aSequence; +} + +//===== XTypeProvider ======================================================= + +uno::Sequence< uno::Type > SAL_CALL ScAccessiblePreviewHeaderCell::getTypes() + throw (uno::RuntimeException) +{ + return comphelper::concatSequences(ScAccessiblePreviewHeaderCellImpl::getTypes(), ScAccessibleContextBase::getTypes()); +} + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessiblePreviewHeaderCell::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +//==== internal ========================================================= + +Rectangle ScAccessiblePreviewHeaderCell::GetBoundingBoxOnScreen() const throw (uno::RuntimeException) +{ + Rectangle aCellRect; + + FillTableInfo(); + + if (mpTableInfo) + { + const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[maCellPos.Col()]; + const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[maCellPos.Row()]; + + aCellRect = Rectangle( rColInfo.nPixelStart, rRowInfo.nPixelStart, rColInfo.nPixelEnd, rRowInfo.nPixelEnd ); + } + + 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 ScAccessiblePreviewHeaderCell::GetBoundingBox() const throw (uno::RuntimeException) +{ + FillTableInfo(); + + if (mpTableInfo) + { + const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[maCellPos.Col()]; + const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[maCellPos.Row()]; + + Rectangle aCellRect( rColInfo.nPixelStart, rRowInfo.nPixelStart, rColInfo.nPixelEnd, rRowInfo.nPixelEnd ); + uno::Reference<XAccessible> xAccParent = const_cast<ScAccessiblePreviewHeaderCell*>(this)->getAccessibleParent(); + if (xAccParent.is()) + { + uno::Reference<XAccessibleContext> xAccParentContext = xAccParent->getAccessibleContext(); + uno::Reference<XAccessibleComponent> xAccParentComp (xAccParentContext, uno::UNO_QUERY); + if (xAccParentComp.is()) + { + Rectangle aParentRect (VCLRectangle(xAccParentComp->getBounds())); + aCellRect.setX(aCellRect.getX() - aParentRect.getX()); + aCellRect.setY(aCellRect.getY() - aParentRect.getY()); + } + } + return aCellRect; + } + return Rectangle(); +} + +rtl::OUString SAL_CALL ScAccessiblePreviewHeaderCell::createAccessibleDescription() throw(uno::RuntimeException) +{ + rtl::OUString sDescription = String(ScResId(STR_ACC_HEADERCELL_DESCR)); + return sDescription; +} + +rtl::OUString SAL_CALL ScAccessiblePreviewHeaderCell::createAccessibleName() throw(uno::RuntimeException) +{ + rtl::OUString sName = String(ScResId(STR_ACC_HEADERCELL_NAME)); + + if ( mbColumnHeader ) + { + if ( mbRowHeader ) + { + //! name for corner cell? + +// sName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Column/Row Header")); + } + else + { + // name of column header + sName += ScColToAlpha( maCellPos.Col() ); + } + } + else + { + // name of row header + sName += rtl::OUString::valueOf( (sal_Int32) ( maCellPos.Row() + 1 ) ); + } + + return sName; +} + +sal_Bool ScAccessiblePreviewHeaderCell::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates ) +{ + return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +void ScAccessiblePreviewHeaderCell::CreateTextHelper() +{ + if (!mpTextHelper) + { + ::std::auto_ptr < ScAccessibleTextData > pAccessiblePreviewHeaderCellTextData + (new ScAccessiblePreviewHeaderCellTextData(mpViewShell, String(getAccessibleName()), maCellPos, mbColumnHeader, mbRowHeader)); + ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessiblePreviewHeaderCellTextData)); + + mpTextHelper = new ::accessibility::AccessibleTextHelper(pEditSource ); + mpTextHelper->SetEventSource(this); + } +} + +void ScAccessiblePreviewHeaderCell::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 ); + } +} diff --git a/sc/source/ui/Accessibility/AccessiblePreviewTable.cxx b/sc/source/ui/Accessibility/AccessiblePreviewTable.cxx new file mode 100644 index 000000000000..e3fe26f47b4d --- /dev/null +++ b/sc/source/ui/Accessibility/AccessiblePreviewTable.cxx @@ -0,0 +1,769 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +#include "scitems.hxx" +#include "AccessiblePreviewTable.hxx" +#include "AccessiblePreviewCell.hxx" +#include "AccessiblePreviewHeaderCell.hxx" +#include "AccessibilityHints.hxx" +#include "prevwsh.hxx" +#include "unoguard.hxx" +#include "miscuno.hxx" +#include "prevloc.hxx" +#include "attrib.hxx" +#include "document.hxx" +#include "scresid.hxx" +#ifndef SC_SC_HRC +#include "sc.hrc" +#endif + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> + +#include <vcl/window.hxx> +#include <svl/smplhint.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <comphelper/sequence.hxx> + +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_incrementInterlockedCount( &m_refCount ); + dispose(); + } +} + +void SAL_CALL ScAccessiblePreviewTable::disposing() +{ + ScUnoGuard 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; + 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) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + sal_Int32 nRet = 0; + if ( mpTableInfo ) + nRet = mpTableInfo->GetRows(); + return nRet; +} + +sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnCount() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + sal_Int32 nRet = 0; + if ( mpTableInfo ) + nRet = mpTableInfo->GetCols(); + return nRet; +} + +rtl::OUString SAL_CALL ScAccessiblePreviewTable::getAccessibleRowDescription( sal_Int32 nRow ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + // is not supported or specified so not implemented +/* ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + rtl::OUString sName; + if ( mpTableInfo && nRow >= 0 && nRow < mpTableInfo->GetRows() ) + { + const ScPreviewColRowInfo& rInfo = mpTableInfo->GetRowInfo()[nRow]; + if ( rInfo.bIsHeader ) + { + //! name of column headers row? + + sName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Column Headers")); + } + else + { + // normal row name + sName = rtl::OUString::valueOf( (sal_Int32) ( rInfo.nDocIndex + 1 ) ); + } + } + else + throw lang::IndexOutOfBoundsException();*/ + + ScUnoGuard aGuard; + FillTableInfo(); + if ( nRow < 0 || (mpTableInfo && nRow >= mpTableInfo->GetRows()) ) + throw lang::IndexOutOfBoundsException(); + + return rtl::OUString(); +} + +rtl::OUString SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnDescription( sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + // is not supported or specified so not implemented +/* ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + rtl::OUString sName; + if ( mpTableInfo && nColumn >= 0 && nColumn < mpTableInfo->GetCols() ) + { + const ScPreviewColRowInfo& rInfo = mpTableInfo->GetColInfo()[nColumn]; + if ( rInfo.bIsHeader ) + { + //! name of row headers column? + + sName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Row Headers")); + } + else + { + // normal column name + sName = ScColToAlpha( rInfo.nDocIndex ); + } + } + else + throw lang::IndexOutOfBoundsException();*/ + + ScUnoGuard aGuard; + FillTableInfo(); + if ( nColumn < 0 || (mpTableInfo && nColumn >= mpTableInfo->GetCols()) ) + throw lang::IndexOutOfBoundsException(); + + return rtl::OUString(); +} + +sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard 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<SCCOL>(rColInfo.nDocIndex), static_cast<SCROW>(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) +{ + ScUnoGuard 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<SCCOL>(rColInfo.nDocIndex), static_cast<SCROW>(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<sal_Int32>(0); +} + +uno::Sequence< sal_Int32 > SAL_CALL ScAccessiblePreviewTable::getSelectedAccessibleColumns() throw (uno::RuntimeException) +{ + // in the page preview, there is no selection + return uno::Sequence<sal_Int32>(0); +} + +sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleRowSelected( sal_Int32 nRow ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + // in the page preview, there is no selection + + ScUnoGuard aGuard; + FillTableInfo(); + if ( nRow < 0 || (mpTableInfo && nRow >= mpTableInfo->GetRows()) ) + throw lang::IndexOutOfBoundsException(); + + return sal_False; +} + +sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleColumnSelected( sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + // in the page preview, there is no selection + + ScUnoGuard aGuard; + FillTableInfo(); + if ( nColumn < 0 || (mpTableInfo && nColumn >= mpTableInfo->GetCols()) ) + throw lang::IndexOutOfBoundsException(); + + return sal_False; +} + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + uno::Reference<XAccessible> 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<SCCOL>(rColInfo.nDocIndex), static_cast<SCROW>(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 + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + if ( mpTableInfo && nColumn >= 0 && nRow >= 0 && nColumn < mpTableInfo->GetCols() && nRow < mpTableInfo->GetRows() ) + { + // index iterates horizontally + } + else + throw lang::IndexOutOfBoundsException(); + + return sal_False; +} + +sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard 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) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + sal_Int32 nRow = 0; + if ( mpTableInfo && nChildIndex >= 0 && nChildIndex < static_cast<sal_Int32>(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) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + sal_Int32 nCol = 0; + if ( mpTableInfo && nChildIndex >= 0 && nChildIndex < static_cast<sal_Int32>(mpTableInfo->GetRows()) * mpTableInfo->GetCols() ) + { + nCol = nChildIndex % static_cast<sal_Int32>(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<XAccessible> xRet; + if (containsPoint(aPoint)) + { + ScUnoGuard 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) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + xAccessibleComponent->grabFocus(); + } +} + +//===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleChildCount() throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + long nRet = 0; + if ( mpTableInfo ) + nRet = static_cast<sal_Int32>(mpTableInfo->GetCols()) * mpTableInfo->GetRows(); + return nRet; +} + +uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleChild( sal_Int32 nIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + FillTableInfo(); + + uno::Reference<XAccessible> 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) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> 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 ==================================================== + +rtl::OUString SAL_CALL ScAccessiblePreviewTable::getImplementationName() throw(uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessiblePreviewTable")); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScAccessiblePreviewTable::getSupportedServiceNames() + throw(uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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()); +} + +uno::Sequence<sal_Int8> SAL_CALL ScAccessiblePreviewTable::getImplementationId() + throw(uno::RuntimeException) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +//==== internal ========================================================= + +::rtl::OUString SAL_CALL ScAccessiblePreviewTable::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + String sDesc(ScResId(STR_ACC_TABLE_DESCR)); +/* if (mpViewShell && mpViewShell->GetDocument()) + { + FillTableInfo(); + + if ( mpTableInfo ) + { + String sCoreName; + if (mpViewShell->GetDocument()->GetName( mpTableInfo->GetTab(), sCoreName )) + sDesc.SearchAndReplaceAscii("%1", sCoreName); + } + } + sDesc.SearchAndReplaceAscii("%2", String(ScResId(SCSTR_UNKNOWN)));*/ + return rtl::OUString(sDesc); +} + +::rtl::OUString SAL_CALL ScAccessiblePreviewTable::createAccessibleName(void) + throw (uno::RuntimeException) +{ + String sName(ScResId(STR_ACC_TABLE_NAME)); + + if (mpViewShell && mpViewShell->GetDocument()) + { + FillTableInfo(); + + if ( mpTableInfo ) + { + String sCoreName; + if (mpViewShell->GetDocument()->GetName( mpTableInfo->GetTab(), sCoreName )) + sName.SearchAndReplaceAscii("%1", sCoreName); + } + } + + return rtl::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<XAccessibleStateSet>& 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 ); + } +} + diff --git a/sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx b/sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx new file mode 100644 index 000000000000..f85fb22531aa --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx @@ -0,0 +1,999 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include "AccessibleSpreadsheet.hxx" +#include "AccessibilityHints.hxx" +#include "AccessibleCell.hxx" +#include "AccessibleDocument.hxx" +#include "tabvwsh.hxx" +#include "document.hxx" +#include "unoguard.hxx" +#include "hints.hxx" +#include "scmod.hxx" + +#ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX +#include <unotools/accessiblestatesethelper.hxx> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#endif +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp> +#include <rtl/uuid.h> +#include <tools/debug.hxx> +#include <tools/gen.hxx> +#include <svtools/colorcfg.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +ScAccessibleSpreadsheet::ScAccessibleSpreadsheet( + ScAccessibleDocument* pAccDoc, + ScTabViewShell* pViewShell, + SCTAB nTab, + ScSplitPos eSplitPos) + : + ScAccessibleTableBase (pAccDoc, GetDocument(pViewShell), + ScRange(ScAddress(0, 0, nTab),ScAddress(MAXCOL, MAXROW, nTab))), + mbIsSpreadsheet( sal_True ) +{ + ConstructScAccessibleSpreadsheet( pAccDoc, pViewShell, nTab, eSplitPos ); +} + +ScAccessibleSpreadsheet::ScAccessibleSpreadsheet( + ScAccessibleSpreadsheet& rParent, const ScRange& rRange ) : + ScAccessibleTableBase( rParent.mpAccDoc, rParent.mpDoc, rRange), + mbIsSpreadsheet( sal_False ) +{ + ConstructScAccessibleSpreadsheet( rParent.mpAccDoc, rParent.mpViewShell, rParent.mnTab, rParent.meSplitPos ); +} + +ScAccessibleSpreadsheet::~ScAccessibleSpreadsheet() +{ + if (mpMarkedRanges) + delete mpMarkedRanges; + if (mpSortedMarkedCells) + delete mpSortedMarkedCells; + if (mpViewShell) + mpViewShell->RemoveAccessibilityObject(*this); +} + +void ScAccessibleSpreadsheet::ConstructScAccessibleSpreadsheet( + ScAccessibleDocument* pAccDoc, + ScTabViewShell* pViewShell, + SCTAB nTab, + ScSplitPos eSplitPos) +{ + mpViewShell = pViewShell; + mpMarkedRanges = 0; + mpSortedMarkedCells = 0; + mpAccDoc = pAccDoc; + mpAccCell = 0; + meSplitPos = eSplitPos; + mnTab = nTab; + mbHasSelection = sal_False; + mbDelIns = sal_False; + mbIsFocusSend = sal_False; + maVisCells = GetVisCells(GetVisArea(mpViewShell, meSplitPos)); + if (mpViewShell) + { + mpViewShell->AddAccessibilityObject(*this); + + const ScViewData& rViewData = *mpViewShell->GetViewData(); + const ScMarkData& rMarkData = rViewData.GetMarkData(); + maActiveCell = rViewData.GetCurPos(); + mbHasSelection = rMarkData.GetTableSelect(maActiveCell.Tab()) && + (rMarkData.IsMarked() || rMarkData.IsMultiMarked()); + mpAccCell = GetAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col()); + mpAccCell->acquire(); + mpAccCell->Init(); + } +} + +void SAL_CALL ScAccessibleSpreadsheet::disposing() +{ + ScUnoGuard aGuard; + if (mpViewShell) + { + mpViewShell->RemoveAccessibilityObject(*this); + mpViewShell = NULL; + } + if (mpAccCell) + { + mpAccCell->release(); + mpAccCell = NULL; + } + + ScAccessibleTableBase::disposing(); +} + +void ScAccessibleSpreadsheet::CompleteSelectionChanged(sal_Bool bNewState) +{ + if (mpMarkedRanges) + DELETEZ(mpMarkedRanges); + if (mpSortedMarkedCells) + DELETEZ(mpSortedMarkedCells); + + mbHasSelection = bNewState; + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::STATE_CHANGED; + if (bNewState) + aEvent.NewValue = uno::makeAny(AccessibleStateType::SELECTED); + else + aEvent.OldValue = uno::makeAny(AccessibleStateType::SELECTED); + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + CommitChange(aEvent); +} + +void ScAccessibleSpreadsheet::LostFocus() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + uno::Reference< XAccessible > xOld = mpAccCell; + aEvent.OldValue <<= xOld; + + CommitChange(aEvent); + + CommitFocusLost(); +} + +void ScAccessibleSpreadsheet::GotFocus() +{ + CommitFocusGained(); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + uno::Reference< XAccessible > xNew = mpAccCell; + aEvent.NewValue <<= xNew; + + CommitChange(aEvent); +} + +void ScAccessibleSpreadsheet::BoundingBoxChanged() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + CommitChange(aEvent); +} + +void ScAccessibleSpreadsheet::VisAreaChanged() +{ + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + CommitChange(aEvent); +} + + //===== SfxListener ===================================================== + +void ScAccessibleSpreadsheet::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (rHint.ISA( SfxSimpleHint ) ) + { + const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; + // only notify if child exist, otherwise it is not necessary + if ((rRef.GetId() == SC_HINT_ACC_CURSORCHANGED)) + { + if (mpViewShell) + { + ScAddress aNewCell = mpViewShell->GetViewData()->GetCurPos(); + sal_Bool bNewMarked(mpViewShell->GetViewData()->GetMarkData().GetTableSelect(aNewCell.Tab()) && + (mpViewShell->GetViewData()->GetMarkData().IsMarked() || + mpViewShell->GetViewData()->GetMarkData().IsMultiMarked())); + sal_Bool bNewCellSelected(isAccessibleSelected(aNewCell.Row(), aNewCell.Col())); + if ((bNewMarked != mbHasSelection) || + (!bNewCellSelected && bNewMarked) || + (bNewCellSelected && mbHasSelection)) + { + if (mpMarkedRanges) + DELETEZ(mpMarkedRanges); + if (mpSortedMarkedCells) + DELETEZ(mpSortedMarkedCells); + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + mbHasSelection = bNewMarked; + + CommitChange(aEvent); + } + + // active descendant changed event (new cell selected) + bool bFireActiveDescChanged = (aNewCell != maActiveCell) && + (aNewCell.Tab() == maActiveCell.Tab()) && IsFocused(); + + /* Remember old active cell and set new active cell. + #i82409# always update the class members mpAccCell and + maActiveCell, even if the sheet is not focused, e.g. when + using the name box in the toolbar. */ + uno::Reference< XAccessible > xOld = mpAccCell; + mpAccCell->release(); + mpAccCell = GetAccessibleCellAt(aNewCell.Row(), aNewCell.Col()); + mpAccCell->acquire(); + mpAccCell->Init(); + uno::Reference< XAccessible > xNew = mpAccCell; + maActiveCell = aNewCell; + + // #i14108# fire event only if sheet is focused + if( bFireActiveDescChanged ) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.OldValue <<= xOld; + aEvent.NewValue <<= xNew; + CommitChange(aEvent); + } + } + } + else if ((rRef.GetId() == SC_HINT_DATACHANGED)) + { + if (!mbDelIns) + CommitTableModelChange(maRange.aStart.Row(), maRange.aStart.Col(), maRange.aEnd.Row(), maRange.aEnd.Col(), AccessibleTableModelChangeType::UPDATE); + else + mbDelIns = sal_False; + } + // no longer needed, because the document calls the VisAreaChanged method +/* else if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + CommitChange(aEvent);*/ + // commented out, because to use a ModelChangeEvent is not the right way + // at the moment there is no way, but the Java/Gnome Api should be extended sometime +/* if (mpViewShell) + { + Rectangle aNewVisCells(GetVisCells(GetVisArea(mpViewShell, meSplitPos))); + + Rectangle aNewPos(aNewVisCells); + + if (aNewVisCells.IsOver(maVisCells)) + aNewPos.Union(maVisCells); + else + CommitTableModelChange(maVisCells.Top(), maVisCells.Left(), maVisCells.Bottom(), maVisCells.Right(), AccessibleTableModelChangeType::UPDATE); + + maVisCells = aNewVisCells; + + CommitTableModelChange(aNewPos.Top(), aNewPos.Left(), aNewPos.Bottom(), aNewPos.Right(), AccessibleTableModelChangeType::UPDATE); + } + }*/ + // no longer needed, because the document calls the BoundingBoxChanged method +/* else if (rRef.GetId() == SC_HINT_ACC_WINDOWRESIZED) + { + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + + CommitChange(aEvent); + }*/ + } + else if (rHint.ISA( ScUpdateRefHint )) + { + const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint; + if (rRef.GetMode() == URM_INSDEL && rRef.GetDz() == 0) //#107250# test whether table is inserted or deleted + { + if (((rRef.GetRange().aStart.Col() == maRange.aStart.Col()) && + (rRef.GetRange().aEnd.Col() == maRange.aEnd.Col())) || + ((rRef.GetRange().aStart.Row() == maRange.aStart.Row()) && + (rRef.GetRange().aEnd.Row() == maRange.aEnd.Row()))) + { + // ignore next SC_HINT_DATACHANGED notification + mbDelIns = sal_True; + + sal_Int16 nId(0); + SCsCOL nX(rRef.GetDx()); + SCsROW nY(rRef.GetDy()); + ScRange aRange(rRef.GetRange()); + if ((nX < 0) || (nY < 0)) + { + DBG_ASSERT(!((nX < 0) && (nY < 0)), "should not be possible to remove row and column at the same time"); + nId = AccessibleTableModelChangeType::DELETE; + if (nX < 0) + { + nX = -nX; + nY = aRange.aEnd.Row() - aRange.aStart.Row(); + } + else + { + nY = -nY; + nX = aRange.aEnd.Col() - aRange.aStart.Col(); + } + } + else if ((nX > 0) || (nY > 0)) + { + DBG_ASSERT(!((nX > 0) && (nY > 0)), "should not be possible to add row and column at the same time"); + nId = AccessibleTableModelChangeType::INSERT; + if (nX < 0) + nY = aRange.aEnd.Row() - aRange.aStart.Row(); + else + nX = aRange.aEnd.Col() - aRange.aStart.Col(); + } + else + { + DBG_ERROR("is it a deletion or a insertion?"); + } + + CommitTableModelChange(rRef.GetRange().aStart.Row(), + rRef.GetRange().aStart.Col(), + rRef.GetRange().aStart.Row() + nY, + rRef.GetRange().aStart.Col() + nX, nId); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + uno::Reference< XAccessible > xNew = mpAccCell; + aEvent.NewValue <<= xNew; + + CommitChange(aEvent); + } + } + } + + ScAccessibleTableBase::Notify(rBC, rHint); +} + + //===== XAccessibleTable ================================================ + +uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleRowHeaders( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Reference< XAccessibleTable > xAccessibleTable; + if( mpDoc && mbIsSpreadsheet ) + { + if( const ScRange* pRowRange = mpDoc->GetRepeatRowRange( mnTab ) ) + { + SCROW nStart = pRowRange->aStart.Row(); + SCROW nEnd = pRowRange->aEnd.Row(); + if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= MAXROW) ) + xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( 0, nStart, mnTab, MAXCOL, nEnd, mnTab ) ) ); + } + } + return xAccessibleTable; +} + +uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleColumnHeaders( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Reference< XAccessibleTable > xAccessibleTable; + if( mpDoc && mbIsSpreadsheet ) + { + if( const ScRange* pColRange = mpDoc->GetRepeatColRange( mnTab ) ) + { + SCCOL nStart = pColRange->aStart.Col(); + SCCOL nEnd = pColRange->aEnd.Col(); + if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= MAXCOL) ) + xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( nStart, 0, mnTab, nEnd, MAXROW, mnTab ) ) ); + } + } + return xAccessibleTable; +} + +uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleRows( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Sequence<sal_Int32> aSequence; + if (mpViewShell && mpViewShell->GetViewData()) + { + aSequence.realloc(maRange.aEnd.Row() - maRange.aStart.Row() + 1); + const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData(); + sal_Int32* pSequence = aSequence.getArray(); + sal_Int32 nCount(0); + for (SCROW i = maRange.aStart.Row(); i <= maRange.aEnd.Row(); ++i) + { + if (rMarkdata.IsRowMarked(i)) + { + pSequence[nCount] = i; + ++nCount; + } + } + aSequence.realloc(nCount); + } + else + aSequence.realloc(0); + return aSequence; +} + +uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleColumns( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Sequence<sal_Int32> aSequence; + if (mpViewShell && mpViewShell->GetViewData()) + { + aSequence.realloc(maRange.aEnd.Col() - maRange.aStart.Col() + 1); + const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData(); + sal_Int32* pSequence = aSequence.getArray(); + sal_Int32 nCount(0); + for (SCCOL i = maRange.aStart.Col(); i <= maRange.aEnd.Col(); ++i) + { + if (rMarkdata.IsColumnMarked(i)) + { + pSequence[nCount] = i; + ++nCount; + } + } + aSequence.realloc(nCount); + } + else + aSequence.realloc(0); + return aSequence; +} + +sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleRowSelected( sal_Int32 nRow ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if ((nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0)) + throw lang::IndexOutOfBoundsException(); + + sal_Bool bResult(sal_False); + if (mpViewShell && mpViewShell->GetViewData()) + { + const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData(); + bResult = rMarkdata.IsRowMarked((SCROW)nRow); + } + return bResult; +} + +sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleColumnSelected( sal_Int32 nColumn ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0)) + throw lang::IndexOutOfBoundsException(); + + sal_Bool bResult(sal_False); + if (mpViewShell && mpViewShell->GetViewData()) + { + const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData(); + bResult = rMarkdata.IsColumnMarked((SCCOL)nColumn); + } + return bResult; +} + +ScAccessibleCell* ScAccessibleSpreadsheet::GetAccessibleCellAt(sal_Int32 nRow, sal_Int32 nColumn) +{ + ScAccessibleCell* pAccessibleCell = NULL; + ScAddress aCellAddress(static_cast<SCCOL>(maRange.aStart.Col() + nColumn), + static_cast<SCROW>(maRange.aStart.Row() + nRow), maRange.aStart.Tab()); + if ((aCellAddress == maActiveCell) && mpAccCell) + { + pAccessibleCell = mpAccCell; + } + else + pAccessibleCell = new ScAccessibleCell(this, mpViewShell, aCellAddress, getAccessibleIndex(nRow, nColumn), meSplitPos, mpAccDoc); + + return pAccessibleCell; +} + +uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (nRow > (maRange.aEnd.Row() - maRange.aStart.Row()) || + nRow < 0 || + nColumn > (maRange.aEnd.Col() - maRange.aStart.Col()) || + nColumn < 0) + throw lang::IndexOutOfBoundsException(); + + uno::Reference<XAccessible> xAccessible; + ScAccessibleCell* pAccessibleCell = GetAccessibleCellAt(nRow, nColumn); + xAccessible = pAccessibleCell; + pAccessibleCell->Init(); + return xAccessible; +} + +sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) || + (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0)) + throw lang::IndexOutOfBoundsException(); + + sal_Bool bResult(sal_False); + if (mpViewShell) + { + const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData(); + bResult = rMarkdata.IsCellMarked(static_cast<SCCOL>(nColumn), static_cast<SCROW>(nRow)); + } + return bResult; +} + + //===== XAccessibleComponent ============================================ + +uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleAtPoint( + const awt::Point& rPoint ) + throw (uno::RuntimeException) +{ + uno::Reference< XAccessible > xAccessible; + if (containsPoint(rPoint)) + { + ScUnoGuard aGuard; + IsObjectValid(); + if (mpViewShell) + { + SCsCOL nX; + SCsROW nY; + mpViewShell->GetViewData()->GetPosFromPixel( rPoint.X, rPoint.Y, meSplitPos, nX, nY); + xAccessible = getAccessibleCellAt(nY, nX); + } + } + return xAccessible; +} + +void SAL_CALL ScAccessibleSpreadsheet::grabFocus( ) + throw (uno::RuntimeException) +{ + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); + if (xAccessibleComponent.is()) + xAccessibleComponent->grabFocus(); + } +} + +sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getForeground( ) + throw (uno::RuntimeException) +{ + return COL_BLACK; +} + +sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getBackground( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor; +} + + //===== XAccessibleContext ============================================== + +uno::Reference<XAccessibleRelationSet> SAL_CALL ScAccessibleSpreadsheet::getAccessibleRelationSet(void) + throw (::com::sun::star::uno::RuntimeException) +{ + utl::AccessibleRelationSetHelper* pRelationSet = NULL; + if(mpAccDoc) + pRelationSet = mpAccDoc->GetRelationSet(NULL); + if (!pRelationSet) + pRelationSet = new utl::AccessibleRelationSetHelper(); + return pRelationSet; +} + +uno::Reference<XAccessibleStateSet> SAL_CALL + ScAccessibleSpreadsheet::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + uno::Reference<XAccessibleStateSet> xParentStates; + if (getAccessibleParent().is()) + { + uno::Reference<XAccessibleContext> 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); + if (IsEditable(xParentStates)) + pStateSet->AddState(AccessibleStateType::EDITABLE); + pStateSet->AddState(AccessibleStateType::ENABLED); + pStateSet->AddState(AccessibleStateType::FOCUSABLE); + if (IsFocused()) + pStateSet->AddState(AccessibleStateType::FOCUSED); + pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE); + pStateSet->AddState(AccessibleStateType::OPAQUE); + pStateSet->AddState(AccessibleStateType::SELECTABLE); + if (IsCompleteSheetSelected()) + pStateSet->AddState(AccessibleStateType::SELECTED); + if (isShowing()) + pStateSet->AddState(AccessibleStateType::SHOWING); + if (isVisible()) + pStateSet->AddState(AccessibleStateType::VISIBLE); + } + return pStateSet; +} + + ///===== XAccessibleSelection =========================================== + +void SAL_CALL + ScAccessibleSpreadsheet::selectAccessibleChild( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount()) + throw lang::IndexOutOfBoundsException(); + + if (mpViewShell) + { + sal_Int32 nCol(getAccessibleColumn(nChildIndex)); + sal_Int32 nRow(getAccessibleRow(nChildIndex)); + + SelectCell(nRow, nCol, sal_False); + } +} + +void SAL_CALL + ScAccessibleSpreadsheet::clearAccessibleSelection( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpViewShell) + { + mpViewShell->Unmark(); + } +} + +void SAL_CALL + ScAccessibleSpreadsheet::selectAllAccessibleChildren( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + if (mpViewShell) + { + mpViewShell->SelectAll(); + } +} + +sal_Int32 SAL_CALL + ScAccessibleSpreadsheet::getSelectedAccessibleChildCount( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + sal_Int32 nResult(0); + if (mpViewShell) + { + if (!mpMarkedRanges) + { + mpMarkedRanges = new ScRangeList(); + ScMarkData aMarkData(mpViewShell->GetViewData()->GetMarkData()); + aMarkData.MarkToMulti(); + aMarkData.FillRangeListWithMarks(mpMarkedRanges, sal_False); + } + // is possible, because there shouldn't be overlapped ranges in it + if (mpMarkedRanges) + nResult = mpMarkedRanges->GetCellCount(); + } + return nResult; +} + +uno::Reference<XAccessible > SAL_CALL + ScAccessibleSpreadsheet::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + uno::Reference < XAccessible > xAccessible; + if (mpViewShell) + { + if (!mpMarkedRanges) + { + mpMarkedRanges = new ScRangeList(); + mpViewShell->GetViewData()->GetMarkData().FillRangeListWithMarks(mpMarkedRanges, sal_False); + } + if (mpMarkedRanges) + { + if (!mpSortedMarkedCells) + CreateSortedMarkedCells(); + if (mpSortedMarkedCells) + { + if ((nSelectedChildIndex < 0) || + (mpSortedMarkedCells->size() <= static_cast<sal_uInt32>(nSelectedChildIndex))) + throw lang::IndexOutOfBoundsException(); + else + xAccessible = getAccessibleCellAt((*mpSortedMarkedCells)[nSelectedChildIndex].Row(), (*mpSortedMarkedCells)[nSelectedChildIndex].Col()); + } + } + } + return xAccessible; +} + +void SAL_CALL + ScAccessibleSpreadsheet::deselectAccessibleChild( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount()) + throw lang::IndexOutOfBoundsException(); + + if (mpViewShell) + { + sal_Int32 nCol(getAccessibleColumn(nChildIndex)); + sal_Int32 nRow(getAccessibleRow(nChildIndex)); + + if (mpViewShell->GetViewData()->GetMarkData().IsCellMarked(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow))) + SelectCell(nRow, nCol, sal_True); + } +} + +void ScAccessibleSpreadsheet::SelectCell(sal_Int32 nRow, sal_Int32 nCol, sal_Bool bDeselect) +{ + mpViewShell->SetTabNo( maRange.aStart.Tab() ); + + mpViewShell->DoneBlockMode( sal_True ); // continue selecting + mpViewShell->InitBlockMode( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), maRange.aStart.Tab(), bDeselect, sal_False, sal_False ); + + mpViewShell->SelectionChanged(); +} + +void ScAccessibleSpreadsheet::CreateSortedMarkedCells() +{ + mpSortedMarkedCells = new std::vector<ScMyAddress>(); + mpSortedMarkedCells->reserve(mpMarkedRanges->GetCellCount()); + ScRange* pRange = mpMarkedRanges->First(); + while (pRange) + { + if (pRange->aStart.Tab() != pRange->aEnd.Tab()) + { + if ((maActiveCell.Tab() >= pRange->aStart.Tab()) || + maActiveCell.Tab() <= pRange->aEnd.Tab()) + { + ScRange aRange(*pRange); + aRange.aStart.SetTab(maActiveCell.Tab()); + aRange.aEnd.SetTab(maActiveCell.Tab()); + AddMarkedRange(aRange); + } + else + { + DBG_ERROR("Range of wrong table"); + } + } + else if(pRange->aStart.Tab() == maActiveCell.Tab()) + AddMarkedRange(*pRange); + else + { + DBG_ERROR("Range of wrong table"); + } + pRange = mpMarkedRanges->Next(); + } + std::sort(mpSortedMarkedCells->begin(), mpSortedMarkedCells->end()); +} + +void ScAccessibleSpreadsheet::AddMarkedRange(const ScRange& rRange) +{ + for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow) + { + for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol) + { + ScMyAddress aCell(nCol, nRow, maActiveCell.Tab()); + mpSortedMarkedCells->push_back(aCell); + } + } +} + + //===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleSpreadsheet::getImplementationName(void) + throw (uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleSpreadsheet")); +} + +uno::Sequence< ::rtl::OUString> SAL_CALL + ScAccessibleSpreadsheet::getSupportedServiceNames (void) + throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleTableBase::getSupportedServiceNames(); + sal_Int32 nOldSize(aSequence.getLength()); + aSequence.realloc(nOldSize + 1); + ::rtl::OUString* pNames = aSequence.getArray(); + + pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.AccessibleSpreadsheet")); + + return aSequence; +} + +//===== XTypeProvider ======================================================= + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessibleSpreadsheet::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +///===== XAccessibleEventBroadcaster ===================================== + +void SAL_CALL ScAccessibleSpreadsheet::addEventListener(const uno::Reference<XAccessibleEventListener>& xListener) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + ScAccessibleTableBase::addEventListener(xListener); + + if (!mbIsFocusSend) + { + mbIsFocusSend = sal_True; + CommitFocusGained(); + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.NewValue <<= getAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col()); + + CommitChange(aEvent); + } +} + + //==== internal ========================================================= + +Rectangle ScAccessibleSpreadsheet::GetBoundingBoxOnScreen() const + throw (uno::RuntimeException) +{ + Rectangle aRect; + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + aRect = pWindow->GetWindowExtentsRelative(NULL); + } + return aRect; +} + +Rectangle ScAccessibleSpreadsheet::GetBoundingBox() const + throw (uno::RuntimeException) +{ + Rectangle aRect; + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + //#101986#; extends to the same window, because the parent is the document and it has the same window + aRect = pWindow->GetWindowExtentsRelative(pWindow); + } + return aRect; +} + +sal_Bool ScAccessibleSpreadsheet::IsDefunc( + const uno::Reference<XAccessibleStateSet>& rxParentStates) +{ + return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() || + (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); +} + +sal_Bool ScAccessibleSpreadsheet::IsEditable( + const uno::Reference<XAccessibleStateSet>& /* rxParentStates */) +{ + sal_Bool bProtected(sal_False); + if (mpDoc && mpDoc->IsTabProtected(maRange.aStart.Tab())) + bProtected = sal_True; + return !bProtected; +} + +sal_Bool ScAccessibleSpreadsheet::IsFocused() +{ + sal_Bool bFocused(sal_False); + if (mpViewShell) + { + if (mpViewShell->GetViewData()->GetActivePart() == meSplitPos) + bFocused = mpViewShell->GetActiveWin()->HasFocus(); + } + return bFocused; +} + +sal_Bool ScAccessibleSpreadsheet::IsCompleteSheetSelected() +{ + sal_Bool bResult(sal_False); + if(mpViewShell) + { + //#103800#; use a copy of MarkData + ScMarkData aMarkData(mpViewShell->GetViewData()->GetMarkData()); + aMarkData.MarkToMulti(); + if (aMarkData.IsAllMarked(maRange)) + bResult = sal_True; + } + return bResult; +} + +ScDocument* ScAccessibleSpreadsheet::GetDocument(ScTabViewShell* pViewShell) +{ + ScDocument* pDoc = NULL; + if (pViewShell) + pDoc = pViewShell->GetViewData()->GetDocument(); + return pDoc; +} + +Rectangle ScAccessibleSpreadsheet::GetVisArea(ScTabViewShell* pViewShell, ScSplitPos eSplitPos) +{ + Rectangle aVisArea; + if (pViewShell) + { + Window* pWindow = pViewShell->GetWindowByPos(eSplitPos); + if (pWindow) + { + aVisArea.SetPos(pViewShell->GetViewData()->GetPixPos(eSplitPos)); + aVisArea.SetSize(pWindow->GetSizePixel()); + } + } + return aVisArea; +} + +Rectangle ScAccessibleSpreadsheet::GetVisCells(const Rectangle& rVisArea) +{ + if (mpViewShell) + { + SCsCOL nStartX, nEndX; + SCsROW nStartY, nEndY; + + mpViewShell->GetViewData()->GetPosFromPixel( 1, 1, meSplitPos, nStartX, nStartY); + mpViewShell->GetViewData()->GetPosFromPixel( rVisArea.GetWidth(), rVisArea.GetHeight(), meSplitPos, nEndX, nEndY); + + return Rectangle(nStartX, nStartY, nEndX, nEndY); + } + else + return Rectangle(); +} diff --git a/sc/source/ui/Accessibility/AccessibleTableBase.cxx b/sc/source/ui/Accessibility/AccessibleTableBase.cxx new file mode 100644 index 000000000000..2d46d3eb776b --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleTableBase.cxx @@ -0,0 +1,495 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include "AccessibleTableBase.hxx" +#include "miscuno.hxx" +#include "document.hxx" +#include "unoguard.hxx" +#include "scresid.hxx" +#ifndef SC_SC_HRC +#include "sc.hrc" +#endif + +#ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#endif +#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <rtl/uuid.h> +#include <tools/debug.hxx> +#include <comphelper/sequence.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +//===== internal ============================================================ + +ScAccessibleTableBase::ScAccessibleTableBase( + const uno::Reference<XAccessible>& rxParent, + ScDocument* pDoc, + const ScRange& rRange) + : + ScAccessibleContextBase (rxParent, AccessibleRole::TABLE), + maRange(rRange), + mpDoc(pDoc) +{ +} + +ScAccessibleTableBase::~ScAccessibleTableBase() +{ +} + +void SAL_CALL ScAccessibleTableBase::disposing() +{ + ScUnoGuard aGuard; + mpDoc = NULL; + + ScAccessibleContextBase::disposing(); +} + + //===== XInterface ===================================================== + +uno::Any SAL_CALL ScAccessibleTableBase::queryInterface( uno::Type const & rType ) + throw (uno::RuntimeException) +{ + uno::Any aAny (ScAccessibleTableBaseImpl::queryInterface(rType)); + return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType); +} + +void SAL_CALL ScAccessibleTableBase::acquire() + throw () +{ + ScAccessibleContextBase::acquire(); +} + +void SAL_CALL ScAccessibleTableBase::release() + throw () +{ + ScAccessibleContextBase::release(); +} + + //===== XAccessibleTable ================================================ + +sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleRowCount( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return maRange.aEnd.Row() - maRange.aStart.Row() + 1; +} + +sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleColumnCount( ) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return maRange.aEnd.Col() - maRange.aStart.Col() + 1; +} + +::rtl::OUString SAL_CALL ScAccessibleTableBase::getAccessibleRowDescription( sal_Int32 nRow ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + DBG_ERROR("Here should be a implementation to fill the description"); + + if ((nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0)) + throw lang::IndexOutOfBoundsException(); + + //setAccessibleRowDescription(nRow, xAccessible); // to remember the created Description + return rtl::OUString(); +} + +::rtl::OUString SAL_CALL ScAccessibleTableBase::getAccessibleColumnDescription( sal_Int32 nColumn ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + DBG_ERROR("Here should be a implementation to fill the description"); + + if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0)) + throw lang::IndexOutOfBoundsException(); + + //setAccessibleColumnDescription(nColumn, xAccessible); // to remember the created Description + return rtl::OUString(); +} + +sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) || + (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0)) + throw lang::IndexOutOfBoundsException(); + + sal_Int32 nCount(1); // the same cell + nRow += maRange.aStart.Row(); + nColumn += maRange.aStart.Col(); + + if (mpDoc) + { + SCROW nEndRow(0); + SCCOL nEndCol(0); + if (mpDoc->ExtendMerge(static_cast<SCCOL>(nColumn), static_cast<SCROW>(nRow), + nEndCol, nEndRow, maRange.aStart.Tab())) + { + if (nEndRow > nRow) + nCount = nEndRow - nRow + 1; + } + } + + return nCount; +} + +sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) || + (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0)) + throw lang::IndexOutOfBoundsException(); + + sal_Int32 nCount(1); // the same cell + nRow += maRange.aStart.Row(); + nColumn += maRange.aStart.Col(); + + if (mpDoc) + { + SCROW nEndRow(0); + SCCOL nEndCol(0); + if (mpDoc->ExtendMerge(static_cast<SCCOL>(nColumn), static_cast<SCROW>(nRow), + nEndCol, nEndRow, maRange.aStart.Tab())) + { + if (nEndCol > nColumn) + nCount = nEndCol - nColumn + 1; + } + } + + return nCount; +} + +uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleTableBase::getAccessibleRowHeaders( ) + throw (uno::RuntimeException) +{ + uno::Reference< XAccessibleTable > xAccessibleTable; + DBG_ERROR("Here should be a implementation to fill the row headers"); + + //CommitChange + return xAccessibleTable; +} + +uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleTableBase::getAccessibleColumnHeaders( ) + throw (uno::RuntimeException) +{ + uno::Reference< XAccessibleTable > xAccessibleTable; + DBG_ERROR("Here should be a implementation to fill the column headers"); + + //CommitChange + return xAccessibleTable; +} + +uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleTableBase::getSelectedAccessibleRows( ) + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented yet"); + uno::Sequence< sal_Int32 > aSequence; + return aSequence; +} + +uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleTableBase::getSelectedAccessibleColumns( ) + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented yet"); + uno::Sequence< sal_Int32 > aSequence; + return aSequence; +} + +sal_Bool SAL_CALL ScAccessibleTableBase::isAccessibleRowSelected( sal_Int32 /* nRow */ ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + DBG_ERROR("not implemented yet"); + return sal_False; +} + +sal_Bool SAL_CALL ScAccessibleTableBase::isAccessibleColumnSelected( sal_Int32 /* nColumn */ ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + DBG_ERROR("not implemented yet"); + return sal_False; +} + +uno::Reference< XAccessible > SAL_CALL ScAccessibleTableBase::getAccessibleCellAt( sal_Int32 /* nRow */, sal_Int32 /* nColumn */ ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + DBG_ERROR("not implemented yet"); + uno::Reference< XAccessible > xAccessible; + return xAccessible; +} + +uno::Reference< XAccessible > SAL_CALL ScAccessibleTableBase::getAccessibleCaption( ) + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented yet"); + uno::Reference< XAccessible > xAccessible; + return xAccessible; +} + +uno::Reference< XAccessible > SAL_CALL ScAccessibleTableBase::getAccessibleSummary( ) + throw (uno::RuntimeException) +{ + DBG_ERROR("not implemented yet"); + uno::Reference< XAccessible > xAccessible; + return xAccessible; +} + +sal_Bool SAL_CALL ScAccessibleTableBase::isAccessibleSelected( sal_Int32 /* nRow */, sal_Int32 /* nColumn */ ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + DBG_ERROR("not implemented yet"); + return sal_False; +} + + //===== XAccessibleExtendedTable ======================================== + +sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (nRow > (maRange.aEnd.Row() - maRange.aStart.Row()) || + nRow < 0 || + nColumn > (maRange.aEnd.Col() - maRange.aStart.Col()) || + nColumn < 0) + throw lang::IndexOutOfBoundsException(); + + nRow -= maRange.aStart.Row(); + nColumn -= maRange.aStart.Col(); + return (nRow * (maRange.aEnd.Col() + 1)) + nColumn; +} + +sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleRow( sal_Int32 nChildIndex ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (nChildIndex >= getAccessibleChildCount() || nChildIndex < 0) + throw lang::IndexOutOfBoundsException(); + + return nChildIndex / (maRange.aEnd.Col() - maRange.aStart.Col() + 1); +} + +sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleColumn( sal_Int32 nChildIndex ) + throw (uno::RuntimeException, lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (nChildIndex >= getAccessibleChildCount() || nChildIndex < 0) + throw lang::IndexOutOfBoundsException(); + + return nChildIndex % static_cast<sal_Int32>(maRange.aEnd.Col() - maRange.aStart.Col() + 1); +} + + //===== XAccessibleContext ============================================== + +sal_Int32 SAL_CALL + ScAccessibleTableBase::getAccessibleChildCount(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + return static_cast<sal_Int32>(maRange.aEnd.Row() - maRange.aStart.Row() + 1) * + (maRange.aEnd.Col() - maRange.aStart.Col() + 1); +// return 1; +} + +uno::Reference< XAccessible > SAL_CALL + ScAccessibleTableBase::getAccessibleChild(sal_Int32 nIndex) + throw (uno::RuntimeException, + lang::IndexOutOfBoundsException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + + if (nIndex >= getAccessibleChildCount() || nIndex < 0) + throw lang::IndexOutOfBoundsException(); + + sal_Int32 nRow(0); + sal_Int32 nColumn(0); + sal_Int32 nTemp(maRange.aEnd.Col() - maRange.aStart.Col() + 1); + nRow = nIndex / nTemp; + nColumn = nIndex % nTemp; + return getAccessibleCellAt(nRow, nColumn); +} + +::rtl::OUString SAL_CALL + ScAccessibleTableBase::createAccessibleDescription(void) + throw (uno::RuntimeException) +{ + String sDesc(ScResId(STR_ACC_TABLE_DESCR)); +/* String sCoreName; + if (mpDoc && mpDoc->GetName( maRange.aStart.Tab(), sCoreName )) + sDesc.SearchAndReplaceAscii("%1", sCoreName); + sDesc.SearchAndReplaceAscii("%2", String(ScResId(SCSTR_UNKNOWN)));*/ + return rtl::OUString(sDesc); +} + +::rtl::OUString SAL_CALL + ScAccessibleTableBase::createAccessibleName(void) + throw (uno::RuntimeException) +{ + String sName(ScResId(STR_ACC_TABLE_NAME)); + String sCoreName; + if (mpDoc && mpDoc->GetName( maRange.aStart.Tab(), sCoreName )) + sName.SearchAndReplaceAscii("%1", sCoreName); + return rtl::OUString(sName); +} + +uno::Reference<XAccessibleRelationSet> SAL_CALL + ScAccessibleTableBase::getAccessibleRelationSet(void) + throw (uno::RuntimeException) +{ + DBG_ERROR("should be implemented in the abrevated class"); + return uno::Reference<XAccessibleRelationSet>(); +} + +uno::Reference<XAccessibleStateSet> SAL_CALL + ScAccessibleTableBase::getAccessibleStateSet(void) + throw (uno::RuntimeException) +{ + DBG_ERROR("should be implemented in the abrevated class"); + uno::Reference< XAccessibleStateSet > xAccessibleStateSet; + return xAccessibleStateSet; +} + + ///===== XAccessibleSelection =========================================== + +void SAL_CALL + ScAccessibleTableBase::selectAccessibleChild( sal_Int32 /* nChildIndex */ ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ +} + +sal_Bool SAL_CALL + ScAccessibleTableBase::isAccessibleChildSelected( sal_Int32 nChildIndex ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + // I don't need to guard, because the called funtions have a guard +// ScUnoGuard aGuard; + if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount()) + throw lang::IndexOutOfBoundsException(); + return isAccessibleSelected(getAccessibleRow(nChildIndex), getAccessibleColumn(nChildIndex)); +} + +void SAL_CALL + ScAccessibleTableBase::clearAccessibleSelection( ) + throw (uno::RuntimeException) +{ +} + +void SAL_CALL + ScAccessibleTableBase::selectAllAccessibleChildren( ) + throw (uno::RuntimeException) +{ +} + +sal_Int32 SAL_CALL + ScAccessibleTableBase::getSelectedAccessibleChildCount( ) + throw (uno::RuntimeException) +{ + sal_Int32 nResult(0); + return nResult; +} + +uno::Reference<XAccessible > SAL_CALL + ScAccessibleTableBase::getSelectedAccessibleChild( sal_Int32 /* nSelectedChildIndex */ ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ + uno::Reference < XAccessible > xAccessible; + return xAccessible; +} + +void SAL_CALL + ScAccessibleTableBase::deselectAccessibleChild( sal_Int32 /* nSelectedChildIndex */ ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) +{ +} + + //===== XServiceInfo ==================================================== + +::rtl::OUString SAL_CALL ScAccessibleTableBase::getImplementationName(void) + throw (uno::RuntimeException) +{ + return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleTableBase")); +} + + //===== XTypeProvider =================================================== + +uno::Sequence< uno::Type > SAL_CALL ScAccessibleTableBase::getTypes() + throw (uno::RuntimeException) +{ + return comphelper::concatSequences(ScAccessibleTableBaseImpl::getTypes(), ScAccessibleContextBase::getTypes()); +} + +uno::Sequence<sal_Int8> SAL_CALL + ScAccessibleTableBase::getImplementationId(void) + throw (uno::RuntimeException) +{ + ScUnoGuard aGuard; + IsObjectValid(); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + aId.realloc (16); + rtl_createUuid (reinterpret_cast<sal_uInt8 *>(aId.getArray()), 0, sal_True); + } + return aId; +} + +void ScAccessibleTableBase::CommitTableModelChange(sal_Int32 nStartRow, sal_Int32 nStartCol, sal_Int32 nEndRow, sal_Int32 nEndCol, sal_uInt16 nId) +{ + AccessibleTableModelChange aModelChange; + aModelChange.FirstRow = nStartRow; + aModelChange.FirstColumn = nStartCol; + aModelChange.LastRow = nEndRow; + aModelChange.LastColumn = nEndCol; + aModelChange.Type = nId; + + AccessibleEventObject aEvent; + aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED; + aEvent.Source = uno::Reference< XAccessibleContext >(this); + aEvent.NewValue <<= aModelChange; + + CommitChange(aEvent); +} diff --git a/sc/source/ui/Accessibility/AccessibleText.cxx b/sc/source/ui/Accessibility/AccessibleText.cxx new file mode 100644 index 000000000000..4073e23f837f --- /dev/null +++ b/sc/source/ui/Accessibility/AccessibleText.cxx @@ -0,0 +1,1911 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + + +#include <memory> +#include "AccessibleText.hxx" +#include "AccessibleCell.hxx" +#include "tabvwsh.hxx" +#include "editutil.hxx" +#include "document.hxx" +#include "scmod.hxx" +#include "prevwsh.hxx" +#include "docsh.hxx" +#include "prevloc.hxx" +#include "unoguard.hxx" +#include "patattr.hxx" +#include "inputwin.hxx" +#include <editeng/unofored.hxx> +#include <editeng/editview.hxx> +#include <editeng/unoedhlp.hxx> +#include <vcl/virdev.hxx> +#include <editeng/editobj.hxx> +#include <editeng/adjitem.hxx> +#include <svx/svdmodel.hxx> +#include <svx/algitem.hxx> + + +// ============================================================================ + +class ScViewForwarder : public SvxViewForwarder +{ + ScTabViewShell* mpViewShell; + ScAddress maCellPos; + ScSplitPos meSplitPos; +public: + ScViewForwarder(ScTabViewShell* pViewShell, ScSplitPos eSplitPos, const ScAddress& rCell); + virtual ~ScViewForwarder(); + + virtual BOOL IsValid() const; + virtual Rectangle GetVisArea() const; + virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const; + virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const; + + void SetInvalid(); +}; + +ScViewForwarder::ScViewForwarder(ScTabViewShell* pViewShell, ScSplitPos eSplitPos, const ScAddress& rCell) + : + mpViewShell(pViewShell), + maCellPos(rCell), + meSplitPos(eSplitPos) +{ +} + +ScViewForwarder::~ScViewForwarder() +{ +} + +BOOL ScViewForwarder::IsValid() const +{ + return mpViewShell != NULL; +} + +Rectangle ScViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + { + aVisArea.SetSize(pWindow->GetSizePixel()); + + ScHSplitPos eWhichH = ((meSplitPos == SC_SPLIT_TOPLEFT) || (meSplitPos == SC_SPLIT_BOTTOMLEFT)) ? + SC_SPLIT_LEFT : SC_SPLIT_RIGHT; + ScVSplitPos eWhichV = ((meSplitPos == SC_SPLIT_TOPLEFT) || (meSplitPos == SC_SPLIT_TOPRIGHT)) ? + SC_SPLIT_TOP : SC_SPLIT_BOTTOM; + + Point aBaseCellPos(mpViewShell->GetViewData()->GetScrPos(mpViewShell->GetViewData()->GetPosX(eWhichH), + mpViewShell->GetViewData()->GetPosY(eWhichV), meSplitPos, sal_True)); + Point aCellPos(mpViewShell->GetViewData()->GetScrPos(maCellPos.Col(), maCellPos.Row(), meSplitPos, sal_True)); + aVisArea.SetPos(aCellPos - aBaseCellPos); + } + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return aVisArea; +} + +Point ScViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + return pWindow->LogicToPixel( rPoint, rMapMode ); + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +Point ScViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); + if (pWindow) + return pWindow->PixelToLogic( rPoint, rMapMode ); + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +void ScViewForwarder::SetInvalid() +{ + mpViewShell = NULL; +} + +// ============================================================================ + +class ScEditObjectViewForwarder : public SvxViewForwarder +{ + Window* mpWindow; + // --> OD 2005-12-21 #i49561# + // - EditView needed for access to its visible area. + const EditView* mpEditView; + // <-- +public: + // --> OD 2005-12-21 #i49561# + ScEditObjectViewForwarder( Window* pWindow, + const EditView* _pEditView); + // <-- + virtual ~ScEditObjectViewForwarder(); + + virtual BOOL IsValid() const; + virtual Rectangle GetVisArea() const; + virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const; + virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const; + + void SetInvalid(); +}; + +// --> OD 2005-12-21 #i49561# +ScEditObjectViewForwarder::ScEditObjectViewForwarder( Window* pWindow, + const EditView* _pEditView ) + : + mpWindow(pWindow), + mpEditView( _pEditView ) +{ +} +// <-- + +ScEditObjectViewForwarder::~ScEditObjectViewForwarder() +{ +} + +BOOL ScEditObjectViewForwarder::IsValid() const +{ + return (mpWindow != NULL); +} + +Rectangle ScEditObjectViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + if (mpWindow) + { + Rectangle aVisRect(mpWindow->GetWindowExtentsRelative(mpWindow->GetAccessibleParentWindow())); + + aVisRect.SetPos(Point(0, 0)); + + aVisArea = aVisRect; + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return aVisArea; +} + +Point ScEditObjectViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpWindow) + { + // --> OD 2005-12-21 #i49561# - consider offset of the visible area + // of the EditView before converting point to pixel. + Point aPoint( rPoint ); + if ( mpEditView ) + { + Rectangle aEditViewVisArea( mpEditView->GetVisArea() ); + aPoint += aEditViewVisArea.TopLeft(); + } + return mpWindow->LogicToPixel( aPoint, rMapMode ); + // <-- + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +Point ScEditObjectViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpWindow) + { + // --> OD 2005-12-21 #i49561# - consider offset of the visible area + // of the EditView after converting point to logic. + Point aPoint( mpWindow->PixelToLogic( rPoint, rMapMode ) ); + if ( mpEditView ) + { + Rectangle aEditViewVisArea( mpEditView->GetVisArea() ); + aPoint -= aEditViewVisArea.TopLeft(); + } + return aPoint; + // <-- + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +void ScEditObjectViewForwarder::SetInvalid() +{ + mpWindow = NULL; +} + +// ============================================================================ + +class ScPreviewViewForwarder : public SvxViewForwarder +{ +protected: + ScPreviewShell* mpViewShell; + mutable ScPreviewTableInfo* mpTableInfo; +public: + ScPreviewViewForwarder(ScPreviewShell* pViewShell); + virtual ~ScPreviewViewForwarder(); + + virtual BOOL IsValid() const; + virtual Rectangle GetVisArea() const; + virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const; + virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const; + + void SetInvalid(); + + Rectangle GetVisRect() const; + + // clips the VisArea and calculates with the negativ coordinates + Rectangle CorrectVisArea(const Rectangle& rVisArea) const; +}; + +ScPreviewViewForwarder::ScPreviewViewForwarder(ScPreviewShell* pViewShell) + : + mpViewShell(pViewShell), + mpTableInfo(NULL) +{ +} + +ScPreviewViewForwarder::~ScPreviewViewForwarder() +{ + delete mpTableInfo; +} + +BOOL ScPreviewViewForwarder::IsValid() const +{ + return mpViewShell != NULL; +} + +Rectangle ScPreviewViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + DBG_ERROR("should be implemented in an abrevated class"); + return aVisArea; +} + +Point ScPreviewViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindow(); + if (pWindow) + { + MapMode aMapMode(pWindow->GetMapMode().GetMapUnit()); + Point aPoint2( OutputDevice::LogicToLogic( rPoint, rMapMode, aMapMode) ); + return pWindow->LogicToPixel(aPoint2); + } + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +Point ScPreviewViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpViewShell) + { + Window* pWindow = mpViewShell->GetWindow(); + if (pWindow) + { + MapMode aMapMode(pWindow->GetMapMode()); + aMapMode.SetOrigin(Point()); + Point aPoint1( pWindow->PixelToLogic( rPoint ) ); + Point aPoint2( OutputDevice::LogicToLogic( aPoint1, + aMapMode.GetMapUnit(), + rMapMode ) ); + return aPoint2; + } + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +void ScPreviewViewForwarder::SetInvalid() +{ + mpViewShell = NULL; +} + +Rectangle ScPreviewViewForwarder::GetVisRect() const +{ + if ( mpViewShell ) + { + Size aOutputSize; + Window* pWindow = mpViewShell->GetWindow(); + if ( pWindow ) + aOutputSize = pWindow->GetOutputSizePixel(); + Point aPoint; + Rectangle aVisRect( aPoint, aOutputSize ); + return aVisRect; + } + return Rectangle(); +} + +Rectangle ScPreviewViewForwarder::CorrectVisArea(const Rectangle& rVisArea) const +{ + Rectangle aVisArea(rVisArea); + Point aPos = aVisArea.TopLeft(); // get first the position to remember negative positions after clipping + + Window* pWin = mpViewShell->GetWindow(); + if (pWin) + aVisArea = pWin->GetWindowExtentsRelative(pWin).GetIntersection(aVisArea); + + sal_Int32 nX(aPos.getX()); + sal_Int32 nY(aPos.getY()); + + if (nX > 0) + nX = 0; + else if (nX < 0) + nX = -nX; + if (nY > 0) + nY = 0; + else if (nY < 0) + nY = -nY; + aVisArea.SetPos(Point(nX, nY)); + + return aVisArea; +} + +// ============================================================================ + +class ScPreviewHeaderFooterViewForwarder : public ScPreviewViewForwarder +{ + sal_Bool mbHeader; +public: + ScPreviewHeaderFooterViewForwarder(ScPreviewShell* pViewShell, sal_Bool bHeader); + virtual ~ScPreviewHeaderFooterViewForwarder(); + + virtual Rectangle GetVisArea() const; +}; + +ScPreviewHeaderFooterViewForwarder::ScPreviewHeaderFooterViewForwarder(ScPreviewShell* pViewShell, sal_Bool bHeader) + : + ScPreviewViewForwarder(pViewShell), + mbHeader(bHeader) +{ +} + +ScPreviewHeaderFooterViewForwarder::~ScPreviewHeaderFooterViewForwarder() +{ +} + +Rectangle ScPreviewHeaderFooterViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + if (mpViewShell) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + if ( mbHeader ) + rData.GetHeaderPosition( aVisArea ); + else + rData.GetFooterPosition( aVisArea ); + + aVisArea = CorrectVisArea(aVisArea); + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return aVisArea; +} + +// ============================================================================ + +class ScPreviewCellViewForwarder : public ScPreviewViewForwarder +{ + ScAddress maCellPos; +public: + ScPreviewCellViewForwarder(ScPreviewShell* pViewShell, + ScAddress aCellPos); + virtual ~ScPreviewCellViewForwarder(); + + virtual Rectangle GetVisArea() const; +}; + +ScPreviewCellViewForwarder::ScPreviewCellViewForwarder(ScPreviewShell* pViewShell, + ScAddress aCellPos) + : + ScPreviewViewForwarder(pViewShell), + maCellPos(aCellPos) +{ +} + +ScPreviewCellViewForwarder::~ScPreviewCellViewForwarder() +{ +} + +Rectangle ScPreviewCellViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + if (mpViewShell) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + aVisArea = rData.GetCellOutputRect(maCellPos); + + aVisArea = CorrectVisArea(aVisArea); + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return aVisArea; +} + +// ============================================================================ + +class ScPreviewHeaderCellViewForwarder : public ScPreviewViewForwarder +{ + ScAddress maCellPos; + sal_Bool mbColHeader; + sal_Bool mbRowHeader; +public: + ScPreviewHeaderCellViewForwarder(ScPreviewShell* pViewShell, + ScAddress aCellPos, + sal_Bool bColHeader, sal_Bool bRowHeader); + virtual ~ScPreviewHeaderCellViewForwarder(); + + virtual Rectangle GetVisArea() const; +}; + +ScPreviewHeaderCellViewForwarder::ScPreviewHeaderCellViewForwarder(ScPreviewShell* pViewShell, + ScAddress aCellPos, + sal_Bool bColHeader, sal_Bool bRowHeader) + : + ScPreviewViewForwarder(pViewShell), + maCellPos(aCellPos), + mbColHeader(bColHeader), + mbRowHeader(bRowHeader) +{ +} + +ScPreviewHeaderCellViewForwarder::~ScPreviewHeaderCellViewForwarder() +{ +} + +Rectangle ScPreviewHeaderCellViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + if (mpViewShell) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + aVisArea = rData.GetHeaderCellOutputRect(GetVisRect(), maCellPos, mbColHeader); + + aVisArea = CorrectVisArea(aVisArea); + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return aVisArea; +} + +// ============================================================================ + +class ScPreviewNoteViewForwarder : public ScPreviewViewForwarder +{ + ScAddress maCellPos; + sal_Bool mbNoteMark; +public: + ScPreviewNoteViewForwarder(ScPreviewShell* pViewShell, + ScAddress aCellPos, + sal_Bool bNoteMark); + virtual ~ScPreviewNoteViewForwarder(); + + virtual Rectangle GetVisArea() const; +}; + +ScPreviewNoteViewForwarder::ScPreviewNoteViewForwarder(ScPreviewShell* pViewShell, + ScAddress aCellPos, + sal_Bool bNoteMark) + : + ScPreviewViewForwarder(pViewShell), + maCellPos(aCellPos), + mbNoteMark(bNoteMark) +{ +} + +ScPreviewNoteViewForwarder::~ScPreviewNoteViewForwarder() +{ +} + +Rectangle ScPreviewNoteViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + if (mpViewShell) + { + const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); + aVisArea = rData.GetNoteInRangeOutputRect(GetVisRect(), mbNoteMark, maCellPos); + + aVisArea = CorrectVisArea(aVisArea); + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return aVisArea; +} + +// ============================================================================ + +class ScEditViewForwarder : public SvxEditViewForwarder +{ + EditView* mpEditView; + Window* mpWindow; +public: + ScEditViewForwarder(EditView* pEditView, Window* pWin); + virtual ~ScEditViewForwarder(); + + virtual BOOL IsValid() const; + virtual Rectangle GetVisArea() const; + virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const; + virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const; + virtual sal_Bool GetSelection( ESelection& rSelection ) const; + virtual sal_Bool SetSelection( const ESelection& rSelection ); + virtual sal_Bool Copy(); + virtual sal_Bool Cut(); + virtual sal_Bool Paste(); + + void GrabFocus(); + + void SetInvalid(); +}; + +ScEditViewForwarder::ScEditViewForwarder(EditView* pEditView, Window* pWin) + : mpEditView(pEditView), + mpWindow(pWin) +{ + GrabFocus(); +} + +ScEditViewForwarder::~ScEditViewForwarder() +{ +} + +BOOL ScEditViewForwarder::IsValid() const +{ + sal_Bool bResult(sal_False); + if (mpWindow && mpEditView) + { + bResult = sal_True; + } + return bResult; +} + +Rectangle ScEditViewForwarder::GetVisArea() const +{ + Rectangle aVisArea; + if (IsValid() && mpEditView->GetEditEngine()) + { + MapMode aMapMode(mpEditView->GetEditEngine()->GetRefMapMode()); + + aVisArea = mpWindow->LogicToPixel( mpEditView->GetVisArea(), aMapMode ); + } + else + { + DBG_ERROR("this EditViewForwarder is no longer valid"); + } + return aVisArea; +} + +Point ScEditViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpWindow) + return mpWindow->LogicToPixel( rPoint, rMapMode ); + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +Point ScEditViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + if (mpWindow) + return mpWindow->PixelToLogic( rPoint, rMapMode ); + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return Point(); +} + +sal_Bool ScEditViewForwarder::GetSelection( ESelection& rSelection ) const +{ + sal_Bool bResult(sal_False); + if (IsValid()) + { + rSelection = mpEditView->GetSelection(); + bResult = sal_True; + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return bResult; +} + +sal_Bool ScEditViewForwarder::SetSelection( const ESelection& rSelection ) +{ + sal_Bool bResult(sal_False); + if (IsValid()) + { + mpEditView->SetSelection(rSelection); + bResult = sal_True; + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return bResult; +} + +sal_Bool ScEditViewForwarder::Copy() +{ + sal_Bool bResult(sal_False); + if (IsValid()) + { + mpEditView->Copy(); + bResult = sal_True; + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return bResult; +} + +sal_Bool ScEditViewForwarder::Cut() +{ + sal_Bool bResult(sal_False); + if (IsValid()) + { + mpEditView->Cut(); + bResult = sal_True; + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return bResult; +} + +sal_Bool ScEditViewForwarder::Paste() +{ + sal_Bool bResult(sal_False); + if (IsValid()) + { + mpEditView->Paste(); + bResult = sal_True; + } + else + { + DBG_ERROR("this ViewForwarder is not valid"); + } + return bResult; +} + +void ScEditViewForwarder::GrabFocus() +{ +} + +void ScEditViewForwarder::SetInvalid() +{ + mpWindow = NULL; + mpEditView = NULL; +} + +// ============================================================================ + +// ScAccessibleCellTextData: shared data between sub objects of a accessible cell text object + +ScAccessibleCellTextData::ScAccessibleCellTextData(ScTabViewShell* pViewShell, + const ScAddress& rP, ScSplitPos eSplitPos, ScAccessibleCell* pAccCell) + : ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP), + mpViewForwarder(NULL), + mpEditViewForwarder(NULL), + mpViewShell(pViewShell), + meSplitPos(eSplitPos), + mbViewEditEngine(sal_False), + mpAccessibleCell( pAccCell ) +{ +} + +ScAccessibleCellTextData::~ScAccessibleCellTextData() +{ + if (pEditEngine) + pEditEngine->SetNotifyHdl(Link()); + if (mpViewForwarder) + delete mpViewForwarder; + if (mpEditViewForwarder) + delete mpEditViewForwarder; +} + +void ScAccessibleCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if ( rHint.ISA( SfxSimpleHint ) ) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if ( nId == SFX_HINT_DYING ) + { + mpViewShell = NULL; // invalid now + if (mpViewForwarder) + mpViewForwarder->SetInvalid(); + if (mpEditViewForwarder) + mpEditViewForwarder->SetInvalid(); + } + } + ScAccessibleCellBaseTextData::Notify(rBC, rHint); +} + +ScAccessibleTextData* ScAccessibleCellTextData::Clone() const +{ + return new ScAccessibleCellTextData( mpViewShell, aCellPos, meSplitPos, mpAccessibleCell ); +} + +void ScAccessibleCellTextData::GetCellText(const ScAddress& rCellPos, String& rText) +{ +// #104893#; don't use the input string +// ScCellTextData::GetCellText(rCellPos, rText); + ScDocument* pDoc = pDocShell->GetDocument(); + if (pDoc) + { + // #104893#; use the displayed string + pDoc->GetString(rCellPos.Col(), rCellPos.Row(), rCellPos.Tab(), rText); + if (mpViewShell) + { + const ScViewOptions& aOptions = mpViewShell->GetViewData()->GetOptions(); + CellType aCellType; + pDoc->GetCellType(rCellPos.Col(), rCellPos.Row(), rCellPos.Tab(), aCellType); + if (aCellType == CELLTYPE_FORMULA && aOptions.GetOption( VOPT_FORMULAS )) + { + pDoc->GetFormula( rCellPos.Col(), rCellPos.Row(), rCellPos.Tab(), rText); + } + else if (!aOptions.GetOption( VOPT_NULLVALS )) + { + if ((aCellType == CELLTYPE_VALUE || aCellType == CELLTYPE_FORMULA) && pDoc->GetValue(rCellPos) == 0.0) + rText.Erase(); + } + } + } +} + +SvxTextForwarder* ScAccessibleCellTextData::GetTextForwarder() +{ +/* sal_Bool bHasForwarder(sal_False); + if (mpViewShell && mpViewShell->GetViewData() && + (mpViewShell->GetViewData()->GetCurPos() == aCellPos) && + (mpViewShell->GetViewData()->HasEditView(meSplitPos)) && + (mpViewShell->GetViewData()->GetEditViewCol() == aCellPos.Col()) && + (mpViewShell->GetViewData()->GetEditViewRow() == aCellPos.Row())) + { + if (!mbViewEditEngine) + { + if (pForwarder) + DELETEZ( pForwarder ); + if (pEditEngine) + DELETEZ( pEditEngine ); + + SCCOL nCol; + SCROW nRow; + EditView* pEditView; + mpViewShell->GetViewData()->GetEditView( meSplitPos, pEditView, nCol, nRow ); + if (pEditView) + { + pEditEngine = (ScFieldEditEngine*)pEditView->GetEditEngine(); + pForwarder = new SvxEditEngineForwarder(*pEditEngine); + bHasForwarder = sal_True; + } + } + else + bHasForwarder = sal_True; + } + else if (mbViewEditEngine) + { + // remove Forwarder created with EditEngine from EditView + if (pForwarder) + DELETEZ( pForwarder ); + pEditEngine->SetNotifyHdl(Link()); + // don't delete, because it is the EditEngine of the EditView + pEditEngine = NULL; + mbViewEditEngine = sal_False; + } + + if (!bHasForwarder)*/ + ScCellTextData::GetTextForwarder(); // creates Forwarder and EditEngine + + ScDocument* pDoc = ( pDocShell ? pDocShell->GetDocument() : NULL ); + if ( pDoc && pEditEngine && mpViewShell ) + { + long nSizeX, nSizeY; + mpViewShell->GetViewData()->GetMergeSizePixel( + aCellPos.Col(), aCellPos.Row(), nSizeX, nSizeY); + + Size aSize(nSizeX, nSizeY); + + // #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells + long nIndent = 0; + const SvxHorJustifyItem* pHorJustifyItem = static_cast< const SvxHorJustifyItem* >( + pDoc->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_HOR_JUSTIFY ) ); + SvxCellHorJustify eHorJust = ( pHorJustifyItem ? static_cast< SvxCellHorJustify >( pHorJustifyItem->GetValue() ) : SVX_HOR_JUSTIFY_STANDARD ); + if ( eHorJust == SVX_HOR_JUSTIFY_LEFT ) + { + const SfxUInt16Item* pIndentItem = static_cast< const SfxUInt16Item* >( + pDoc->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_INDENT ) ); + if ( pIndentItem ) + { + nIndent = static_cast< long >( pIndentItem->GetValue() ); + } + } + + const SvxMarginItem* pMarginItem = static_cast< const SvxMarginItem* >( + pDoc->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_MARGIN ) ); + ScViewData* pViewData = mpViewShell->GetViewData(); + double nPPTX = ( pViewData ? pViewData->GetPPTX() : 0 ); + double nPPTY = ( pViewData ? pViewData->GetPPTY() : 0 ); + long nLeftM = ( pMarginItem ? static_cast< long >( ( pMarginItem->GetLeftMargin() + nIndent ) * nPPTX ) : 0 ); + long nTopM = ( pMarginItem ? static_cast< long >( pMarginItem->GetTopMargin() * nPPTY ) : 0 ); + long nRightM = ( pMarginItem ? static_cast< long >( pMarginItem->GetRightMargin() * nPPTX ) : 0 ); + long nBottomM = ( pMarginItem ? static_cast< long >( pMarginItem->GetBottomMargin() * nPPTY ) : 0 ); + long nWidth = aSize.getWidth() - nLeftM - nRightM; + aSize.setWidth( nWidth ); + aSize.setHeight( aSize.getHeight() - nTopM - nBottomM ); + + Window* pWin = mpViewShell->GetWindowByPos( meSplitPos ); + if ( pWin ) + { + aSize = pWin->PixelToLogic( aSize, pEditEngine->GetRefMapMode() ); + } + + /* #i19430# Gnopernicus reads text partly if it sticks out of the cell + boundaries. This leads to wrong results in cases where the cell text + is rotated, because rotation is not taken into account when calcu- + lating the visible part of the text. In these cases we will expand + the cell size passed as paper size to the edit engine. The function + accessibility::AccessibleStaticTextBase::GetParagraphBoundingBox() + (see svx/source/accessibility/AccessibleStaticTextBase.cxx) will + return the size of the complete text then, which is used to expand + the cell bounding box in ScAccessibleCell::GetBoundingBox() + (see sc/source/ui/Accessibility/AccessibleCell.cxx). */ + const SfxInt32Item* pItem = static_cast< const SfxInt32Item* >( + pDoc->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_ROTATE_VALUE ) ); + if( pItem && (pItem->GetValue() != 0) ) + { + pEditEngine->SetPaperSize( Size( LONG_MAX, aSize.getHeight() ) ); + long nTxtWidth = static_cast< long >( pEditEngine->CalcTextWidth() ); + aSize.setWidth( std::max( aSize.getWidth(), nTxtWidth + 2 ) ); + } + else + { + // #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells + const SfxBoolItem* pLineBreakItem = static_cast< const SfxBoolItem* >( + pDoc->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_LINEBREAK ) ); + bool bLineBreak = ( pLineBreakItem && pLineBreakItem->GetValue() ); + if ( !bLineBreak ) + { + long nTxtWidth = static_cast< long >( pEditEngine->CalcTextWidth() ); + aSize.setWidth( ::std::max( aSize.getWidth(), nTxtWidth ) ); + } + } + + pEditEngine->SetPaperSize( aSize ); + + // #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells + if ( eHorJust == SVX_HOR_JUSTIFY_STANDARD && pDoc->HasValueData( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab() ) ) + { + pEditEngine->SetDefaultItem( SvxAdjustItem( SVX_ADJUST_RIGHT, EE_PARA_JUST ) ); + } + + Size aTextSize; + if ( pWin ) + { + aTextSize = pWin->LogicToPixel( Size( pEditEngine->CalcTextWidth(), pEditEngine->GetTextHeight() ), pEditEngine->GetRefMapMode() ); + } + long nTextWidth = aTextSize.Width(); + long nTextHeight = aTextSize.Height(); + + long nOffsetX = nLeftM; + long nDiffX = nTextWidth - nWidth; + if ( nDiffX > 0 ) + { + switch ( eHorJust ) + { + case SVX_HOR_JUSTIFY_RIGHT: + { + nOffsetX -= nDiffX; + } + break; + case SVX_HOR_JUSTIFY_CENTER: + { + nOffsetX -= nDiffX / 2; + } + break; + default: + { + } + break; + } + } + + long nOffsetY = 0; + const SvxVerJustifyItem* pVerJustifyItem = static_cast< const SvxVerJustifyItem* >( + pDoc->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_VER_JUSTIFY ) ); + SvxCellVerJustify eVerJust = ( pVerJustifyItem ? static_cast< SvxCellVerJustify >( pVerJustifyItem->GetValue() ) : SVX_VER_JUSTIFY_STANDARD ); + switch ( eVerJust ) + { + case SVX_VER_JUSTIFY_STANDARD: + case SVX_VER_JUSTIFY_BOTTOM: + { + nOffsetY = nSizeY - nBottomM - nTextHeight; + } + break; + case SVX_VER_JUSTIFY_CENTER: + { + nOffsetY = ( nSizeY - nTopM - nBottomM - nTextHeight ) / 2 + nTopM; + } + break; + default: + { + nOffsetY = nTopM; + } + break; + } + + if ( mpAccessibleCell ) + { + mpAccessibleCell->SetOffset( Point( nOffsetX, nOffsetY ) ); + } + + pEditEngine->SetNotifyHdl( LINK(this, ScAccessibleCellTextData, NotifyHdl) ); + } + + return pForwarder; +} + +SvxViewForwarder* ScAccessibleCellTextData::GetViewForwarder() +{ + if (!mpViewForwarder) + mpViewForwarder = new ScViewForwarder(mpViewShell, meSplitPos, aCellPos); + return mpViewForwarder; +} + +SvxEditViewForwarder* ScAccessibleCellTextData::GetEditViewForwarder( sal_Bool /* bCreate */ ) +{ + //#102219#; there should no EditViewForwarder be, because the cell is now readonly in this interface +/* if (!mpEditViewForwarder) + { + SCCOL nCol; + SCROW nRow; + EditView* pEditView; + mpViewShell->GetViewData()->GetEditView( meSplitPos, pEditView, nCol, nRow ); + + mpEditViewForwarder = new ScEditViewForwarder(pEditView, mpViewShell->GetWindowByPos(meSplitPos)); + } + else if (bCreate) + mpEditViewForwarder->GrabFocus(); + return mpEditViewForwarder;*/ + return NULL; +} + +IMPL_LINK(ScAccessibleCellTextData, NotifyHdl, EENotify*, aNotify) +{ + if( aNotify ) + { + ::std::auto_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( aNotify ); + + if( aHint.get() ) + GetBroadcaster().Broadcast( *aHint.get() ); + } + + return 0; +} + +ScDocShell* ScAccessibleCellTextData::GetDocShell(ScTabViewShell* pViewShell) +{ + ScDocShell* pDocSh = NULL; + if (pViewShell) + pDocSh = pViewShell->GetViewData()->GetDocShell(); + return pDocSh; +} + + +// ============================================================================ + +ScAccessibleEditObjectTextData::ScAccessibleEditObjectTextData(EditView* pEditView, Window* pWin) + : + mpViewForwarder(NULL), + mpEditViewForwarder(NULL), + mpEditView(pEditView), + mpEditEngine(pEditView ? pEditView->GetEditEngine() : 0), + mpForwarder(NULL), + mpWindow(pWin) +{ + if (mpEditEngine) + mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleEditObjectTextData, NotifyHdl) ); +} + +ScAccessibleEditObjectTextData::~ScAccessibleEditObjectTextData() +{ + if (mpEditEngine) + mpEditEngine->SetNotifyHdl(Link()); + if (mpViewForwarder) + delete mpViewForwarder; + if (mpEditViewForwarder) + delete mpEditViewForwarder; + if (mpForwarder) + delete mpForwarder; +} + +void ScAccessibleEditObjectTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if ( rHint.ISA( SfxSimpleHint ) ) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if ( nId == SFX_HINT_DYING ) + { + mpWindow = NULL; + mpEditView = NULL; + mpEditEngine = NULL; + DELETEZ(mpForwarder); + if (mpViewForwarder) + mpViewForwarder->SetInvalid(); + if (mpEditViewForwarder) + mpEditViewForwarder->SetInvalid(); + } + } + ScAccessibleTextData::Notify(rBC, rHint); +} + +ScAccessibleTextData* ScAccessibleEditObjectTextData::Clone() const +{ + return new ScAccessibleEditObjectTextData(mpEditView, mpWindow); +} + +SvxTextForwarder* ScAccessibleEditObjectTextData::GetTextForwarder() +{ + if ((!mpForwarder && mpEditView) || (mpEditEngine && !mpEditEngine->GetNotifyHdl().IsSet())) + { + if (!mpEditEngine) + mpEditEngine = mpEditView->GetEditEngine(); + if (mpEditEngine && !mpEditEngine->GetNotifyHdl().IsSet()) + mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleEditObjectTextData, NotifyHdl) ); + if(!mpForwarder) + mpForwarder = new SvxEditEngineForwarder(*mpEditEngine); + } + return mpForwarder; +} + +SvxViewForwarder* ScAccessibleEditObjectTextData::GetViewForwarder() +{ + if (!mpViewForwarder) + { + // --> OD 2005-12-21 #i49561# + mpViewForwarder = new ScEditObjectViewForwarder( mpWindow, mpEditView ); + // <-- + } + return mpViewForwarder; +} + +SvxEditViewForwarder* ScAccessibleEditObjectTextData::GetEditViewForwarder( sal_Bool bCreate ) +{ + if (!mpEditViewForwarder && mpEditView) + mpEditViewForwarder = new ScEditViewForwarder(mpEditView, mpWindow); + if (bCreate) + { + if (!mpEditView && mpEditViewForwarder) + { + DELETEZ(mpEditViewForwarder); + } + else if (mpEditViewForwarder) + mpEditViewForwarder->GrabFocus(); + } + return mpEditViewForwarder; +} + +IMPL_LINK(ScAccessibleEditObjectTextData, NotifyHdl, EENotify*, aNotify) +{ + if( aNotify ) + { + ::std::auto_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( aNotify ); + + if( aHint.get() ) + GetBroadcaster().Broadcast( *aHint.get() ); + } + + return 0; +} + + +// ============================================================================ + +ScAccessibleEditLineTextData::ScAccessibleEditLineTextData(EditView* pEditView, Window* pWin) + : + ScAccessibleEditObjectTextData(pEditView, pWin), + mbEditEngineCreated(sal_False) +{ + ScTextWnd* pTxtWnd = (ScTextWnd*)pWin; + + if (pTxtWnd) + pTxtWnd->InsertAccessibleTextData( *this ); +} + +ScAccessibleEditLineTextData::~ScAccessibleEditLineTextData() +{ + ScTextWnd* pTxtWnd = (ScTextWnd*)mpWindow; + + if (pTxtWnd) + pTxtWnd->RemoveAccessibleTextData( *this ); + + if (mbEditEngineCreated && mpEditEngine) + { + delete mpEditEngine; + mpEditEngine = NULL; // #103346# don't access in ScAccessibleEditObjectTextData dtor! + } + else if (pTxtWnd && pTxtWnd->GetEditView() && pTxtWnd->GetEditView()->GetEditEngine()) + { + // #103346# the NotifyHdl also has to be removed from the ScTextWnd's EditEngine + // (it's set in ScAccessibleEditLineTextData::GetTextForwarder, and mpEditEngine + // is reset there) + pTxtWnd->GetEditView()->GetEditEngine()->SetNotifyHdl(Link()); + } +} + +void ScAccessibleEditLineTextData::Dispose() +{ + ScTextWnd* pTxtWnd = (ScTextWnd*)mpWindow; + + if (pTxtWnd) + pTxtWnd->RemoveAccessibleTextData( *this ); + + ResetEditMode(); + mpWindow = NULL; +} + +ScAccessibleTextData* ScAccessibleEditLineTextData::Clone() const +{ + return new ScAccessibleEditLineTextData(mpEditView, mpWindow); +} + +SvxTextForwarder* ScAccessibleEditLineTextData::GetTextForwarder() +{ + ScTextWnd* pTxtWnd = (ScTextWnd*)mpWindow; + + if (pTxtWnd) + { + mpEditView = pTxtWnd->GetEditView(); + if (mpEditView) + { + if (mbEditEngineCreated && mpEditEngine) + ResetEditMode(); + mbEditEngineCreated = sal_False; + + mpEditView = pTxtWnd->GetEditView(); + ScAccessibleEditObjectTextData::GetTextForwarder(); // fill the mpForwarder + mpEditEngine = NULL; + } + else + { + if (mpEditEngine && !mbEditEngineCreated) + ResetEditMode(); + if (!mpEditEngine) + { + SfxItemPool* pEnginePool = EditEngine::CreatePool(); + pEnginePool->FreezeIdRanges(); + mpEditEngine = new ScFieldEditEngine( pEnginePool, NULL, TRUE ); + mbEditEngineCreated = sal_True; + // currently, GetPortions doesn't work if UpdateMode is FALSE, + // this will be fixed (in EditEngine) by src600 + // pEditEngine->SetUpdateMode( FALSE ); + mpEditEngine->EnableUndo( FALSE ); + mpEditEngine->SetRefMapMode( MAP_100TH_MM ); + mpForwarder = new SvxEditEngineForwarder(*mpEditEngine); + + mpEditEngine->SetText(pTxtWnd->GetTextString()); + + Size aSize(pTxtWnd->GetSizePixel()); + + aSize = pTxtWnd->PixelToLogic(aSize, mpEditEngine->GetRefMapMode()); + + mpEditEngine->SetPaperSize(aSize); + + mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleEditObjectTextData, NotifyHdl) ); + } + } + } + return mpForwarder; +} + +SvxEditViewForwarder* ScAccessibleEditLineTextData::GetEditViewForwarder( sal_Bool bCreate ) +{ + ScTextWnd* pTxtWnd = (ScTextWnd*)mpWindow; + + if (pTxtWnd) + { + mpEditView = pTxtWnd->GetEditView(); + if (!mpEditView && bCreate) + { + if ( !pTxtWnd->IsInputActive() ) + { + pTxtWnd->StartEditEngine(); + pTxtWnd->GrabFocus(); +// pTxtWnd->SetTextString( rText ); +// pTxtWnd->GetEditView()->SetSelection( rSel ); + + mpEditView = pTxtWnd->GetEditView(); + } + } + } + + return ScAccessibleEditObjectTextData::GetEditViewForwarder(bCreate); +} + +void ScAccessibleEditLineTextData::ResetEditMode() +{ + ScTextWnd* pTxtWnd = (ScTextWnd*)mpWindow; + + if (mbEditEngineCreated && mpEditEngine) + delete mpEditEngine; + else if (pTxtWnd && pTxtWnd->GetEditView() && pTxtWnd->GetEditView()->GetEditEngine()) + pTxtWnd->GetEditView()->GetEditEngine()->SetNotifyHdl(Link()); + mpEditEngine = NULL; + + DELETEZ(mpForwarder); + DELETEZ(mpEditViewForwarder); + DELETEZ(mpViewForwarder); + mbEditEngineCreated = sal_False; +} + +void ScAccessibleEditLineTextData::TextChanged() +{ + if (mbEditEngineCreated && mpEditEngine) + { + ScTextWnd* pTxtWnd = (ScTextWnd*)mpWindow; + + if (pTxtWnd) + mpEditEngine->SetText(pTxtWnd->GetTextString()); + } +} + +void ScAccessibleEditLineTextData::StartEdit() +{ + ResetEditMode(); + mpEditView = NULL; + + // send HINT_BEGEDIT + SdrHint aHint(HINT_BEGEDIT); + GetBroadcaster().Broadcast( aHint ); +} + +void ScAccessibleEditLineTextData::EndEdit() +{ + // send HINT_ENDEDIT + SdrHint aHint(HINT_ENDEDIT); + GetBroadcaster().Broadcast( aHint ); + + ResetEditMode(); + mpEditView = NULL; +} + + +// ============================================================================ + +// ScAccessiblePreviewCellTextData: shared data between sub objects of a accessible cell text object + +ScAccessiblePreviewCellTextData::ScAccessiblePreviewCellTextData(ScPreviewShell* pViewShell, + const ScAddress& rP) + : ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP), + mpViewForwarder(NULL), + mpViewShell(pViewShell) +{ +} + +ScAccessiblePreviewCellTextData::~ScAccessiblePreviewCellTextData() +{ + if (pEditEngine) + pEditEngine->SetNotifyHdl(Link()); + if (mpViewForwarder) + delete mpViewForwarder; +} + +void ScAccessiblePreviewCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if ( rHint.ISA( SfxSimpleHint ) ) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if ( nId == SFX_HINT_DYING ) + { + mpViewShell = NULL; // invalid now + if (mpViewForwarder) + mpViewForwarder->SetInvalid(); + } + } + ScAccessibleCellBaseTextData::Notify(rBC, rHint); +} + +ScAccessibleTextData* ScAccessiblePreviewCellTextData::Clone() const +{ + return new ScAccessiblePreviewCellTextData(mpViewShell, aCellPos); +} + +SvxTextForwarder* ScAccessiblePreviewCellTextData::GetTextForwarder() +{ + sal_Bool bEditEngineBefore(pEditEngine != NULL); + + ScCellTextData::GetTextForwarder(); // creates Forwarder and EditEngine + + if (!bEditEngineBefore && pEditEngine) + { + Size aSize(mpViewShell->GetLocationData().GetCellOutputRect(aCellPos).GetSize()); + Window* pWin = mpViewShell->GetWindow(); + if (pWin) + aSize = pWin->PixelToLogic(aSize, pEditEngine->GetRefMapMode()); + pEditEngine->SetPaperSize(aSize); + } + + if (pEditEngine) + pEditEngine->SetNotifyHdl( LINK(this, ScAccessibleCellTextData, NotifyHdl) ); + + return pForwarder; +} + +SvxViewForwarder* ScAccessiblePreviewCellTextData::GetViewForwarder() +{ + if (!mpViewForwarder) + mpViewForwarder = new ScPreviewCellViewForwarder(mpViewShell, aCellPos); + return mpViewForwarder; +} + +//UNUSED2008-05 IMPL_LINK(ScAccessiblePreviewCellTextData, NotifyHdl, EENotify*, aNotify) +//UNUSED2008-05 { +//UNUSED2008-05 if( aNotify ) +//UNUSED2008-05 { +//UNUSED2008-05 ::std::auto_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( aNotify); +//UNUSED2008-05 +//UNUSED2008-05 if( aHint.get() ) +//UNUSED2008-05 GetBroadcaster().Broadcast( *aHint.get() ); +//UNUSED2008-05 } +//UNUSED2008-05 +//UNUSED2008-05 return 0; +//UNUSED2008-05 } + +ScDocShell* ScAccessiblePreviewCellTextData::GetDocShell(ScPreviewShell* pViewShell) +{ + ScDocShell* pDocSh = NULL; + if (pViewShell && pViewShell->GetDocument()) + pDocSh = (ScDocShell*) pViewShell->GetDocument()->GetDocumentShell(); + return pDocSh; +} + + +// ============================================================================ + +// ScAccessiblePreviewHeaderCellTextData: shared data between sub objects of a accessible cell text object + +ScAccessiblePreviewHeaderCellTextData::ScAccessiblePreviewHeaderCellTextData(ScPreviewShell* pViewShell, + const String& rText, const ScAddress& rP, sal_Bool bColHeader, sal_Bool bRowHeader) + : ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP), + mpViewForwarder(NULL), + mpViewShell(pViewShell), + maText(rText), + mbColHeader(bColHeader), + mbRowHeader(bRowHeader) +{ +} + +ScAccessiblePreviewHeaderCellTextData::~ScAccessiblePreviewHeaderCellTextData() +{ + if (pEditEngine) + pEditEngine->SetNotifyHdl(Link()); + if (mpViewForwarder) + delete mpViewForwarder; +} + +void ScAccessiblePreviewHeaderCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if ( rHint.ISA( SfxSimpleHint ) ) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if ( nId == SFX_HINT_DYING ) + { + mpViewShell = NULL; // invalid now + if (mpViewForwarder) + mpViewForwarder->SetInvalid(); + } + } + ScAccessibleCellBaseTextData::Notify(rBC, rHint); +} + +ScAccessibleTextData* ScAccessiblePreviewHeaderCellTextData::Clone() const +{ + return new ScAccessiblePreviewHeaderCellTextData(mpViewShell, maText, aCellPos, mbColHeader, mbRowHeader); +} + +SvxTextForwarder* ScAccessiblePreviewHeaderCellTextData::GetTextForwarder() +{ + if (!pEditEngine) + { + if ( pDocShell ) + { + ScDocument* pDoc = pDocShell->GetDocument(); + pEditEngine = pDoc->CreateFieldEditEngine(); + } + else + { + SfxItemPool* pEnginePool = EditEngine::CreatePool(); + pEnginePool->FreezeIdRanges(); + pEditEngine = new ScFieldEditEngine( pEnginePool, NULL, TRUE ); + } + // currently, GetPortions doesn't work if UpdateMode is FALSE, + // this will be fixed (in EditEngine) by src600 +// pEditEngine->SetUpdateMode( FALSE ); + pEditEngine->EnableUndo( FALSE ); + if (pDocShell) + pEditEngine->SetRefDevice(pDocShell->GetRefDevice()); + else + pEditEngine->SetRefMapMode( MAP_100TH_MM ); + pForwarder = new SvxEditEngineForwarder(*pEditEngine); + } + + if (bDataValid) + return pForwarder; + + if (maText.Len() && pEditEngine) + { + + if ( mpViewShell ) + { + Size aOutputSize; + Window* pWindow = mpViewShell->GetWindow(); + if ( pWindow ) + aOutputSize = pWindow->GetOutputSizePixel(); + Point aPoint; + Rectangle aVisRect( aPoint, aOutputSize ); + Size aSize(mpViewShell->GetLocationData().GetHeaderCellOutputRect(aVisRect, aCellPos, mbColHeader).GetSize()); + if (pWindow) + aSize = pWindow->PixelToLogic(aSize, pEditEngine->GetRefMapMode()); + pEditEngine->SetPaperSize(aSize); + } + pEditEngine->SetText( maText ); + } + + bDataValid = TRUE; + + if (pEditEngine) + pEditEngine->SetNotifyHdl( LINK(this, ScAccessibleCellTextData, NotifyHdl) ); + + return pForwarder; +} + +SvxViewForwarder* ScAccessiblePreviewHeaderCellTextData::GetViewForwarder() +{ + if (!mpViewForwarder) + mpViewForwarder = new ScPreviewHeaderCellViewForwarder(mpViewShell, aCellPos, mbColHeader, mbRowHeader); + return mpViewForwarder; +} + +//UNUSED2008-05 IMPL_LINK(ScAccessiblePreviewHeaderCellTextData, NotifyHdl, EENotify*, aNotify) +//UNUSED2008-05 { +//UNUSED2008-05 if( aNotify ) +//UNUSED2008-05 { +//UNUSED2008-05 ::std::auto_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( aNotify); +//UNUSED2008-05 +//UNUSED2008-05 if( aHint.get() ) +//UNUSED2008-05 GetBroadcaster().Broadcast( *aHint.get() ); +//UNUSED2008-05 } +//UNUSED2008-05 +//UNUSED2008-05 return 0; +//UNUSED2008-05 } + +ScDocShell* ScAccessiblePreviewHeaderCellTextData::GetDocShell(ScPreviewShell* pViewShell) +{ + ScDocShell* pDocSh = NULL; + if (pViewShell && pViewShell->GetDocument()) + pDocSh = (ScDocShell*) pViewShell->GetDocument()->GetDocumentShell(); + return pDocSh; +} + + +// ============================================================================ + +ScAccessibleHeaderTextData::ScAccessibleHeaderTextData(ScPreviewShell* pViewShell, + const EditTextObject* pEditObj, sal_Bool bHeader, SvxAdjust eAdjust) + : + mpViewForwarder(NULL), + mpViewShell(pViewShell), + mpEditEngine(NULL), + mpForwarder(NULL), + mpDocSh(NULL), + mpEditObj(pEditObj), + mbHeader(bHeader), + mbDataValid(sal_False), + meAdjust(eAdjust) +{ + if (pViewShell && pViewShell->GetDocument()) + mpDocSh = (ScDocShell*) pViewShell->GetDocument()->GetDocumentShell(); + if (mpDocSh) + mpDocSh->GetDocument()->AddUnoObject(*this); +} + +ScAccessibleHeaderTextData::~ScAccessibleHeaderTextData() +{ + ScUnoGuard aGuard; // needed for EditEngine dtor + + if (mpDocSh) + mpDocSh->GetDocument()->RemoveUnoObject(*this); + if (mpEditEngine) + mpEditEngine->SetNotifyHdl(Link()); + delete mpEditEngine; + delete mpForwarder; +} + +ScAccessibleTextData* ScAccessibleHeaderTextData::Clone() const +{ + return new ScAccessibleHeaderTextData(mpViewShell, mpEditObj, mbHeader, meAdjust); +} + +void ScAccessibleHeaderTextData::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if ( rHint.ISA( SfxSimpleHint ) ) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if ( nId == SFX_HINT_DYING ) + { + mpViewShell = NULL;// invalid now + mpDocSh = NULL; + if (mpViewForwarder) + mpViewForwarder->SetInvalid(); + } + } +} + +SvxTextForwarder* ScAccessibleHeaderTextData::GetTextForwarder() +{ + if (!mpEditEngine) + { + SfxItemPool* pEnginePool = EditEngine::CreatePool(); + pEnginePool->FreezeIdRanges(); + ScHeaderEditEngine* pHdrEngine = new ScHeaderEditEngine( pEnginePool, TRUE ); + + pHdrEngine->EnableUndo( FALSE ); + pHdrEngine->SetRefMapMode( MAP_TWIP ); + + // default font must be set, independently of document + // -> use global pool from module + + SfxItemSet aDefaults( pHdrEngine->GetEmptyItemSet() ); + const ScPatternAttr& rPattern = (const ScPatternAttr&)SC_MOD()->GetPool().GetDefaultItem(ATTR_PATTERN); + rPattern.FillEditItemSet( &aDefaults ); + // FillEditItemSet adjusts font height to 1/100th mm, + // but for header/footer twips is needed, as in the PatternAttr: + aDefaults.Put( rPattern.GetItem(ATTR_FONT_HEIGHT), EE_CHAR_FONTHEIGHT ); + aDefaults.Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT), EE_CHAR_FONTHEIGHT_CJK ); + aDefaults.Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT), EE_CHAR_FONTHEIGHT_CTL ); + aDefaults.Put( SvxAdjustItem( meAdjust, EE_PARA_JUST ) ); + pHdrEngine->SetDefaults( aDefaults ); + + ScHeaderFieldData aData; + if (mpViewShell) + mpViewShell->FillFieldData(aData); + else + ScHeaderFooterTextObj::FillDummyFieldData( aData ); + pHdrEngine->SetData( aData ); + + mpEditEngine = pHdrEngine; + mpForwarder = new SvxEditEngineForwarder(*mpEditEngine); + } + + if (mbDataValid) + return mpForwarder; + + if ( mpViewShell ) + { + Rectangle aVisRect; + mpViewShell->GetLocationData().GetHeaderPosition(aVisRect); + Size aSize(aVisRect.GetSize()); + Window* pWin = mpViewShell->GetWindow(); + if (pWin) + aSize = pWin->PixelToLogic(aSize, mpEditEngine->GetRefMapMode()); + mpEditEngine->SetPaperSize(aSize); + } + if (mpEditObj) + mpEditEngine->SetText(*mpEditObj); + + mbDataValid = sal_True; + return mpForwarder; +} + +SvxViewForwarder* ScAccessibleHeaderTextData::GetViewForwarder() +{ + if (!mpViewForwarder) + mpViewForwarder = new ScPreviewHeaderFooterViewForwarder(mpViewShell, mbHeader); + return mpViewForwarder; +} + + +// ============================================================================ + +ScAccessibleNoteTextData::ScAccessibleNoteTextData(ScPreviewShell* pViewShell, + const String& sText, const ScAddress& aCellPos, sal_Bool bMarkNote) + : + mpViewForwarder(NULL), + mpViewShell(pViewShell), + mpEditEngine(NULL), + mpForwarder(NULL), + mpDocSh(NULL), + msText(sText), + maCellPos(aCellPos), + mbMarkNote(bMarkNote), + mbDataValid(sal_False) +{ + if (pViewShell && pViewShell->GetDocument()) + mpDocSh = (ScDocShell*) pViewShell->GetDocument()->GetDocumentShell(); + if (mpDocSh) + mpDocSh->GetDocument()->AddUnoObject(*this); +} + +ScAccessibleNoteTextData::~ScAccessibleNoteTextData() +{ + ScUnoGuard aGuard; // needed for EditEngine dtor + + if (mpDocSh) + mpDocSh->GetDocument()->RemoveUnoObject(*this); + if (mpEditEngine) + mpEditEngine->SetNotifyHdl(Link()); + delete mpEditEngine; + delete mpForwarder; +} + +ScAccessibleTextData* ScAccessibleNoteTextData::Clone() const +{ + return new ScAccessibleNoteTextData(mpViewShell, msText, maCellPos, mbMarkNote); +} + +void ScAccessibleNoteTextData::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if ( rHint.ISA( SfxSimpleHint ) ) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if ( nId == SFX_HINT_DYING ) + { + mpViewShell = NULL;// invalid now + mpDocSh = NULL; + if (mpViewForwarder) + mpViewForwarder->SetInvalid(); + } + } +} + +SvxTextForwarder* ScAccessibleNoteTextData::GetTextForwarder() +{ + if (!mpEditEngine) + { + if ( mpDocSh ) + { + ScDocument* pDoc = mpDocSh->GetDocument(); + mpEditEngine = pDoc->CreateFieldEditEngine(); + } + else + { + SfxItemPool* pEnginePool = EditEngine::CreatePool(); + pEnginePool->FreezeIdRanges(); + mpEditEngine = new ScFieldEditEngine( pEnginePool, NULL, TRUE ); + } + // currently, GetPortions doesn't work if UpdateMode is FALSE, + // this will be fixed (in EditEngine) by src600 +// pEditEngine->SetUpdateMode( FALSE ); + mpEditEngine->EnableUndo( FALSE ); + if (mpDocSh) + mpEditEngine->SetRefDevice(mpDocSh->GetRefDevice()); + else + mpEditEngine->SetRefMapMode( MAP_100TH_MM ); + mpForwarder = new SvxEditEngineForwarder(*mpEditEngine); + } + + if (mbDataValid) + return mpForwarder; + + if (msText.Len() && mpEditEngine) + { + + if ( mpViewShell ) + { + Size aOutputSize; + Window* pWindow = mpViewShell->GetWindow(); + if ( pWindow ) + aOutputSize = pWindow->GetOutputSizePixel(); + Point aPoint; + Rectangle aVisRect( aPoint, aOutputSize ); + Size aSize(mpViewShell->GetLocationData().GetNoteInRangeOutputRect(aVisRect, mbMarkNote, maCellPos).GetSize()); + if (pWindow) + aSize = pWindow->PixelToLogic(aSize, mpEditEngine->GetRefMapMode()); + mpEditEngine->SetPaperSize(aSize); + } + mpEditEngine->SetText( msText ); + } + + mbDataValid = TRUE; + + if (mpEditEngine) + mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleCellTextData, NotifyHdl) ); + + return mpForwarder; +} + +SvxViewForwarder* ScAccessibleNoteTextData::GetViewForwarder() +{ + if (!mpViewForwarder) + mpViewForwarder = new ScPreviewNoteViewForwarder(mpViewShell, maCellPos, mbMarkNote); + return mpViewForwarder; +} + + +// CSV import ================================================================= + +class ScCsvViewForwarder : public SvxViewForwarder +{ + Rectangle maBoundBox; + Window* mpWindow; + +public: + explicit ScCsvViewForwarder( Window* pWindow, const Rectangle& rBoundBox ); + + virtual BOOL IsValid() const; + virtual Rectangle GetVisArea() const; + virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const; + virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const; + + void SetInvalid(); +}; + +ScCsvViewForwarder::ScCsvViewForwarder( Window* pWindow, const Rectangle& rBoundBox ) : + maBoundBox( rBoundBox ), + mpWindow( pWindow ) +{ +} + +BOOL ScCsvViewForwarder::IsValid() const +{ + return mpWindow != NULL; +} + +Rectangle ScCsvViewForwarder::GetVisArea() const +{ + return maBoundBox; +} + +Point ScCsvViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + if( !mpWindow ) return Point(); + return mpWindow->LogicToPixel( rPoint, rMapMode ); +} + +Point ScCsvViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + if( !mpWindow ) return Point(); + return mpWindow->PixelToLogic( rPoint, rMapMode ); +} + +void ScCsvViewForwarder::SetInvalid() +{ + mpWindow = NULL; +} + +// ---------------------------------------------------------------------------- + +ScAccessibleCsvTextData::ScAccessibleCsvTextData( + Window* pWindow, EditEngine* pEditEngine, + const String& rCellText, const Rectangle& rBoundBox, const Size& rCellSize ) : + mpWindow( pWindow ), + mpEditEngine( pEditEngine ), + maCellText( rCellText ), + maBoundBox( rBoundBox ), + maCellSize( rCellSize ) +{ +} + +ScAccessibleCsvTextData::~ScAccessibleCsvTextData() +{ +} + +void ScAccessibleCsvTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if ( rHint.ISA( SfxSimpleHint ) ) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if( nId == SFX_HINT_DYING ) + { + mpWindow = NULL; + mpEditEngine = NULL; + if (mpViewForwarder.get()) + mpViewForwarder->SetInvalid(); + } + } + ScAccessibleTextData::Notify( rBC, rHint ); +} + +ScAccessibleTextData* ScAccessibleCsvTextData::Clone() const +{ + return new ScAccessibleCsvTextData( mpWindow, mpEditEngine, maCellText, maBoundBox, maCellSize ); +} + +SvxTextForwarder* ScAccessibleCsvTextData::GetTextForwarder() +{ + if( mpEditEngine ) + { + mpEditEngine->SetPaperSize( maCellSize ); + mpEditEngine->SetText( maCellText ); + if( !mpTextForwarder.get() ) + mpTextForwarder.reset( new SvxEditEngineForwarder( *mpEditEngine ) ); + } + else + mpTextForwarder.reset( NULL ); + return mpTextForwarder.get(); +} + +SvxViewForwarder* ScAccessibleCsvTextData::GetViewForwarder() +{ + if( !mpViewForwarder.get() ) + mpViewForwarder.reset( new ScCsvViewForwarder( mpWindow, maBoundBox ) ); + return mpViewForwarder.get(); +} + +SvxEditViewForwarder* ScAccessibleCsvTextData::GetEditViewForwarder( sal_Bool /* bCreate */ ) +{ + return NULL; +} + + +// ============================================================================ + diff --git a/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx b/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx new file mode 100644 index 000000000000..31bf438772d0 --- /dev/null +++ b/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" +#include "DrawModelBroadcaster.hxx" +#include <svx/svdmodel.hxx> +#include <svx/unomod.hxx> +#include <tools/debug.hxx> + +using namespace ::com::sun::star; + +ScDrawModelBroadcaster::ScDrawModelBroadcaster( SdrModel *pDrawModel ) : + maEventListeners( maListenerMutex ), + mpDrawModel( pDrawModel ) +{ + if (mpDrawModel) + StartListening( *mpDrawModel ); +} + +ScDrawModelBroadcaster::~ScDrawModelBroadcaster() +{ + if (mpDrawModel) + EndListening( *mpDrawModel ); +} + +void SAL_CALL ScDrawModelBroadcaster::addEventListener( const uno::Reference< document::XEventListener >& xListener ) + throw (uno::RuntimeException) +{ + maEventListeners.addInterface( xListener ); +} + +void SAL_CALL ScDrawModelBroadcaster::removeEventListener( const uno::Reference< document::XEventListener >& xListener ) + throw (uno::RuntimeException) +{ + maEventListeners.removeInterface( xListener ); +} + +void ScDrawModelBroadcaster::Notify( SfxBroadcaster&, + const SfxHint& rHint ) +{ + const SdrHint *pSdrHint = PTR_CAST( SdrHint, &rHint ); + if( !pSdrHint ) + return; + + document::EventObject aEvent; + if( !SvxUnoDrawMSFactory::createEvent( mpDrawModel, pSdrHint, aEvent ) ) + return; + + ::cppu::OInterfaceIteratorHelper aIter( maEventListeners ); + while( aIter.hasMoreElements() ) + { + uno::Reference < document::XEventListener > xListener( aIter.next(), uno::UNO_QUERY ); + try + { + xListener->notifyEvent( aEvent ); + } + catch( uno::RuntimeException& r ) + { + (void) r; +#if OSL_DEBUG_LEVEL > 1 + ByteString aError( "Runtime exception caught while notifying shape.:\n" ); + aError += ByteString( String( r.Message), RTL_TEXTENCODING_ASCII_US ); + DBG_ERROR( aError.GetBuffer() ); +#endif + } + } +} diff --git a/sc/source/ui/Accessibility/makefile.mk b/sc/source/ui/Accessibility/makefile.mk new file mode 100644 index 000000000000..32df95750f85 --- /dev/null +++ b/sc/source/ui/Accessibility/makefile.mk @@ -0,0 +1,94 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=sc +TARGET=accessibility + +# --- Settings ----------------------------------------------------- + +.INCLUDE : scpre.mk +.INCLUDE : settings.mk +.INCLUDE : sc.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/AccessibleContextBase.obj \ + $(SLO)$/AccessibleTableBase.obj \ + $(SLO)$/AccessibleDocument.obj \ + $(SLO)$/AccessibleGlobal.obj \ + $(SLO)$/AccessibleSpreadsheet.obj \ + $(SLO)$/AccessibleCell.obj \ + $(SLO)$/AccessibilityHints.obj \ + $(SLO)$/AccessibleDocumentBase.obj \ + $(SLO)$/AccessibleCellBase.obj \ + $(SLO)$/AccessibleDocumentPagePreview.obj \ + $(SLO)$/AccessibleFilterMenu.obj \ + $(SLO)$/AccessibleFilterMenuItem.obj \ + $(SLO)$/AccessibleFilterTopWindow.obj \ + $(SLO)$/AccessiblePreviewTable.obj \ + $(SLO)$/AccessiblePreviewCell.obj \ + $(SLO)$/AccessiblePreviewHeaderCell.obj \ + $(SLO)$/AccessiblePageHeader.obj \ + $(SLO)$/AccessibleText.obj \ + $(SLO)$/AccessiblePageHeaderArea.obj \ + $(SLO)$/DrawModelBroadcaster.obj \ + $(SLO)$/AccessibleEditObject.obj \ + $(SLO)$/AccessibleDataPilotControl.obj \ + $(SLO)$/AccessibleCsvControl.obj + +EXCEPTIONSFILES= \ + $(SLO)$/AccessibleContextBase.obj \ + $(SLO)$/AccessibleTableBase.obj \ + $(SLO)$/AccessibleDocument.obj \ + $(SLO)$/AccessibleGlobal.obj \ + $(SLO)$/AccessibleSpreadsheet.obj \ + $(SLO)$/AccessibleCell.obj \ + $(SLO)$/AccessibleDocumentBase.obj \ + $(SLO)$/AccessibleCellBase.obj \ + $(SLO)$/AccessibleDocumentPagePreview.obj \ + $(SLO)$/AccessibleFilterMenu.obj \ + $(SLO)$/AccessibleFilterMenuItem.obj \ + $(SLO)$/AccessibleFilterTopWindow.obj \ + $(SLO)$/AccessiblePreviewTable.obj \ + $(SLO)$/AccessiblePreviewCell.obj \ + $(SLO)$/AccessiblePreviewHeaderCell.obj \ + $(SLO)$/AccessiblePageHeader.obj \ + $(SLO)$/AccessiblePageHeaderArea.obj \ + $(SLO)$/DrawModelBroadcaster.obj \ + $(SLO)$/AccessibleEditObject.obj \ + $(SLO)$/AccessibleDataPilotControl.obj \ + $(SLO)$/AccessibleCsvControl.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + + |