/* -*- 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 <AccessibleSpreadsheet.hxx>
#include <AccessibilityHints.hxx>
#include <AccessibleCell.hxx>
#include <AccessibleDocument.hxx>
#include <tabvwsh.hxx>
#include <document.hxx>
#include <hints.hxx>
#include <scmod.hxx>
#include <markdata.hxx>
#include <gridwin.hxx>
#include <unotools/accessiblestatesethelper.hxx>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
#include <sal/log.hxx>
#include <tools/gen.hxx>
#include <svtools/colorcfg.hxx>
#include <vcl/svapp.hxx>
#include <scresid.hxx>
#include <strings.hrc>
#include <algorithm>
using namespace ::com::sun::star;
using namespace ::com::sun::star::accessibility;
bool CompMinCol(const std::pair<sal_uInt16,sal_uInt16> & pc1,const std::pair<sal_uInt16,sal_uInt16> &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<SCCOL>(rRange.aStart.Col() + nCurCol), rRange.aStart.Row() + nCurRow, maActiveCell.Tab());
}
else
{
sal_Int32 nMinRow = MAXROW;
sal_Int32 nMaxRow = 0;
m_vecTempRange.clear();
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())
{
m_vecTempRange.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())
{
m_vecTempRange.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)
{
m_vecTempCol.clear();
{
VEC_RANGE::const_iterator vi = m_vecTempRange.begin();
for (; vi < m_vecTempRange.end(); ++vi)
{
ScRange const & r = *vi;
if ( row >= r.aStart.Row() && row <= r.aEnd.Row())
{
m_vecTempCol.emplace_back(r.aStart.Col(),r.aEnd.Col());
}
}
}
std::sort(m_vecTempCol.begin(),m_vecTempCol.end(),CompMinCol);
{
VEC_COL::const_iterator vic = m_vecTempCol.begin();
for(; vic != m_vecTempCol.end(); ++vic)
{
const PAIR_COL &pariCol = *vic;
sal_uInt16 nCol = pariCol.second - pariCol.first + 1;
if (nCol + nCurrentIndex > nSelectedChildIndex)
{
return ScMyAddress(static_cast<SCCOL>(pariCol.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, VEC_MYADDR &vecRet, int &nSize)
{
//Src Must be :Src > Dest
if (rDest.In(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.In(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.In(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,VEC_MYADDR &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() > sal_uInt32(nMax))//if the Src Cell count is greater then nMax
{
return true;
}
//now the cell count is less then 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, MAXCOL, 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 )
{
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;
maVisCells = GetVisCells(GetVisArea(mpViewShell, meSplitPos));
if (mpViewShell)
{
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<XAccessible>(mpAccCell.get());
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 ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
{
const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
if (rRef.GetMode() == URM_INSDEL && rRef.GetDz() == 0) //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 SfxHintId::ScDataChanged notification
mbDelIns = true;
sal_Int16 nId(0);
SCCOL nX(rRef.GetDx());
SCROW nY(rRef.GetDy());
ScRange aRange(rRef.GetRange());
if ((nX < 0) || (nY < 0))
{
OSL_ENSURE(!((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))
{
OSL_ENSURE(!((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
{
OSL_FAIL("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);
aEvent.NewValue <<= uno::Reference<XAccessible>(mpAccCell.get());
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;
ScAccessibleDocument *pAccDoc =
static_cast<ScAccessibleDocument*>(getAccessibleParent().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();
ScRange aMarkRange;
refScMarkData.GetMarkArea(aMarkRange);
aEvent.OldValue.clear();
//Mark All
if ( !bNewPosCellFocus &&
(bNewMarked || bIsMark || bIsMultMark ) &&
aMarkRange == ScRange( 0,0,nTab, MAXCOL,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 = ::labs(aMarkRange.aStart.Row() - aMarkRange.aEnd.Row()) == MAXROW ;
bool bWholeCol = ::abs(aMarkRange.aStart.Col() - aMarkRange.aEnd.Col()) == MAXCOL ;
if ((bNewMarked || bIsMark || bIsMultMark ) && (bWholeCol || bWholeRow))
{
if ( aMarkRange != m_aLastWithInMarkRange )
{
RemoveSelection(refScMarkData);
if(bNewPosCell)
{
CommitFocusCell(aNewCell);
}
bool bLastIsWholeColRow =
(::labs(m_aLastWithInMarkRange.aStart.Row() - m_aLastWithInMarkRange.aEnd.Row()) == MAXROW && bWholeRow) ||
(::abs(m_aLastWithInMarkRange.aStart.Col() - m_aLastWithInMarkRange.aEnd.Col()) == MAXCOL && bWholeCol);
bool bSelSmaller=
bLastIsWholeColRow &&
!aMarkRange.In(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);
}
VEC_MYADDR vecNew;
if(CalcScRangeListDifferenceMax(mpMarkedRanges.get(), &m_LastMarkedRanges,10,vecNew))
{
aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
aEvent.NewValue.clear();
CommitChange(aEvent);
}
else
{
VEC_MYADDR::iterator viAddr = vecNew.begin();
for(; viAddr < vecNew.end() ; ++viAddr )
{
uno::Reference< XAccessible > xChild = getAccessibleCellAt(viAddr->Row(),viAddr->Col());
if (!(bNewPosCellFocus && *viAddr == 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(*viAddr,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;
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));
sOldName = 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.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);
}
}*/
}
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();
for(; 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);
MAP_ADDR_XACC::iterator miNext = miRemove;
++miNext;
m_mapSelectionSend.erase(miRemove);
miRemove = miNext;
}
}
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<XAccessible>(mpAccCell.get());
mpAccCell.clear();
mpAccCell = GetAccessibleCellAt(aNewCell.Row(), aNewCell.Col());
aEvent.NewValue <<= uno::Reference<XAccessible>(mpAccCell.get());
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( 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( )
{
SolarMutexGuard 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( )
{
SolarMutexGuard aGuard;
IsObjectValid();
uno::Sequence<sal_Int32> 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<sal_Int32> 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<SCROW>(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<SCCOL>(nColumn));
}
return bResult;
}
rtl::Reference<ScAccessibleCell> ScAccessibleSpreadsheet::GetAccessibleCellAt(sal_Int32 nRow, sal_Int32 nColumn)
{
if (IsFormulaMode())
{
ScAddress aCellAddress(static_cast<SCCOL>(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<SCCOL>(maRange.aStart.Col() + nColumn),
static_cast<SCROW>(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<ScAccessibleCell> pAccessibleCell = GetAccessibleCellAt(nRow, nColumn);
return pAccessibleCell.get();
}
sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
{
SolarMutexGuard aGuard;
IsObjectValid();
if (IsFormulaMode())
{
ScAddress addr(static_cast<SCCOL>(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<SCCOL>(nColumn), static_cast<SCROW>(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> 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<XAccessibleRelationSet> SAL_CALL ScAccessibleSpreadsheet::getAccessibleRelationSet()
{
utl::AccessibleRelationSetHelper* pRelationSet = nullptr;
if(mpAccDoc)
pRelationSet = mpAccDoc->GetRelationSet(nullptr);
if (!pRelationSet)
pRelationSet = new utl::AccessibleRelationSetHelper();
return pRelationSet;
}
uno::Reference<XAccessibleStateSet> SAL_CALL
ScAccessibleSpreadsheet::getAccessibleStateSet()
{
SolarMutexGuard 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())
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)
{
if (!IsFormulaMode())
mpViewShell->Unmark();
}
}
void SAL_CALL ScAccessibleSpreadsheet::selectAllAccessibleChildren( )
{
SolarMutexGuard aGuard;
IsObjectValid();
if (mpViewShell)
{
if (IsFormulaMode())
{
ScViewData& rViewData = mpViewShell->GetViewData();
mpViewShell->InitRefMode( 0, 0, rViewData.GetTabNo(), SC_REFTYPE_REF );
rViewData.SetRefStart(0, 0, rViewData.GetTabNo());
rViewData.SetRefEnd(MAXCOL, MAXROW, rViewData.GetTabNo());
mpViewShell->UpdateRef(MAXCOL, 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<XAccessible > 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() <= static_cast<sal_uInt32>(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)
{
sal_Int32 nCol(getAccessibleColumn(nChildIndex));
sal_Int32 nRow(getAccessibleRow(nChildIndex));
if (IsFormulaMode())
{
if(IsScAddrFormulaSel(
ScAddress(static_cast<SCCOL>(nCol), nRow,mpViewShell->GetViewData().GetTabNo()))
)
{
SelectCell(nRow, nCol, true);
}
return ;
}
if (mpViewShell->GetViewData().GetMarkData().IsCellMarked(static_cast<SCCOL>(nCol), static_cast<SCROW>(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<SCCOL>(nCol), nRow, rViewData.GetTabNo(), SC_REFTYPE_REF );
mpViewShell->UpdateRef(static_cast<SCCOL>(nCol), nRow, rViewData.GetTabNo());
}
return ;
}
mpViewShell->SetTabNo( maRange.aStart.Tab() );
mpViewShell->DoneBlockMode( true ); // continue selecting
mpViewShell->InitBlockMode( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), maRange.aStart.Tab(), bDeselect );
mpViewShell->SelectionChanged();
}
/*
void ScAccessibleSpreadsheet::CreateSortedMarkedCells()
{
mpSortedMarkedCells = new std::vector<ScMyAddress>();
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 OUString("ScAccessibleSpreadsheet");
}
uno::Sequence< OUString> SAL_CALL
ScAccessibleSpreadsheet::getSupportedServiceNames()
{
uno::Sequence< OUString > aSequence = ScAccessibleTableBase::getSupportedServiceNames();
sal_Int32 nOldSize(aSequence.getLength());
aSequence.realloc(nOldSize + 1);
aSequence[nOldSize] = "com.sun.star.AccessibleSpreadsheet";
return aSequence;
}
//===== XTypeProvider =======================================================
uno::Sequence<sal_Int8> SAL_CALL
ScAccessibleSpreadsheet::getImplementationId()
{
return css::uno::Sequence<sal_Int8>();
}
///===== XAccessibleEventBroadcaster =====================================
void SAL_CALL ScAccessibleSpreadsheet::addAccessibleEventListener(const uno::Reference<XAccessibleEventListener>& 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<XAccessibleStateSet>& 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());
aMarkData.MarkToMulti();
if (aMarkData.IsAllMarked(maRange))
bResult = true;
}
return bResult;
}
ScDocument* ScAccessibleSpreadsheet::GetDocument(ScTabViewShell* pViewShell)
{
ScDocument* pDoc = nullptr;
if (pViewShell)
pDoc = pViewShell->GetViewData().GetDocument();
return pDoc;
}
tools::Rectangle ScAccessibleSpreadsheet::GetVisArea(ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
{
tools::Rectangle aVisArea;
if (pViewShell)
{
vcl::Window* pWindow = pViewShell->GetWindowByPos(eSplitPos);
if (pWindow)
{
aVisArea.SetPos(pViewShell->GetViewData().GetPixPos(eSplitPos));
aVisArea.SetSize(pWindow->GetSizePixel());
}
}
return aVisArea;
}
tools::Rectangle ScAccessibleSpreadsheet::GetVisCells(const tools::Rectangle& rVisArea)
{
if (mpViewShell)
{
SCCOL nStartX, nEndX;
SCROW nStartY, nEndY;
mpViewShell->GetViewData().GetPosFromPixel( 1, 1, meSplitPos, nStartX, nStartY);
mpViewShell->GetViewData().GetPosFromPixel( rVisArea.GetWidth(), rVisArea.GetHeight(), meSplitPos, nEndX, nEndY);
return tools::Rectangle(nStartX, nStartY, nEndX, nEndY);
}
else
return tools::Rectangle();
}
sal_Bool SAL_CALL ScAccessibleSpreadsheet::selectRow( sal_Int32 row )
{
SolarMutexGuard g;
if (IsFormulaMode())
{
return false;
}
mpViewShell->SetTabNo( maRange.aStart.Tab() );
mpViewShell->DoneBlockMode( true ); // continue selecting
mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true );
mpViewShell->MarkCursor( 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;
}
mpViewShell->SetTabNo( maRange.aStart.Tab() );
mpViewShell->DoneBlockMode( true ); // continue selecting
mpViewShell->InitBlockMode( static_cast<SCCOL>(column), 0, maRange.aStart.Tab(), false, true );
mpViewShell->MarkCursor( static_cast<SCCOL>(column), MAXROW, maRange.aStart.Tab(), true );
mpViewShell->SelectionChanged();
return true;
}
sal_Bool SAL_CALL ScAccessibleSpreadsheet::unselectRow( sal_Int32 row )
{
SolarMutexGuard g;
if (IsFormulaMode())
{
return false;
}
mpViewShell->SetTabNo( maRange.aStart.Tab() );
mpViewShell->DoneBlockMode( true ); // continue selecting
mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true, true );
mpViewShell->MarkCursor( 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;
}
mpViewShell->SetTabNo( maRange.aStart.Tab() );
mpViewShell->DoneBlockMode( true ); // continue selecting
mpViewShell->InitBlockMode( static_cast<SCCOL>(column), 0, maRange.aStart.Tab(), false, true, false, true );
mpViewShell->MarkCursor( static_cast<SCCOL>(column), 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<XAccessible>(m_pAccFormulaCell.get());
m_pAccFormulaCell = GetAccessibleCellAt(aFormulaAddr.Row(), aFormulaAddr.Col());
uno::Reference< XAccessible > xNew = m_pAccFormulaCell.get();
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
{
VEC_MYADDR 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());
VEC_MYADDR vecNew;
std::set_difference(vecCurSel.begin(),vecCurSel.end(),
m_vecFormulaLastMyAddr.begin(),m_vecFormulaLastMyAddr.end(),
std::back_insert_iterator<VEC_MYADDR>(vecNew));
int nNewSize = vecNew.size();
if ( nNewSize > 10 )
{
aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
aEvent.NewValue.clear();
CommitChange(aEvent);
}
else
{
VEC_MYADDR::iterator viAddr = vecNew.begin();
for(; viAddr != vecNew.end() ; ++viAddr )
{
uno::Reference< XAccessible > xChild;
if (*viAddr == aFormulaAddr)
{
xChild = m_pAccFormulaCell.get();
}
else
{
xChild = getAccessibleCellAt(viAddr->Row(),viAddr->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(*viAddr,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();
for(; miRemove != m_mapFormulaSelectionSend.end() ;)
{
if( !bRemoveAll && IsScAddrFormulaSel(miRemove->first) )
{
++miRemove;
continue;
}
aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
aEvent.NewValue <<= miRemove->second;
CommitChange(aEvent);
MAP_ADDR_XACC::iterator miNext = miRemove;
++miNext;
m_mapFormulaSelectionSend.erase(miRemove);
miRemove = miNext;
}
}
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<SCCOL>((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();
}
if( /* Always true: nRefX >= 0 && */ nRefX <= MAXCOL && nRefY >= 0 && nRefY <= MAXROW)
{
addr = ScAddress(nRefX,nRefY,rViewData.GetTabNo());
return true;
}
return false;
}
uno::Reference < XAccessible > ScAccessibleSpreadsheet::GetActiveCell()
{
if( m_mapSelectionSend.find( maActiveCell ) != m_mapSelectionSend.end() )
return m_mapSelectionSend[maActiveCell];
else
return getAccessibleCellAt(maActiveCell.Row(), maActiveCell .Col());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression 'nX < 0' is always false.
↑ V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'GetWindowExtentsRelative' function.