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