/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::accessibility; static bool CompMinCol(const std::pair & pc1,const std::pair &pc2) { return pc1.first < pc2.first; } ScMyAddress ScAccessibleSpreadsheet::CalcScAddressFromRangeList(ScRangeList *pMarkedRanges,sal_Int32 nSelectedChildIndex) { if (pMarkedRanges->size() <= 1) { ScRange const & rRange = pMarkedRanges->front(); // MT IA2: Not used. // const int nRowNum = rRange.aEnd.Row() - rRange.aStart.Row() + 1; const int nColNum = rRange.aEnd.Col() - rRange.aStart.Col() + 1; const int nCurCol = nSelectedChildIndex % nColNum; const int nCurRow = (nSelectedChildIndex - nCurCol)/nColNum; return ScMyAddress(static_cast(rRange.aStart.Col() + nCurCol), rRange.aStart.Row() + nCurRow, maActiveCell.Tab()); } else { ScDocument* pDoc= GetDocument(mpViewShell); sal_Int32 nMinRow = pDoc->MaxRow(); sal_Int32 nMaxRow = 0; std::vector aRanges; size_t nSize = pMarkedRanges->size(); for (size_t i = 0; i < nSize; ++i) { ScRange const & rRange = (*pMarkedRanges)[i]; if (rRange.aStart.Tab() != rRange.aEnd.Tab()) { if ((maActiveCell.Tab() >= rRange.aStart.Tab()) || maActiveCell.Tab() <= rRange.aEnd.Tab()) { aRanges.push_back(rRange); nMinRow = std::min(rRange.aStart.Row(),nMinRow); nMaxRow = std::max(rRange.aEnd.Row(),nMaxRow); } else SAL_WARN("sc", "Range of wrong table"); } else if(rRange.aStart.Tab() == maActiveCell.Tab()) { aRanges.push_back(rRange); nMinRow = std::min(rRange.aStart.Row(),nMinRow); nMaxRow = std::max(rRange.aEnd.Row(),nMaxRow); } else SAL_WARN("sc", "Range of wrong table"); } int nCurrentIndex = 0 ; for(sal_Int32 row = nMinRow ; row <= nMaxRow ; ++row) { std::vector> aVecCol; for (ScRange const & r : aRanges) { if ( row >= r.aStart.Row() && row <= r.aEnd.Row()) { aVecCol.emplace_back(r.aStart.Col(), r.aEnd.Col()); } } std::sort(aVecCol.begin(), aVecCol.end(), CompMinCol); for (const std::pair &pairCol : aVecCol) { SCCOL nCol = pairCol.second - pairCol.first + 1; if (nCol + nCurrentIndex > nSelectedChildIndex) { return ScMyAddress(static_cast(pairCol.first + nSelectedChildIndex - nCurrentIndex), row, maActiveCell.Tab()); } nCurrentIndex += nCol; } } } return ScMyAddress(0,0,maActiveCell.Tab()); } bool ScAccessibleSpreadsheet::CalcScRangeDifferenceMax(const ScRange & rSrc, const ScRange & rDest, int nMax, std::vector &vecRet, int &nSize) { //Src Must be :Src > Dest if (rDest.Contains(rSrc)) {//Here is Src In Dest,Src <= Dest return false; } if (!rDest.Intersects(rSrc)) { int nCellCount = sal_uInt32(rDest.aEnd.Col() - rDest.aStart.Col() + 1) * sal_uInt32(rDest.aEnd.Row() - rDest.aStart.Row() + 1) * sal_uInt32(rDest.aEnd.Tab() - rDest.aStart.Tab() + 1); if (nCellCount + nSize > nMax) { return true; } else if(nCellCount > 0) { for (sal_Int32 row = rDest.aStart.Row(); row <= rDest.aEnd.Row();++row) { for (sal_uInt16 col = rDest.aStart.Col(); col <= rDest.aEnd.Col();++col) { vecRet.emplace_back(col,row,rDest.aStart.Tab()); } } } return false; } sal_Int32 nMinRow = rSrc.aStart.Row(); sal_Int32 nMaxRow = rSrc.aEnd.Row(); for (; nMinRow <= nMaxRow ; ++nMinRow,--nMaxRow) { for (sal_uInt16 col = rSrc.aStart.Col(); col <= rSrc.aEnd.Col();++col) { if (nSize > nMax) { return true; } ScMyAddress cell(col,nMinRow,rSrc.aStart.Tab()); if(!rDest.Contains(cell)) {//In Src ,Not In Dest vecRet.push_back(cell); ++nSize; } } if (nMinRow != nMaxRow) { for (sal_uInt16 col = rSrc.aStart.Col(); col <= rSrc.aEnd.Col();++col) { if (nSize > nMax) { return true; } ScMyAddress cell(col,nMaxRow,rSrc.aStart.Tab()); if(!rDest.Contains(cell)) {//In Src ,Not In Dest vecRet.push_back(cell); ++nSize; } } } } return false; } //In Src , Not in Dest bool ScAccessibleSpreadsheet::CalcScRangeListDifferenceMax(ScRangeList *pSrc, ScRangeList *pDest, int nMax, std::vector &vecRet) { if (pSrc == nullptr || pDest == nullptr) { return false; } int nSize =0; if (pDest->GetCellCount() == 0)//if the Dest Rang List is empty { if (pSrc->GetCellCount() > o3tl::make_unsigned(nMax))//if the Src Cell count is greater than nMax { return true; } //now the cell count is less than nMax vecRet.reserve(10); size_t nSrcSize = pSrc->size(); for (size_t i = 0; i < nSrcSize; ++i) { ScRange const & rRange = (*pSrc)[i]; for (sal_Int32 row = rRange.aStart.Row(); row <= rRange.aEnd.Row();++row) { for (sal_uInt16 col = rRange.aStart.Col(); col <= rRange.aEnd.Col();++col) { vecRet.emplace_back(col,row, rRange.aStart.Tab()); } } } return false; } //the Dest Rang List is not empty vecRet.reserve(10); size_t nSizeSrc = pSrc->size(); for (size_t i = 0; i < nSizeSrc; ++i) { ScRange const & rRange = (*pSrc)[i]; size_t nSizeDest = pDest->size(); for (size_t j = 0; j < nSizeDest; ++j) { ScRange const & rRangeDest = (*pDest)[j]; if (CalcScRangeDifferenceMax(rRange,rRangeDest,nMax,vecRet,nSize)) { return true; } } } return false; } //===== internal ============================================================ // FIXME: really unclear why we have an ScAccessibleTableBase with // only this single sub-class ScAccessibleSpreadsheet::ScAccessibleSpreadsheet( ScAccessibleDocument* pAccDoc, ScTabViewShell* pViewShell, SCTAB nTab, ScSplitPos eSplitPos) : ScAccessibleTableBase( pAccDoc, GetDocument(pViewShell), ScRange( 0, 0, nTab, GetDocument(pViewShell)->MaxCol(), GetDocument(pViewShell)->MaxRow(), nTab)), mbIsSpreadsheet( true ), m_bFormulaMode( false ), m_bFormulaLastMode( false ), m_nMinX(0),m_nMaxX(0),m_nMinY(0),m_nMaxY(0) { ConstructScAccessibleSpreadsheet( pAccDoc, pViewShell, nTab, eSplitPos ); } ScAccessibleSpreadsheet::ScAccessibleSpreadsheet( ScAccessibleSpreadsheet& rParent, const ScRange& rRange ) : ScAccessibleTableBase( rParent.mpAccDoc, rParent.mpDoc, rRange), mbIsSpreadsheet( false ), m_bFormulaMode( false ), m_bFormulaLastMode( false ), m_nMinX(0),m_nMaxX(0),m_nMinY(0),m_nMaxY(0) { ConstructScAccessibleSpreadsheet( rParent.mpAccDoc, rParent.mpViewShell, rParent.mnTab, rParent.meSplitPos ); } ScAccessibleSpreadsheet::~ScAccessibleSpreadsheet() { mpMarkedRanges.reset(); if (mpViewShell) mpViewShell->RemoveAccessibilityObject(*this); } void ScAccessibleSpreadsheet::ConstructScAccessibleSpreadsheet( ScAccessibleDocument* pAccDoc, ScTabViewShell* pViewShell, SCTAB nTab, ScSplitPos eSplitPos) { mpViewShell = pViewShell; mpMarkedRanges = nullptr; mpAccDoc = pAccDoc; mpAccCell.clear(); meSplitPos = eSplitPos; mnTab = nTab; mbDelIns = false; mbIsFocusSend = false; if (!mpViewShell) return; mpViewShell->AddAccessibilityObject(*this); const ScViewData& rViewData = mpViewShell->GetViewData(); maActiveCell = rViewData.GetCurPos(); mpAccCell = GetAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col()); ScDocument* pScDoc= GetDocument(mpViewShell); if (pScDoc) { pScDoc->GetName( maActiveCell.Tab(), m_strOldTabName ); } } void SAL_CALL ScAccessibleSpreadsheet::disposing() { SolarMutexGuard aGuard; if (mpViewShell) { mpViewShell->RemoveAccessibilityObject(*this); mpViewShell = nullptr; } mpAccCell.clear(); ScAccessibleTableBase::disposing(); } void ScAccessibleSpreadsheet::CompleteSelectionChanged(bool bNewState) { if (IsFormulaMode()) { return ; } mpMarkedRanges.reset(); AccessibleEventObject aEvent; aEvent.EventId = AccessibleEventId::STATE_CHANGED; if (bNewState) aEvent.NewValue <<= AccessibleStateType::SELECTED; else aEvent.OldValue <<= 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); aEvent.OldValue <<= uno::Reference(mpAccCell); 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; if (IsFormulaMode()) { if (!m_pAccFormulaCell.is() || !m_bFormulaLastMode) { ScAddress aFormulaAddr; if(!GetFormulaCurrentFocusCell(aFormulaAddr)) { return; } m_pAccFormulaCell = GetAccessibleCellAt(aFormulaAddr.Row(),aFormulaAddr.Col()); } xNew = m_pAccFormulaCell.get(); } else { if(mpAccCell->GetCellAddress() == maActiveCell) { xNew = mpAccCell.get(); } else { CommitFocusCell(maActiveCell); return ; } } 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 ( auto pRefHint = dynamic_cast(&rHint) ) { if (pRefHint->GetMode() == URM_INSDEL && pRefHint->GetDz() == 0) //test whether table is inserted or deleted { if (((pRefHint->GetRange().aStart.Col() == maRange.aStart.Col()) && (pRefHint->GetRange().aEnd.Col() == maRange.aEnd.Col())) || ((pRefHint->GetRange().aStart.Row() == maRange.aStart.Row()) && (pRefHint->GetRange().aEnd.Row() == maRange.aEnd.Row()))) { // ignore next SfxHintId::ScDataChanged notification mbDelIns = true; SCROW nFirstRow = -1; SCROW nLastRow = -1; SCCOL nFirstCol = -1; SCCOL nLastCol = -1; sal_Int16 nId(0); SCCOL nX(pRefHint->GetDx()); SCROW nY(pRefHint->GetDy()); ScRange aRange(pRefHint->GetRange()); if ((nX < 0) || (nY < 0)) { assert(!((nX < 0) && (nY < 0)) && "should not be possible to remove row and column at the same time"); // Range in the update hint is the range after the removed rows/columns; // calculate indices for the removed ones from that if (nX < 0) { nId = AccessibleTableModelChangeType::COLUMNS_REMOVED; nFirstCol = aRange.aStart.Col() + nX; nLastCol = aRange.aStart.Col() - 1; } else { nId = AccessibleTableModelChangeType::ROWS_REMOVED; nFirstRow = aRange.aStart.Row() + nY; nLastRow = aRange.aStart.Row() - 1; } } else if ((nX > 0) || (nY > 0)) { assert(!((nX > 0) && (nY > 0)) && "should not be possible to add row and column at the same time"); // Range in the update hint is from first inserted row/column to last one in spreadsheet; // calculate indices for the inserted ones from that if (nX > 0) { nId = AccessibleTableModelChangeType::COLUMNS_INSERTED; nFirstCol = aRange.aStart.Col(); nLastCol = aRange.aStart.Col() + nX - 1; } else { nId = AccessibleTableModelChangeType::ROWS_INSERTED; nFirstRow = aRange.aStart.Row(); nLastRow = aRange.aStart.Row() + nY -1; } } else { assert(false && "is it a deletion or an insertion?"); } CommitTableModelChange(nFirstRow, nFirstCol, nLastRow, nLastCol, nId); AccessibleEventObject aEvent; aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; aEvent.Source = uno::Reference< XAccessibleContext >(this); aEvent.NewValue <<= uno::Reference(mpAccCell); CommitChange(aEvent); } } } else { if (rHint.GetId() == SfxHintId::ScAccCursorChanged) { if (mpViewShell) { ScViewData& rViewData = mpViewShell->GetViewData(); m_bFormulaMode = rViewData.IsRefMode() || SC_MOD()->IsFormulaMode(); if ( m_bFormulaMode ) { NotifyRefMode(); m_bFormulaLastMode = true; return; } if (m_bFormulaLastMode) {//Last Notify Mode Is Formula Mode. m_vecFormulaLastMyAddr.clear(); RemoveFormulaSelection(true); m_pAccFormulaCell.clear(); //Remove All Selection } m_bFormulaLastMode = m_bFormulaMode; AccessibleEventObject aEvent; aEvent.Source = uno::Reference< XAccessible >(this); ScAddress aNewCell = rViewData.GetCurPos(); if(aNewCell.Tab() != maActiveCell.Tab()) { aEvent.EventId = AccessibleEventId::PAGE_CHANGED; auto pAccParent = getAccessibleParent(); ScAccessibleDocument *pAccDoc = static_cast(pAccParent.get()); if(pAccDoc) { pAccDoc->CommitChange(aEvent); } } bool bNewPosCell = (aNewCell != maActiveCell) || mpViewShell->GetForceFocusOnCurCell(); // #i123629# bool bNewPosCellFocus=false; if ( bNewPosCell && IsFocused() && aNewCell.Tab() == maActiveCell.Tab() ) {//single Focus bNewPosCellFocus=true; } ScMarkData &refScMarkData = rViewData.GetMarkData(); // MT IA2: Not used // int nSelCount = refScMarkData.GetSelectCount(); bool bIsMark =refScMarkData.IsMarked(); bool bIsMultMark = refScMarkData.IsMultiMarked(); bool bNewMarked = refScMarkData.GetTableSelect(aNewCell.Tab()) && ( bIsMark || bIsMultMark ); // sal_Bool bNewCellSelected = isAccessibleSelected(aNewCell.Row(), aNewCell.Col()); sal_uInt16 nTab = rViewData.GetTabNo(); const ScRange& aMarkRange = refScMarkData.GetMarkArea(); aEvent.OldValue.clear(); ScDocument* pDoc= GetDocument(mpViewShell); //Mark All if ( !bNewPosCellFocus && (bNewMarked || bIsMark || bIsMultMark ) && aMarkRange == ScRange( 0,0,nTab, pDoc->MaxCol(),pDoc->MaxRow(),nTab ) ) { aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN; aEvent.NewValue.clear(); CommitChange(aEvent); return ; } if (!mpMarkedRanges) { mpMarkedRanges.reset(new ScRangeList()); } refScMarkData.FillRangeListWithMarks(mpMarkedRanges.get(), true); //For Whole Col Row bool bWholeRow = std::abs(aMarkRange.aStart.Row() - aMarkRange.aEnd.Row()) == pDoc->MaxRow() ; bool bWholeCol = ::abs(aMarkRange.aStart.Col() - aMarkRange.aEnd.Col()) == pDoc->MaxCol() ; if ((bNewMarked || bIsMark || bIsMultMark ) && (bWholeCol || bWholeRow)) { if ( aMarkRange != m_aLastWithInMarkRange ) { RemoveSelection(refScMarkData); if(bNewPosCell) { CommitFocusCell(aNewCell); } bool bLastIsWholeColRow = (std::abs(m_aLastWithInMarkRange.aStart.Row() - m_aLastWithInMarkRange.aEnd.Row()) == pDoc->MaxRow() && bWholeRow) || (::abs(m_aLastWithInMarkRange.aStart.Col() - m_aLastWithInMarkRange.aEnd.Col()) == pDoc->MaxCol() && bWholeCol); bool bSelSmaller= bLastIsWholeColRow && !aMarkRange.Contains(m_aLastWithInMarkRange) && aMarkRange.Intersects(m_aLastWithInMarkRange); if( !bSelSmaller ) { aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN; aEvent.NewValue.clear(); CommitChange(aEvent); } m_aLastWithInMarkRange = aMarkRange; } return ; } m_aLastWithInMarkRange = aMarkRange; int nNewMarkCount = mpMarkedRanges->GetCellCount(); bool bSendSingle= (0 == nNewMarkCount) && bNewPosCell; if (bSendSingle) { RemoveSelection(refScMarkData); if(bNewPosCellFocus) { CommitFocusCell(aNewCell); } uno::Reference< XAccessible > xChild ; if (bNewPosCellFocus) { xChild = mpAccCell.get(); } else { mpAccCell = GetAccessibleCellAt(aNewCell.Row(),aNewCell.Col()); xChild = mpAccCell.get(); maActiveCell = aNewCell; aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS; aEvent.NewValue <<= xChild; aEvent.OldValue <<= uno::Reference< XAccessible >(); CommitChange(aEvent); } aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; aEvent.NewValue <<= xChild; CommitChange(aEvent); OSL_ASSERT(m_mapSelectionSend.count(aNewCell) == 0 ); m_mapSelectionSend.emplace(aNewCell,xChild); } else { ScRange aDelRange; bool bIsDel = rViewData.GetDelMark( aDelRange ); if ( (!bIsDel || aMarkRange != aDelRange) && bNewMarked && nNewMarkCount > 0 && m_LastMarkedRanges != *mpMarkedRanges ) { RemoveSelection(refScMarkData); if(bNewPosCellFocus) { CommitFocusCell(aNewCell); } std::vector vecNew; if(CalcScRangeListDifferenceMax(mpMarkedRanges.get(), &m_LastMarkedRanges,10,vecNew)) { aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN; aEvent.NewValue.clear(); CommitChange(aEvent); } else { for(const auto& rAddr : vecNew) { uno::Reference< XAccessible > xChild = getAccessibleCellAt(rAddr.Row(),rAddr.Col()); if (!(bNewPosCellFocus && rAddr == aNewCell) ) { aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS; aEvent.NewValue <<= xChild; CommitChange(aEvent); } aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD; aEvent.NewValue <<= xChild; CommitChange(aEvent); m_mapSelectionSend.emplace(rAddr,xChild); } } } } if (bNewPosCellFocus && maActiveCell != aNewCell) { CommitFocusCell(aNewCell); } m_LastMarkedRanges = *mpMarkedRanges; } } else if (rHint.GetId() == SfxHintId::ScDataChanged) { if (!mbDelIns) CommitTableModelChange(maRange.aStart.Row(), maRange.aStart.Col(), maRange.aEnd.Row(), maRange.aEnd.Col(), AccessibleTableModelChangeType::UPDATE); else mbDelIns = false; if (mpViewShell) { ScViewData& rViewData = mpViewShell->GetViewData(); ScAddress aNewCell = rViewData.GetCurPos(); if( maActiveCell == aNewCell) { ScDocument* pScDoc= GetDocument(mpViewShell); if (pScDoc) { OUString valStr(pScDoc->GetString(aNewCell.Col(),aNewCell.Row(),aNewCell.Tab())); if(m_strCurCellValue != valStr) { AccessibleEventObject aEvent; aEvent.EventId = AccessibleEventId::VALUE_CHANGED; mpAccCell->CommitChange(aEvent); m_strCurCellValue=valStr; } OUString tabName; pScDoc->GetName( maActiveCell.Tab(), tabName ); if( m_strOldTabName != tabName ) { AccessibleEventObject aEvent; aEvent.EventId = AccessibleEventId::NAME_CHANGED; OUString sOldName(ScResId(STR_ACC_TABLE_NAME)); sOldName = sOldName.replaceFirst("%1", m_strOldTabName); aEvent.OldValue <<= sOldName; OUString sNewName(ScResId(STR_ACC_TABLE_NAME)); sNewName = sNewName.replaceFirst("%1", tabName); aEvent.NewValue <<= sNewName; CommitChange( aEvent ); m_strOldTabName = tabName; } } } } } // 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.Overlaps(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); } }*/ } ScAccessibleTableBase::Notify(rBC, rHint); } void ScAccessibleSpreadsheet::RemoveSelection(const ScMarkData &refScMarkData) { AccessibleEventObject aEvent; aEvent.Source = uno::Reference< XAccessible >(this); MAP_ADDR_XACC::iterator miRemove = m_mapSelectionSend.begin(); while (miRemove != m_mapSelectionSend.end()) { if (refScMarkData.IsCellMarked(miRemove->first.Col(),miRemove->first.Row(),true) || refScMarkData.IsCellMarked(miRemove->first.Col(),miRemove->first.Row()) ) { ++miRemove; continue; } aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE; aEvent.NewValue <<= miRemove->second; CommitChange(aEvent); miRemove = m_mapSelectionSend.erase(miRemove); } } void ScAccessibleSpreadsheet::CommitFocusCell(const ScAddress &aNewCell) { OSL_ASSERT(!IsFormulaMode()); if(IsFormulaMode()) { return ; } AccessibleEventObject aEvent; aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; aEvent.Source = uno::Reference< XAccessible >(this); aEvent.OldValue <<= uno::Reference(mpAccCell); mpAccCell.clear(); mpAccCell = GetAccessibleCellAt(aNewCell.Row(), aNewCell.Col()); aEvent.NewValue <<= uno::Reference(mpAccCell); maActiveCell = aNewCell; ScDocument* pScDoc= GetDocument(mpViewShell); if (pScDoc) { m_strCurCellValue = pScDoc->GetString(maActiveCell.Col(),maActiveCell.Row(),maActiveCell.Tab()); } CommitChange(aEvent); } //===== XAccessibleTable ================================================ uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleRowHeaders( ) { SolarMutexGuard aGuard; IsObjectValid(); uno::Reference< XAccessibleTable > xAccessibleTable; if( mpDoc && mbIsSpreadsheet ) { if( std::optional oRowRange = mpDoc->GetRepeatRowRange( mnTab ) ) { SCROW nStart = oRowRange->aStart.Row(); SCROW nEnd = oRowRange->aEnd.Row(); ScDocument* pDoc = GetDocument(mpViewShell); if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= pDoc->MaxRow()) ) xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( 0, nStart, mnTab, pDoc->MaxCol(), nEnd, mnTab ) ) ); } } return xAccessibleTable; } uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleColumnHeaders( ) { SolarMutexGuard aGuard; IsObjectValid(); uno::Reference< XAccessibleTable > xAccessibleTable; if( mpDoc && mbIsSpreadsheet ) { if( std::optional oColRange = mpDoc->GetRepeatColRange( mnTab ) ) { SCCOL nStart = oColRange->aStart.Col(); SCCOL nEnd = oColRange->aEnd.Col(); ScDocument* pDoc = GetDocument(mpViewShell); if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= pDoc->MaxCol()) ) xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( nStart, 0, mnTab, nEnd, pDoc->MaxRow(), mnTab ) ) ); } } return xAccessibleTable; } uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleRows( ) { SolarMutexGuard aGuard; IsObjectValid(); uno::Sequence aSequence; if (IsFormulaMode()) { return aSequence; } if (mpViewShell) { 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( ) { SolarMutexGuard aGuard; IsObjectValid(); uno::Sequence aSequence; if (IsFormulaMode() || !mpViewShell) return aSequence; aSequence.realloc(maRange.aEnd.Col() - maRange.aStart.Col() + 1); sal_Int32* pSequence = aSequence.getArray(); sal_Int32 nCount(0); const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData(); for (SCCOL i = maRange.aStart.Col(); i <= maRange.aEnd.Col(); ++i) { if (rMarkdata.IsColumnMarked(i)) { pSequence[nCount] = i; ++nCount; } } aSequence.realloc(nCount); return aSequence; } sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleRowSelected( sal_Int32 nRow ) { SolarMutexGuard aGuard; IsObjectValid(); if (IsFormulaMode()) { return false; } if ((nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0)) throw lang::IndexOutOfBoundsException(); bool bResult(false); if (mpViewShell) { const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData(); bResult = rMarkdata.IsRowMarked(static_cast(nRow)); } return bResult; } sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleColumnSelected( sal_Int32 nColumn ) { SolarMutexGuard aGuard; IsObjectValid(); if (IsFormulaMode()) { return false; } if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0)) throw lang::IndexOutOfBoundsException(); bool bResult(false); if (mpViewShell) { const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData(); bResult = rMarkdata.IsColumnMarked(static_cast(nColumn)); } return bResult; } rtl::Reference ScAccessibleSpreadsheet::GetAccessibleCellAt(sal_Int32 nRow, sal_Int32 nColumn) { if (IsFormulaMode()) { ScAddress aCellAddress(static_cast(nColumn), nRow, mpViewShell->GetViewData().GetTabNo()); if ((aCellAddress == m_aFormulaActiveCell) && m_pAccFormulaCell.is()) { return m_pAccFormulaCell; } else return ScAccessibleCell::create(this, mpViewShell, aCellAddress, GetAccessibleIndexFormula(nRow, nColumn), meSplitPos, mpAccDoc); } else { ScAddress aCellAddress(static_cast(maRange.aStart.Col() + nColumn), static_cast(maRange.aStart.Row() + nRow), maRange.aStart.Tab()); if ((aCellAddress == maActiveCell) && mpAccCell.is()) { return mpAccCell; } else return ScAccessibleCell::create(this, mpViewShell, aCellAddress, getAccessibleIndex(nRow, nColumn), meSplitPos, mpAccDoc); } } uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) { SolarMutexGuard aGuard; IsObjectValid(); if (!IsFormulaMode()) { if (nRow > (maRange.aEnd.Row() - maRange.aStart.Row()) || nRow < 0 || nColumn > (maRange.aEnd.Col() - maRange.aStart.Col()) || nColumn < 0) throw lang::IndexOutOfBoundsException(); } rtl::Reference pAccessibleCell = GetAccessibleCellAt(nRow, nColumn); return pAccessibleCell; } sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) { SolarMutexGuard aGuard; IsObjectValid(); if (IsFormulaMode()) { ScAddress addr(static_cast(nColumn), nRow, 0); return IsScAddrFormulaSel(addr); } if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) || (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0)) throw lang::IndexOutOfBoundsException(); bool bResult(false); if (mpViewShell) { const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData(); bResult = rMarkdata.IsCellMarked(static_cast(nColumn), static_cast(nRow)); } return bResult; } //===== XAccessibleComponent ============================================ uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleAtPoint(const awt::Point& rPoint) { uno::Reference< XAccessible > xAccessible; if (containsPoint(rPoint)) { SolarMutexGuard aGuard; IsObjectValid(); if (mpViewShell) { SCCOL nX; SCROW nY; mpViewShell->GetViewData().GetPosFromPixel( rPoint.X, rPoint.Y, meSplitPos, nX, nY); try { xAccessible = getAccessibleCellAt(nY, nX); } catch(const css::lang::IndexOutOfBoundsException &) { return nullptr; } } } return xAccessible; } void SAL_CALL ScAccessibleSpreadsheet::grabFocus( ) { if (getAccessibleParent().is()) { uno::Reference xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); if (xAccessibleComponent.is()) xAccessibleComponent->grabFocus(); } } sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getForeground( ) { return sal_Int32(COL_BLACK); } sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getBackground( ) { SolarMutexGuard aGuard; IsObjectValid(); return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor); } //===== XAccessibleContext ============================================== uno::Reference SAL_CALL ScAccessibleSpreadsheet::getAccessibleRelationSet() { rtl::Reference pRelationSet; if(mpAccDoc) pRelationSet = mpAccDoc->GetRelationSet(nullptr); if (pRelationSet) return pRelationSet; return new utl::AccessibleRelationSetHelper(); } uno::Reference SAL_CALL ScAccessibleSpreadsheet::getAccessibleStateSet() { SolarMutexGuard aGuard; uno::Reference xParentStates; if (getAccessibleParent().is()) { uno::Reference xParentContext = getAccessibleParent()->getAccessibleContext(); xParentStates = xParentContext->getAccessibleStateSet(); } rtl::Reference pStateSet = new utl::AccessibleStateSetHelper(); if (IsDefunc(xParentStates)) pStateSet->AddState(AccessibleStateType::DEFUNC); else { pStateSet->AddState(AccessibleStateType::MANAGES_DESCENDANTS); if (IsEditable()) 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 ) { SolarMutexGuard 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, false); } } void SAL_CALL ScAccessibleSpreadsheet::clearAccessibleSelection( ) { SolarMutexGuard aGuard; IsObjectValid(); if (mpViewShell && !IsFormulaMode()) mpViewShell->Unmark(); } void SAL_CALL ScAccessibleSpreadsheet::selectAllAccessibleChildren( ) { SolarMutexGuard aGuard; IsObjectValid(); if (!mpViewShell) return; if (IsFormulaMode()) { ScDocument* pDoc = GetDocument(mpViewShell); ScViewData& rViewData = mpViewShell->GetViewData(); mpViewShell->InitRefMode( 0, 0, rViewData.GetTabNo(), SC_REFTYPE_REF ); rViewData.SetRefStart(0, 0, rViewData.GetTabNo()); rViewData.SetRefEnd(pDoc->MaxCol(), pDoc->MaxRow(), rViewData.GetTabNo()); mpViewShell->UpdateRef(pDoc->MaxCol(), pDoc->MaxRow(), rViewData.GetTabNo()); } else mpViewShell->SelectAll(); } sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleChildCount( ) { SolarMutexGuard aGuard; IsObjectValid(); sal_Int32 nResult(0); if (mpViewShell) { if (IsFormulaMode()) { nResult = GetRowAll() * GetColAll() ; } else { if (!mpMarkedRanges) { mpMarkedRanges.reset(new ScRangeList()); ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData()); aMarkData.FillRangeListWithMarks(mpMarkedRanges.get(), false); } // is possible, because there shouldn't be overlapped ranges in it if (mpMarkedRanges) nResult = mpMarkedRanges->GetCellCount(); } } return nResult; } uno::Reference SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) { SolarMutexGuard aGuard; IsObjectValid(); uno::Reference < XAccessible > xAccessible; if (IsFormulaMode()) { if(CheckChildIndex(nSelectedChildIndex)) { ScAddress addr = GetChildIndexAddress(nSelectedChildIndex); xAccessible = getAccessibleCellAt(addr.Row(), addr.Col()); } return xAccessible; } if (mpViewShell) { if (!mpMarkedRanges) { mpMarkedRanges.reset(new ScRangeList()); mpViewShell->GetViewData().GetMarkData().FillRangeListWithMarks(mpMarkedRanges.get(), false); } if (mpMarkedRanges) { if ((nSelectedChildIndex < 0) || (mpMarkedRanges->GetCellCount() <= o3tl::make_unsigned(nSelectedChildIndex))) { throw lang::IndexOutOfBoundsException(); } ScMyAddress addr = CalcScAddressFromRangeList(mpMarkedRanges.get(),nSelectedChildIndex); if( m_mapSelectionSend.find(addr) != m_mapSelectionSend.end() ) xAccessible = m_mapSelectionSend[addr]; else xAccessible = getAccessibleCellAt(addr.Row(), addr.Col()); } } return xAccessible; } void SAL_CALL ScAccessibleSpreadsheet::deselectAccessibleChild( sal_Int32 nChildIndex ) { SolarMutexGuard aGuard; IsObjectValid(); if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount()) throw lang::IndexOutOfBoundsException(); if (!mpViewShell) return; sal_Int32 nCol(getAccessibleColumn(nChildIndex)); sal_Int32 nRow(getAccessibleRow(nChildIndex)); if (IsFormulaMode()) { if(IsScAddrFormulaSel( ScAddress(static_cast(nCol), nRow,mpViewShell->GetViewData().GetTabNo())) ) { SelectCell(nRow, nCol, true); } return ; } if (mpViewShell->GetViewData().GetMarkData().IsCellMarked(static_cast(nCol), static_cast(nRow))) SelectCell(nRow, nCol, true); } void ScAccessibleSpreadsheet::SelectCell(sal_Int32 nRow, sal_Int32 nCol, bool bDeselect) { if (IsFormulaMode()) { if (bDeselect) {//?? return; } else { ScViewData& rViewData = mpViewShell->GetViewData(); mpViewShell->InitRefMode( static_cast(nCol), nRow, rViewData.GetTabNo(), SC_REFTYPE_REF ); mpViewShell->UpdateRef(static_cast(nCol), nRow, rViewData.GetTabNo()); } return ; } mpViewShell->SetTabNo( maRange.aStart.Tab() ); mpViewShell->DoneBlockMode( true ); // continue selecting mpViewShell->InitBlockMode( static_cast(nCol), static_cast(nRow), maRange.aStart.Tab(), bDeselect ); mpViewShell->SelectionChanged(); } /* void ScAccessibleSpreadsheet::CreateSortedMarkedCells() { mpSortedMarkedCells = new std::vector(); mpSortedMarkedCells->reserve(mpMarkedRanges->GetCellCount()); for ( size_t i = 0, ListSize = mpMarkedRanges->size(); i < ListSize; ++i ) { ScRange* pRange = (*mpMarkedRanges)[i]; 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 { OSL_FAIL("Range of wrong table"); } } else if(pRange->aStart.Tab() == maActiveCell.Tab()) AddMarkedRange(*pRange); else { OSL_FAIL("Range of wrong table"); } } 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 ==================================================== OUString SAL_CALL ScAccessibleSpreadsheet::getImplementationName() { return "ScAccessibleSpreadsheet"; } uno::Sequence< OUString> SAL_CALL ScAccessibleSpreadsheet::getSupportedServiceNames() { const css::uno::Sequence vals { "com.sun.star.AccessibleSpreadsheet" }; return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals); } //===== XTypeProvider ======================================================= uno::Sequence SAL_CALL ScAccessibleSpreadsheet::getImplementationId() { return css::uno::Sequence(); } ///===== XAccessibleEventBroadcaster ===================================== void SAL_CALL ScAccessibleSpreadsheet::addAccessibleEventListener(const uno::Reference& xListener) { SolarMutexGuard aGuard; IsObjectValid(); ScAccessibleTableBase::addAccessibleEventListener(xListener); } //==== internal ========================================================= tools::Rectangle ScAccessibleSpreadsheet::GetBoundingBoxOnScreen() const { tools::Rectangle aRect; if (mpViewShell) { vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); if (pWindow) aRect = pWindow->GetWindowExtentsRelative(nullptr); } return aRect; } tools::Rectangle ScAccessibleSpreadsheet::GetBoundingBox() const { tools::Rectangle aRect; if (mpViewShell) { vcl::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; } bool ScAccessibleSpreadsheet::IsDefunc( const uno::Reference& rxParentStates) { return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() || (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); } bool ScAccessibleSpreadsheet::IsEditable() { if (IsFormulaMode()) { return false; } bool bProtected(false); if (mpDoc && mpDoc->IsTabProtected(maRange.aStart.Tab())) bProtected = true; return !bProtected; } bool ScAccessibleSpreadsheet::IsFocused() { bool bFocused(false); if (mpViewShell) { if (mpViewShell->GetViewData().GetActivePart() == meSplitPos) bFocused = mpViewShell->GetActiveWin()->HasFocus(); } return bFocused; } bool ScAccessibleSpreadsheet::IsCompleteSheetSelected() { if (IsFormulaMode()) { return false; } bool bResult(false); if(mpViewShell) { //#103800#; use a copy of MarkData ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData()); if (aMarkData.IsAllMarked(maRange)) bResult = true; } return bResult; } ScDocument* ScAccessibleSpreadsheet::GetDocument(ScTabViewShell* pViewShell) { ScDocument* pDoc = nullptr; if (pViewShell) pDoc = &pViewShell->GetViewData().GetDocument(); return pDoc; } sal_Bool SAL_CALL ScAccessibleSpreadsheet::selectRow( sal_Int32 row ) { SolarMutexGuard g; if (IsFormulaMode()) { return false; } ScDocument* pDoc = GetDocument(mpViewShell); mpViewShell->SetTabNo( maRange.aStart.Tab() ); mpViewShell->DoneBlockMode( true ); // continue selecting mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true ); mpViewShell->MarkCursor( pDoc->MaxCol(), row, maRange.aStart.Tab(), false, true ); mpViewShell->SelectionChanged(); return true; } sal_Bool SAL_CALL ScAccessibleSpreadsheet::selectColumn( sal_Int32 column ) { SolarMutexGuard g; if (IsFormulaMode()) { return false; } ScDocument* pDoc = GetDocument(mpViewShell); mpViewShell->SetTabNo( maRange.aStart.Tab() ); mpViewShell->DoneBlockMode( true ); // continue selecting mpViewShell->InitBlockMode( static_cast(column), 0, maRange.aStart.Tab(), false, true ); mpViewShell->MarkCursor( static_cast(column), pDoc->MaxRow(), maRange.aStart.Tab(), true ); mpViewShell->SelectionChanged(); return true; } sal_Bool SAL_CALL ScAccessibleSpreadsheet::unselectRow( sal_Int32 row ) { SolarMutexGuard g; if (IsFormulaMode()) { return false; } ScDocument* pDoc = GetDocument(mpViewShell); mpViewShell->SetTabNo( maRange.aStart.Tab() ); mpViewShell->DoneBlockMode( true ); // continue selecting mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true, true ); mpViewShell->MarkCursor( pDoc->MaxCol(), row, maRange.aStart.Tab(), false, true ); mpViewShell->SelectionChanged(); mpViewShell->DoneBlockMode( true ); return true; } sal_Bool SAL_CALL ScAccessibleSpreadsheet::unselectColumn( sal_Int32 column ) { SolarMutexGuard g; if (IsFormulaMode()) { return false; } ScDocument* pDoc = GetDocument(mpViewShell); mpViewShell->SetTabNo( maRange.aStart.Tab() ); mpViewShell->DoneBlockMode( true ); // continue selecting mpViewShell->InitBlockMode( static_cast(column), 0, maRange.aStart.Tab(), false, true, false, true ); mpViewShell->MarkCursor( static_cast(column), pDoc->MaxRow(), maRange.aStart.Tab(), true ); mpViewShell->SelectionChanged(); mpViewShell->DoneBlockMode( true ); return true; } void ScAccessibleSpreadsheet::FireFirstCellFocus() { if (IsFormulaMode()) { return ; } if (mbIsFocusSend) { return ; } mbIsFocusSend = true; AccessibleEventObject aEvent; aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; aEvent.Source = uno::Reference< XAccessible >(this); aEvent.NewValue <<= getAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col()); CommitChange(aEvent); } void ScAccessibleSpreadsheet::NotifyRefMode() { ScViewData& rViewData = mpViewShell->GetViewData(); if (!rViewData.IsRefMode()) // Not in reference mode. Bail out. return; sal_uInt16 nRefStartX = rViewData.GetRefStartX(); sal_Int32 nRefStartY = rViewData.GetRefStartY(); sal_uInt16 nRefEndX = rViewData.GetRefEndX(); sal_Int32 nRefEndY = rViewData.GetRefEndY(); ScAddress aFormulaAddr; if(!GetFormulaCurrentFocusCell(aFormulaAddr)) { return ; } if (m_aFormulaActiveCell != aFormulaAddr) {//New Focus m_nMinX =std::min(nRefStartX,nRefEndX); m_nMaxX =std::max(nRefStartX,nRefEndX); m_nMinY = std::min(nRefStartY,nRefEndY); m_nMaxY = std::max(nRefStartY,nRefEndY); RemoveFormulaSelection(); AccessibleEventObject aEvent; aEvent.Source = uno::Reference< XAccessible >(this); aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED; aEvent.OldValue <<= uno::Reference(m_pAccFormulaCell); m_pAccFormulaCell = GetAccessibleCellAt(aFormulaAddr.Row(), aFormulaAddr.Col()); uno::Reference< XAccessible > xNew = m_pAccFormulaCell; aEvent.NewValue <<= xNew; CommitChange(aEvent); if (nRefStartX == nRefEndX && nRefStartY == nRefEndY) {//Selection Single aEvent.EventId = AccessibleEventId::SELECTION_CHANGED; aEvent.NewValue <<= xNew; CommitChange(aEvent); m_mapFormulaSelectionSend.emplace(aFormulaAddr,xNew); m_vecFormulaLastMyAddr.clear(); m_vecFormulaLastMyAddr.emplace_back(aFormulaAddr); } else { std::vector vecCurSel; int nCurSize = (m_nMaxX - m_nMinX +1)*(m_nMaxY - m_nMinY +1) ; vecCurSel.reserve(nCurSize); for (sal_uInt16 x = m_nMinX ; x <= m_nMaxX ; ++x) { for (sal_Int32 y = m_nMinY ; y <= m_nMaxY ; ++y) { ScMyAddress aAddr(x,y,0); vecCurSel.push_back(aAddr); } } std::sort(vecCurSel.begin(), vecCurSel.end()); std::vector vecNew; std::set_difference(vecCurSel.begin(),vecCurSel.end(), m_vecFormulaLastMyAddr.begin(),m_vecFormulaLastMyAddr.end(), std::back_insert_iterator(vecNew)); int nNewSize = vecNew.size(); if ( nNewSize > 10 ) { aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN; aEvent.NewValue.clear(); CommitChange(aEvent); } else { for(const auto& rAddr : vecNew) { uno::Reference< XAccessible > xChild; if (rAddr == aFormulaAddr) { xChild = m_pAccFormulaCell.get(); } else { xChild = getAccessibleCellAt(rAddr.Row(),rAddr.Col()); aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS; aEvent.NewValue <<= xChild; CommitChange(aEvent); } aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD; aEvent.NewValue <<= xChild; CommitChange(aEvent); m_mapFormulaSelectionSend.emplace(rAddr,xChild); } } m_vecFormulaLastMyAddr.swap(vecCurSel); } } m_aFormulaActiveCell = aFormulaAddr; } void ScAccessibleSpreadsheet::RemoveFormulaSelection(bool bRemoveAll ) { AccessibleEventObject aEvent; aEvent.Source = uno::Reference< XAccessible >(this); MAP_ADDR_XACC::iterator miRemove = m_mapFormulaSelectionSend.begin(); while (miRemove != m_mapFormulaSelectionSend.end()) { if( !bRemoveAll && IsScAddrFormulaSel(miRemove->first) ) { ++miRemove; continue; } aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE; aEvent.NewValue <<= miRemove->second; CommitChange(aEvent); miRemove = m_mapFormulaSelectionSend.erase(miRemove); } } bool ScAccessibleSpreadsheet::IsScAddrFormulaSel(const ScAddress &addr) const { return addr.Col() >= m_nMinX && addr.Col() <= m_nMaxX && addr.Row() >= m_nMinY && addr.Row() <= m_nMaxY && addr.Tab() == mpViewShell->GetViewData().GetTabNo(); } bool ScAccessibleSpreadsheet::CheckChildIndex(sal_Int32 nIndex) const { sal_Int32 nMaxIndex = (m_nMaxX - m_nMinX +1)*(m_nMaxY - m_nMinY +1) -1 ; return nIndex <= nMaxIndex && nIndex >= 0 ; } ScAddress ScAccessibleSpreadsheet::GetChildIndexAddress(sal_Int32 nIndex) const { sal_Int32 nRowAll = GetRowAll(); sal_uInt16 nColAll = GetColAll(); if (nIndex < 0 || nIndex >= nRowAll * nColAll ) { return ScAddress(); } return ScAddress( static_cast((nIndex - nIndex % nRowAll) / nRowAll + + m_nMinX), nIndex % nRowAll + m_nMinY, mpViewShell->GetViewData().GetTabNo() ); } sal_Int32 ScAccessibleSpreadsheet::GetAccessibleIndexFormula( sal_Int32 nRow, sal_Int32 nColumn ) { sal_uInt16 nColRelative = sal_uInt16(nColumn) - GetColAll(); sal_Int32 nRowRelative = nRow - GetRowAll(); if (nRow < 0 || nColumn < 0 || nRowRelative >= GetRowAll() || nColRelative >= GetColAll() ) { return -1; } return GetRowAll() * nRowRelative + nColRelative; } bool ScAccessibleSpreadsheet::IsFormulaMode() { ScViewData& rViewData = mpViewShell->GetViewData(); m_bFormulaMode = rViewData.IsRefMode() || SC_MOD()->IsFormulaMode(); return m_bFormulaMode ; } bool ScAccessibleSpreadsheet::GetFormulaCurrentFocusCell(ScAddress &addr) { ScViewData& rViewData = mpViewShell->GetViewData(); sal_uInt16 nRefX=0; sal_Int32 nRefY=0; if(m_bFormulaLastMode) { nRefX=rViewData.GetRefEndX(); nRefY=rViewData.GetRefEndY(); } else { nRefX=rViewData.GetRefStartX(); nRefY=rViewData.GetRefStartY(); } ScDocument* pDoc = GetDocument(mpViewShell); if( /* Always true: nRefX >= 0 && */ nRefX <= pDoc->MaxCol() && nRefY >= 0 && nRefY <= pDoc->MaxRow()) { addr = ScAddress(nRefX,nRefY,rViewData.GetTabNo()); return true; } return false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */