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 #include "AccessiblePageHeader.hxx" 28 #include "AccessiblePageHeaderArea.hxx" 29 #include "AccessibilityHints.hxx" 30 #include "prevwsh.hxx" 31 #include "unoguard.hxx" 32 #include "miscuno.hxx" 33 #include "prevloc.hxx" 34 #include "document.hxx" 35 #include "stlpool.hxx" 36 #include "scitems.hxx" 37 #include "attrib.hxx" 38 #include "scresid.hxx" 39 #ifndef SC_SC_HRC 40 #include "sc.hrc" 41 #endif 42 43 #include <com/sun/star/accessibility/AccessibleRole.hpp> 44 #include <com/sun/star/accessibility/AccessibleStateType.hpp> 45 #include <com/sun/star/accessibility/AccessibleEventId.hpp> 46 47 #include <vcl/window.hxx> 48 #include <svl/smplhint.hxx> 49 #include <unotools/accessiblestatesethelper.hxx> 50 #include <svl/style.hxx> 51 #include <svl/itempool.hxx> 52 #include <editeng/editobj.hxx> 53 #include <toolkit/helper/convert.hxx> 54 55 #include <algorithm> 56 57 using namespace ::com::sun::star; 58 using namespace ::com::sun::star::accessibility; 59 60 const sal_uInt8 MAX_AREAS = 3; 61 62 //===== internal ============================================================ 63 struct Acquire 64 { 65 void operator() (ScAccessiblePageHeaderArea* pArea) 66 { 67 if (pArea) 68 pArea->acquire(); 69 } 70 }; 71 72 struct Release 73 { 74 void operator() (ScAccessiblePageHeaderArea*& pArea) 75 { 76 if (pArea) 77 pArea->release(); 78 } 79 }; 80 81 struct Dispose 82 { 83 void operator() (ScAccessiblePageHeaderArea*& pArea) 84 { 85 if (pArea) 86 { 87 pArea->dispose(); 88 pArea->release(); 89 } 90 pArea = NULL; 91 } 92 }; 93 94 ScAccessiblePageHeader::ScAccessiblePageHeader( const ::com::sun::star::uno::Reference< 95 ::com::sun::star::accessibility::XAccessible>& rxParent, 96 ScPreviewShell* pViewShell, sal_Bool bHeader, sal_Int32 nIndex ) : 97 ScAccessibleContextBase( rxParent, bHeader ? AccessibleRole::HEADER : AccessibleRole::FOOTER ), 98 mpViewShell( pViewShell ), 99 mnIndex( nIndex ), 100 mbHeader( bHeader ), 101 maAreas(MAX_AREAS, NULL), 102 mnChildCount(-1) 103 { 104 if (mpViewShell) 105 mpViewShell->AddAccessibilityObject(*this); 106 } 107 108 ScAccessiblePageHeader::~ScAccessiblePageHeader() 109 { 110 if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose) 111 { 112 // increment refcount to prevent double call off dtor 113 osl_incrementInterlockedCount( &m_refCount ); 114 dispose(); 115 } 116 } 117 118 void SAL_CALL ScAccessiblePageHeader::disposing() 119 { 120 ScUnoGuard aGuard; 121 if (mpViewShell) 122 { 123 mpViewShell->RemoveAccessibilityObject(*this); 124 mpViewShell = NULL; 125 } 126 std::for_each(maAreas.begin(), maAreas.end(), Dispose()); 127 128 ScAccessibleContextBase::disposing(); 129 } 130 131 //===== SfxListener ===================================================== 132 133 void ScAccessiblePageHeader::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) 134 { 135 if (rHint.ISA( SfxSimpleHint ) ) 136 { 137 const SfxSimpleHint& rRef = (const SfxSimpleHint&)rHint; 138 // only notify if child exist, otherwise it is not necessary 139 if ((rRef.GetId() == SC_HINT_DATACHANGED)) 140 { 141 ScHFAreas aOldAreas(maAreas); 142 std::for_each(aOldAreas.begin(), aOldAreas.end(), Acquire()); 143 mnChildCount = -1; 144 getAccessibleChildCount(); 145 for (sal_uInt8 i = 0; i < MAX_AREAS; ++i) 146 { 147 if ((aOldAreas[i] && maAreas[i] && !ScGlobal::EETextObjEqual(aOldAreas[i]->GetEditTextObject(), maAreas[i]->GetEditTextObject())) || 148 (aOldAreas[i] && !maAreas[i]) || (!aOldAreas[i] && maAreas[i])) 149 { 150 if (aOldAreas[i] && aOldAreas[i]->GetEditTextObject()) 151 { 152 AccessibleEventObject aEvent; 153 aEvent.EventId = AccessibleEventId::CHILD; 154 aEvent.Source = uno::Reference< XAccessibleContext >(this); 155 aEvent.OldValue = uno::makeAny(uno::Reference<XAccessible>(aOldAreas[i])); 156 157 CommitChange(aEvent); // child gone - event 158 aOldAreas[i]->dispose(); 159 } 160 if (maAreas[i] && maAreas[i]->GetEditTextObject()) 161 { 162 AccessibleEventObject aEvent; 163 aEvent.EventId = AccessibleEventId::CHILD; 164 aEvent.Source = uno::Reference< XAccessibleContext >(this); 165 aEvent.NewValue = uno::makeAny(uno::Reference<XAccessible>(maAreas[i])); 166 167 CommitChange(aEvent); // new child - event 168 } 169 } 170 } 171 std::for_each(aOldAreas.begin(), aOldAreas.end(), Release()); 172 } 173 else if (rRef.GetId() == SC_HINT_ACC_VISAREACHANGED) 174 { 175 AccessibleEventObject aEvent; 176 aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED; 177 aEvent.Source = uno::Reference< XAccessibleContext >(this); 178 CommitChange(aEvent); 179 } 180 } 181 182 ScAccessibleContextBase::Notify(rBC, rHint); 183 } 184 185 //===== XAccessibleComponent ============================================ 186 187 uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleAtPoint( const awt::Point& aPoint ) 188 throw (uno::RuntimeException) 189 { 190 uno::Reference<XAccessible> xRet; 191 192 if (containsPoint(aPoint)) 193 { 194 ScUnoGuard aGuard; 195 IsObjectValid(); 196 197 sal_Int32 nCount(getAccessibleChildCount()); // fill the areas 198 199 if (nCount) 200 { 201 // return the first with content, because they have all the same Bounding Box 202 sal_uInt8 i(0); 203 while(!xRet.is() && i < MAX_AREAS) 204 { 205 if (maAreas[i]) 206 xRet = maAreas[i]; 207 else 208 ++i; 209 } 210 } 211 } 212 213 return xRet; 214 } 215 216 void SAL_CALL ScAccessiblePageHeader::grabFocus() throw (uno::RuntimeException) 217 { 218 ScUnoGuard aGuard; 219 IsObjectValid(); 220 if (getAccessibleParent().is()) 221 { 222 uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY); 223 if (xAccessibleComponent.is()) 224 xAccessibleComponent->grabFocus(); 225 } 226 } 227 228 //===== XAccessibleContext ============================================== 229 230 sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleChildCount() throw (uno::RuntimeException) 231 { 232 ScUnoGuard aGuard; 233 IsObjectValid(); 234 235 if((mnChildCount < 0) && mpViewShell) 236 { 237 mnChildCount = 0; 238 ScDocument* pDoc = mpViewShell->GetDocument(); 239 if (pDoc) 240 { 241 // find out how many regions (left,center, right) are with content 242 243 SfxStyleSheetBase* pStyle = pDoc->GetStyleSheetPool()->Find(pDoc->GetPageStyle(mpViewShell->GetLocationData().GetPrintTab()), SFX_STYLE_FAMILY_PAGE); 244 if (pStyle) 245 { 246 sal_uInt16 nPageWhichId(0); 247 if (mbHeader) 248 nPageWhichId = mpViewShell->GetLocationData().IsHeaderLeft() ? ATTR_PAGE_HEADERLEFT : ATTR_PAGE_HEADERRIGHT; 249 else 250 nPageWhichId = mpViewShell->GetLocationData().IsFooterLeft() ? ATTR_PAGE_FOOTERLEFT : ATTR_PAGE_FOOTERRIGHT; 251 252 const ScPageHFItem& rPageItem = static_cast<const ScPageHFItem&>(pStyle->GetItemSet().Get(nPageWhichId)); 253 AddChild(rPageItem.GetLeftArea(), 0, SVX_ADJUST_LEFT); 254 AddChild(rPageItem.GetCenterArea(), 1, SVX_ADJUST_CENTER); 255 AddChild(rPageItem.GetRightArea(), 2, SVX_ADJUST_RIGHT); 256 } 257 } 258 } 259 260 return mnChildCount; 261 } 262 263 uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleChild( sal_Int32 nIndex ) 264 throw (lang::IndexOutOfBoundsException, uno::RuntimeException) 265 { 266 ScUnoGuard aGuard; 267 IsObjectValid(); 268 269 uno::Reference<XAccessible> xRet; 270 271 if(mnChildCount < 0) 272 getAccessibleChildCount(); 273 274 ScHFAreas::iterator aItr = maAreas.begin(); 275 ScHFAreas::iterator aEndItr = maAreas.end(); 276 while (!xRet.is() && (nIndex >= 0) && (aItr != aEndItr)) 277 { 278 if (*aItr) 279 { 280 if (nIndex == 0) 281 xRet = *aItr; 282 else 283 --nIndex; 284 } 285 else 286 ++aItr; 287 } 288 289 if ( !xRet.is() ) 290 throw lang::IndexOutOfBoundsException(); 291 292 return xRet; 293 } 294 295 sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleIndexInParent() throw (uno::RuntimeException) 296 { 297 return mnIndex; 298 } 299 300 uno::Reference< XAccessibleStateSet > SAL_CALL ScAccessiblePageHeader::getAccessibleStateSet() 301 throw (uno::RuntimeException) 302 { 303 ScUnoGuard aGuard; 304 uno::Reference<XAccessibleStateSet> xParentStates; 305 if (getAccessibleParent().is()) 306 { 307 uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext(); 308 xParentStates = xParentContext->getAccessibleStateSet(); 309 } 310 utl::AccessibleStateSetHelper* pStateSet = new utl::AccessibleStateSetHelper(); 311 if (IsDefunc(xParentStates)) 312 pStateSet->AddState(AccessibleStateType::DEFUNC); 313 else 314 { 315 pStateSet->AddState(AccessibleStateType::ENABLED); 316 pStateSet->AddState(AccessibleStateType::OPAQUE); 317 if (isShowing()) 318 pStateSet->AddState(AccessibleStateType::SHOWING); 319 if (isVisible()) 320 pStateSet->AddState(AccessibleStateType::VISIBLE); 321 } 322 return pStateSet; 323 } 324 325 //===== XServiceInfo ==================================================== 326 327 rtl::OUString SAL_CALL ScAccessiblePageHeader::getImplementationName() throw(uno::RuntimeException) 328 { 329 return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScAccessiblePageHeader")); 330 } 331 332 uno::Sequence<rtl::OUString> SAL_CALL ScAccessiblePageHeader::getSupportedServiceNames() 333 throw(uno::RuntimeException) 334 { 335 uno::Sequence< ::rtl::OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames(); 336 sal_Int32 nOldSize(aSequence.getLength()); 337 aSequence.realloc(nOldSize + 1); 338 ::rtl::OUString* pNames = aSequence.getArray(); 339 340 pNames[nOldSize] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.AccessibleHeaderFooterView")); 341 342 return aSequence; 343 } 344 345 //==== internal ========================================================= 346 347 ::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleDescription(void) 348 throw (uno::RuntimeException) 349 { 350 String sDesc(ScResId(mbHeader ? STR_ACC_HEADER_DESCR : STR_ACC_FOOTER_DESCR)); 351 sDesc.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN))); 352 return rtl::OUString( sDesc ); 353 } 354 355 ::rtl::OUString SAL_CALL ScAccessiblePageHeader::createAccessibleName(void) 356 throw (uno::RuntimeException) 357 { 358 String sName(ScResId(mbHeader ? STR_ACC_HEADER_NAME : STR_ACC_FOOTER_NAME)); 359 sName.SearchAndReplaceAscii("%1", String(ScResId(SCSTR_UNKNOWN))); 360 return rtl::OUString( sName ); 361 } 362 363 Rectangle ScAccessiblePageHeader::GetBoundingBoxOnScreen() const throw (uno::RuntimeException) 364 { 365 Rectangle aCellRect(GetBoundingBox()); 366 if (mpViewShell) 367 { 368 Window* pWindow = mpViewShell->GetWindow(); 369 if (pWindow) 370 { 371 Rectangle aRect = pWindow->GetWindowExtentsRelative(NULL); 372 aCellRect.setX(aCellRect.getX() + aRect.getX()); 373 aCellRect.setY(aCellRect.getY() + aRect.getY()); 374 } 375 } 376 return aCellRect; 377 } 378 379 Rectangle ScAccessiblePageHeader::GetBoundingBox() const throw (uno::RuntimeException) 380 { 381 Rectangle aRect; 382 if (mpViewShell) 383 { 384 const ScPreviewLocationData& rData = mpViewShell->GetLocationData(); 385 if ( mbHeader ) 386 rData.GetHeaderPosition( aRect ); 387 else 388 rData.GetFooterPosition( aRect ); 389 390 // the Rectangle could contain negative coordinates so it should be cliped 391 Rectangle aClipRect(Point(0, 0), aRect.GetSize()); 392 Window* pWindow = mpViewShell->GetWindow(); 393 if (pWindow) 394 aClipRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow()); 395 aRect = aClipRect.GetIntersection(aRect); 396 } 397 if (aRect.IsEmpty()) 398 aRect.SetSize(Size(-1, -1)); 399 400 return aRect; 401 } 402 403 sal_Bool ScAccessiblePageHeader::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates ) 404 { 405 return ScAccessibleContextBase::IsDefunc() || (mpViewShell == NULL) || !getAccessibleParent().is() || 406 (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC)); 407 } 408 409 void ScAccessiblePageHeader::AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust) 410 { 411 if (pArea && (pArea->GetText(0).Len() || (pArea->GetParagraphCount() > 1))) 412 { 413 if (maAreas[nIndex]) 414 { 415 if (!ScGlobal::EETextObjEqual(maAreas[nIndex]->GetEditTextObject(), pArea)) 416 { 417 maAreas[nIndex]->release(); 418 maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust); 419 maAreas[nIndex]->acquire(); 420 } 421 } 422 else 423 { 424 maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, mbHeader, eAdjust); 425 maAreas[nIndex]->acquire(); 426 } 427 ++mnChildCount; 428 } 429 else 430 { 431 if (maAreas[nIndex]) 432 { 433 maAreas[nIndex]->release(); 434 maAreas[nIndex] = NULL; 435 } 436 } 437 } 438