1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 27 28 #include "AccessibleCell.hxx" 29 #include "scitems.hxx" 30 #include <editeng/eeitem.hxx> 31 32 33 #include "AccessibleText.hxx" 34 #include "AccessibleDocument.hxx" 35 #include "tabvwsh.hxx" 36 #include "document.hxx" 37 #include "attrib.hxx" 38 #include "miscuno.hxx" 39 #include "unoguard.hxx" 40 #include "editsrc.hxx" 41 #include "dociter.hxx" 42 #include "cell.hxx" 43 44 #ifndef _UTL_ACCESSIBLESTATESETHELPER_HXX 45 #include <unotools/accessiblestatesethelper.hxx> 46 #endif 47 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEROLE_HPP_ 48 #include <com/sun/star/accessibility/AccessibleRole.hpp> 49 #endif 50 #ifndef _COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLESTATETYPE_HPP_ 51 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 52 #endif 53 #include <com/sun/star/accessibility/AccessibleRelationType.hpp> 54 #include <com/sun/star/accessibility/XAccessibleTable.hpp> 55 #include <rtl/uuid.h> 56 #include <tools/debug.hxx> 57 #include <editeng/brshitem.hxx> 58 #include <comphelper/sequence.hxx> 59 #include <float.h> 60 61 using namespace ::com::sun::star; 62 using namespace ::com::sun::star::accessibility; 63 64 //===== internal ============================================================ 65 66 ScAccessibleCell::ScAccessibleCell( 67 const uno::Reference<XAccessible>& rxParent, 68 ScTabViewShell* pViewShell, 69 ScAddress& rCellAddress, 70 sal_Int32 nIndex, 71 ScSplitPos eSplitPos, 72 ScAccessibleDocument* pAccDoc) 73 : 74 ScAccessibleCellBase(rxParent, GetDocument(pViewShell), rCellAddress, nIndex), 75 ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell, rCellAddress, eSplitPos)), 76 mpViewShell(pViewShell), 77 mpAccDoc(pAccDoc), 78 meSplitPos(eSplitPos) 79 { 80 if (pViewShell) 81 pViewShell->AddAccessibilityObject(*this); 82 } 83 84 ScAccessibleCell::~ScAccessibleCell() 85 { 86 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) 87 { 88 // increment refcount to prevent double call off dtor 89 osl_incrementInterlockedCount( &m_refCount ); 90 // call dispose to inform object wich have a weak reference to this object 91 dispose(); 92 } 93 } 94 95 void ScAccessibleCell::Init() 96 { 97 ScAccessibleCellBase::Init(); 98 99 SetEventSource(this); 100 } 101 102 void SAL_CALL ScAccessibleCell::disposing() 103 { 104 ScUnoGuard aGuard; 105 // #100593# dispose in AccessibleStaticTextBase 106 Dispose(); 107 108 if (mpViewShell) 109 { 110 mpViewShell->RemoveAccessibilityObject(*this); 111 mpViewShell = NULL; 112 } 113 mpAccDoc = NULL; 114 115 ScAccessibleCellBase::disposing(); 116 } 117 118 //===== XInterface ===================================================== 119 120 IMPLEMENT_FORWARD_XINTERFACE2( ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase ) 121 122 //===== XTypeProvider =================================================== 123 124 IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase ) 125 126 //===== XAccessibleComponent ============================================ 127 128 uno::Reference< XAccessible > SAL_CALL ScAccessibleCell::getAccessibleAtPoint( 129 const awt::Point& rPoint ) 130 throw (uno::RuntimeException) 131 { 132 return AccessibleStaticTextBase::getAccessibleAtPoint(rPoint); 133 } 134 135 void SAL_CALL ScAccessibleCell::grabFocus( ) 136 throw (uno::RuntimeException) 137 { 138 ScUnoGuard aGuard; 139 IsObjectValid(); 140 if (getAccessibleParent().is() && mpViewShell) 141 { 142 uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); 143 if (xAccessibleComponent.is()) 144 { 145 xAccessibleComponent->grabFocus(); 146 mpViewShell->SetCursor(maCellAddress.Col(), maCellAddress.Row()); 147 } 148 } 149 } 150 151 Rectangle ScAccessibleCell::GetBoundingBoxOnScreen(void) const 152 throw (uno::RuntimeException) 153 { 154 Rectangle aCellRect(GetBoundingBox()); 155 if (mpViewShell) 156 { 157 Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); 158 if (pWindow) 159 { 160 Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL); 161 aCellRect.setX(aCellRect.getX() + aRect.getX()); 162 aCellRect.setY(aCellRect.getY() + aRect.getY()); 163 } 164 } 165 return aCellRect; 166 } 167 168 Rectangle ScAccessibleCell::GetBoundingBox(void) const 169 throw (uno::RuntimeException) 170 { 171 Rectangle aCellRect; 172 if (mpViewShell) 173 { 174 long nSizeX, nSizeY; 175 mpViewShell->GetViewData()->GetMergeSizePixel( 176 maCellAddress.Col(), maCellAddress.Row(), nSizeX, nSizeY); 177 aCellRect.SetSize(Size(nSizeX, nSizeY)); 178 aCellRect.SetPos(mpViewShell->GetViewData()->GetScrPos(maCellAddress.Col(), maCellAddress.Row(), meSplitPos, sal_True)); 179 180 Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos); 181 if (pWindow) 182 { 183 Rectangle aRect(pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow())); 184 aRect.Move(-aRect.Left(), -aRect.Top()); 185 aCellRect = aRect.Intersection(aCellRect); 186 } 187 188 /* #i19430# Gnopernicus reads text partly if it sticks out of the cell 189 boundaries. This leads to wrong results in cases where the cell 190 text is rotated, because rotation is not taken into account when 191 calculating the visible part of the text. In these cases we will 192 simply expand the cell size to the width of the unrotated text. */ 193 if (mpDoc) 194 { 195 const SfxInt32Item* pItem = static_cast< const SfxInt32Item* >( 196 mpDoc->GetAttr( maCellAddress.Col(), maCellAddress.Row(), maCellAddress.Tab(), ATTR_ROTATE_VALUE ) ); 197 if( pItem && (pItem->GetValue() != 0) ) 198 { 199 Rectangle aParaRect = GetParagraphBoundingBox(); 200 if( !aParaRect.IsEmpty() && (aCellRect.GetWidth() < aParaRect.GetWidth()) ) 201 aCellRect.SetSize( Size( aParaRect.GetWidth(), aCellRect.GetHeight() ) ); 202 } 203 } 204 } 205 if (aCellRect.IsEmpty()) 206 aCellRect.SetPos(Point(-1, -1)); 207 return aCellRect; 208 } 209 210 //===== XAccessibleContext ============================================== 211 212 sal_Int32 SAL_CALL 213 ScAccessibleCell::getAccessibleChildCount(void) 214 throw (uno::RuntimeException) 215 { 216 return AccessibleStaticTextBase::getAccessibleChildCount(); 217 } 218 219 uno::Reference< XAccessible > SAL_CALL 220 ScAccessibleCell::getAccessibleChild(sal_Int32 nIndex) 221 throw (uno::RuntimeException, 222 lang::IndexOutOfBoundsException) 223 { 224 return AccessibleStaticTextBase::getAccessibleChild(nIndex); 225 } 226 227 uno::Reference<XAccessibleStateSet> SAL_CALL 228 ScAccessibleCell::getAccessibleStateSet(void) 229 throw (uno::RuntimeException) 230 { 231 ScUnoGuard aGuard; 232 uno::Reference<XAccessibleStateSet> xParentStates; 233 if (getAccessibleParent().is()) 234 { 235 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); 236 xParentStates = xParentContext->getAccessibleStateSet(); 237 } 238 utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); 239 if (IsDefunc(xParentStates)) 240 pStateSet->AddState(AccessibleStateType::DEFUNC); 241 else 242 { 243 if (IsEditable(xParentStates)) 244 { 245 pStateSet->AddState(AccessibleStateType::EDITABLE); 246 pStateSet->AddState(AccessibleStateType::RESIZABLE); 247 } 248 pStateSet->AddState(AccessibleStateType::ENABLED); 249 pStateSet->AddState(AccessibleStateType::MULTI_LINE); 250 pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE); 251 if (IsOpaque(xParentStates)) 252 pStateSet->AddState(AccessibleStateType::OPAQUE); 253 pStateSet->AddState(AccessibleStateType::SELECTABLE); 254 if (IsSelected()) 255 pStateSet->AddState(AccessibleStateType::SELECTED); 256 if (isShowing()) 257 pStateSet->AddState(AccessibleStateType::SHOWING); 258 pStateSet->AddState(AccessibleStateType::TRANSIENT); 259 if (isVisible()) 260 pStateSet->AddState(AccessibleStateType::VISIBLE); 261 } 262 return pStateSet; 263 } 264 265 uno::Reference<XAccessibleRelationSet> SAL_CALL 266 ScAccessibleCell::getAccessibleRelationSet(void) 267 throw (uno::RuntimeException) 268 { 269 ScUnoGuard aGuard; 270 IsObjectValid(); 271 utl::AccessibleRelationSetHelper* pRelationSet = NULL; 272 if (mpAccDoc) 273 pRelationSet = mpAccDoc->GetRelationSet(&maCellAddress); 274 if (!pRelationSet) 275 pRelationSet = new utl::AccessibleRelationSetHelper(); 276 FillDependends(pRelationSet); 277 FillPrecedents(pRelationSet); 278 return pRelationSet; 279 } 280 281 //===== XServiceInfo ==================================================== 282 283 ::rtl::OUString SAL_CALL ScAccessibleCell::getImplementationName(void) 284 throw (uno::RuntimeException) 285 { 286 return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("ScAccessibleCell")); 287 } 288 289 uno::Sequence< ::rtl::OUString> SAL_CALL 290 ScAccessibleCell::getSupportedServiceNames(void) 291 throw (uno::RuntimeException) 292 { 293 uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); 294 sal_Int32 nOldSize(aSequence.getLength()); 295 aSequence.realloc(nOldSize + 1); 296 ::rtl::OUString* pNames = aSequence.getArray(); 297 298 pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.AccessibleCell")); 299 300 return aSequence; 301 } 302 303 //==== internal ========================================================= 304 305 sal_Bool ScAccessibleCell::IsDefunc( 306 const uno::Reference<XAccessibleStateSet>& rxParentStates) 307 { 308 return ScAccessibleContextBase::IsDefunc() || (mpDoc == NULL) || (mpViewShell == NULL) || !getAccessibleParent().is() || 309 (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); 310 } 311 312 sal_Bool ScAccessibleCell::IsEditable( 313 const uno::Reference<XAccessibleStateSet>& rxParentStates) 314 { 315 sal_Bool bEditable(sal_True); 316 if (rxParentStates.is() && !rxParentStates->contains(AccessibleStateType::EDITABLE) && 317 mpDoc) 318 { 319 // here I have to test whether the protection of the table should influence this cell. 320 const ScProtectionAttr* pItem = (const ScProtectionAttr*)mpDoc->GetAttr( 321 maCellAddress.Col(), maCellAddress.Row(), 322 maCellAddress.Tab(), ATTR_PROTECTION); 323 if (pItem) 324 bEditable = !pItem->GetProtection(); 325 } 326 return bEditable; 327 } 328 329 sal_Bool ScAccessibleCell::IsOpaque( 330 const uno::Reference<XAccessibleStateSet>& /* rxParentStates */) 331 { 332 // test whether there is a background color 333 sal_Bool bOpaque(sal_True); 334 if (mpDoc) 335 { 336 const SvxBrushItem* pItem = (const SvxBrushItem*)mpDoc->GetAttr( 337 maCellAddress.Col(), maCellAddress.Row(), 338 maCellAddress.Tab(), ATTR_BACKGROUND); 339 if (pItem) 340 bOpaque = pItem->GetColor() != COL_TRANSPARENT; 341 } 342 return bOpaque; 343 } 344 345 sal_Bool ScAccessibleCell::IsSelected() 346 { 347 sal_Bool bResult(sal_False); 348 if (mpViewShell && mpViewShell->GetViewData()) 349 { 350 const ScMarkData& rMarkdata = mpViewShell->GetViewData()->GetMarkData(); 351 bResult = rMarkdata.IsCellMarked(maCellAddress.Col(), maCellAddress.Row()); 352 } 353 return bResult; 354 } 355 356 ScDocument* ScAccessibleCell::GetDocument(ScTabViewShell* pViewShell) 357 { 358 ScDocument* pDoc = NULL; 359 if (pViewShell && pViewShell->GetViewData()) 360 pDoc = pViewShell->GetViewData()->GetDocument(); 361 return pDoc; 362 } 363 364 ::std::auto_ptr< SvxEditSource > ScAccessibleCell::CreateEditSource(ScTabViewShell* pViewShell, ScAddress aCell, ScSplitPos eSplitPos) 365 { 366 ::std::auto_ptr < ScAccessibleTextData > pAccessibleCellTextData 367 ( new ScAccessibleCellTextData( pViewShell, aCell, eSplitPos, this ) ); 368 ::std::auto_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(pAccessibleCellTextData)); 369 370 return pEditSource; 371 } 372 373 void ScAccessibleCell::FillDependends(utl::AccessibleRelationSetHelper* pRelationSet) 374 { 375 if (mpDoc) 376 { 377 ScCellIterator aCellIter( mpDoc, 0,0, maCellAddress.Tab(), MAXCOL,MAXROW, maCellAddress.Tab() ); 378 ScBaseCell* pCell = aCellIter.GetFirst(); 379 while (pCell) 380 { 381 if (pCell->GetCellType() == CELLTYPE_FORMULA) 382 { 383 sal_Bool bFound(sal_False); 384 ScDetectiveRefIter aIter( (ScFormulaCell*) pCell ); 385 ScRange aRef; 386 while ( !bFound && aIter.GetNextRef( aRef ) ) 387 { 388 if (aRef.In(maCellAddress)) 389 bFound = sal_True; 390 } 391 if (bFound) 392 AddRelation(ScAddress(aCellIter.GetCol(), aCellIter.GetRow(), aCellIter.GetTab()), AccessibleRelationType::CONTROLLER_FOR, pRelationSet); 393 } 394 pCell = aCellIter.GetNext(); 395 } 396 } 397 } 398 399 void ScAccessibleCell::FillPrecedents(utl::AccessibleRelationSetHelper* pRelationSet) 400 { 401 if (mpDoc) 402 { 403 ScBaseCell* pBaseCell = mpDoc->GetCell(maCellAddress); 404 if (pBaseCell && (pBaseCell->GetCellType() == CELLTYPE_FORMULA)) 405 { 406 ScFormulaCell* pFCell = (ScFormulaCell*) pBaseCell; 407 408 ScDetectiveRefIter aIter( pFCell ); 409 ScRange aRef; 410 while ( aIter.GetNextRef( aRef ) ) 411 { 412 AddRelation( aRef, AccessibleRelationType::CONTROLLED_BY, pRelationSet); 413 } 414 } 415 } 416 } 417 418 void ScAccessibleCell::AddRelation(const ScAddress& rCell, 419 const sal_uInt16 aRelationType, 420 utl::AccessibleRelationSetHelper* pRelationSet) 421 { 422 AddRelation(ScRange(rCell, rCell), aRelationType, pRelationSet); 423 } 424 425 void ScAccessibleCell::AddRelation(const ScRange& rRange, 426 const sal_uInt16 aRelationType, 427 utl::AccessibleRelationSetHelper* pRelationSet) 428 { 429 uno::Reference < XAccessibleTable > xTable ( getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY ); 430 if (xTable.is()) 431 { 432 sal_uInt32 nCount(static_cast<sal_uInt32>(rRange.aEnd.Col() - 433 rRange.aStart.Col() + 1) * (rRange.aEnd.Row() - 434 rRange.aStart.Row() + 1)); 435 uno::Sequence < uno::Reference < uno::XInterface > > aTargetSet( nCount ); 436 uno::Reference < uno::XInterface >* pTargetSet = aTargetSet.getArray(); 437 if (pTargetSet) 438 { 439 sal_uInt32 nPos(0); 440 for (sal_uInt32 nRow = rRange.aStart.Row(); nRow <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Row()); ++nRow) 441 { 442 for (sal_uInt32 nCol = rRange.aStart.Col(); nCol <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Col()); ++nCol) 443 { 444 pTargetSet[nPos] = xTable->getAccessibleCellAt(nRow, nCol); 445 ++nPos; 446 } 447 } 448 DBG_ASSERT(nCount == nPos, "something wents wrong"); 449 } 450 AccessibleRelation aRelation; 451 aRelation.RelationType = aRelationType; 452 aRelation.TargetSet = aTargetSet; 453 pRelationSet->AddRelation(aRelation); 454 } 455 } 456