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 #include "precompiled_sd.hxx"
25 
26 #include "AccessibleSlideSorterView.hxx"
27 #include "AccessibleSlideSorterObject.hxx"
28 
29 #include "SlideSorter.hxx"
30 #include "controller/SlideSorterController.hxx"
31 #include "controller/SlsPageSelector.hxx"
32 #include "controller/SlsFocusManager.hxx"
33 #include "controller/SlsSelectionManager.hxx"
34 #include "view/SlideSorterView.hxx"
35 #include "model/SlideSorterModel.hxx"
36 #include "model/SlsPageDescriptor.hxx"
37 #include "SlideSorterViewShell.hxx"
38 
39 #include "ViewShellHint.hxx"
40 #include "sdpage.hxx"
41 #include "drawdoc.hxx"
42 
43 #include "sdresid.hxx"
44 #include "accessibility.hrc"
45 #include <com/sun/star/accessibility/AccessibleRole.hpp>
46 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
47 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
48 #include <comphelper/accessibleeventnotifier.hxx>
49 #include <unotools/accessiblestatesethelper.hxx>
50 #include <rtl/ref.hxx>
51 #include <vcl/svapp.hxx>
52 
53 using ::rtl::OUString;
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::uno;
56 using namespace ::com::sun::star::accessibility;
57 
58 namespace accessibility {
59 
60 
61 /** Inner implementation class of the AccessibleSlideSorterView.
62 
63     Note that some event broadcasting is done asynchronously because
64     otherwise it could lead to deadlocks on (at least) some Solaris
65     machines.  Probably (but unverified) this can happen on all GTK based
66     systems.  The asynchronous broadcasting is just a workaround for a
67     poorly understood problem.
68 */
69 class AccessibleSlideSorterView::Implementation
70     : public SfxListener
71 {
72 public:
73     Implementation (
74         AccessibleSlideSorterView& rAccessibleSlideSorter,
75         ::sd::slidesorter::SlideSorter& rSlideSorter,
76         ::Window* pWindow);
77     ~Implementation (void);
78 
79     void RequestUpdateChildren (void);
80     void Clear (void);
81     sal_Int32 GetVisibleChildCount (void) const;
82     AccessibleSlideSorterObject* GetAccessibleChild (sal_Int32 nIndex);
83     AccessibleSlideSorterObject* GetVisibleChild (sal_Int32 nIndex);
84 
85     void ConnectListeners (void);
86     void ReleaseListeners (void);
87     void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint);
88     DECL_LINK(WindowEventListener, VclWindowEvent*);
89     DECL_LINK(SelectionChangeListener, void*);
90     DECL_LINK(BroadcastSelectionChange, void*);
91     DECL_LINK(FocusChangeListener, void*);
92     DECL_LINK(UpdateChildrenCallback, void*);
93 
94 private:
95     AccessibleSlideSorterView& mrAccessibleSlideSorter;
96     ::sd::slidesorter::SlideSorter& mrSlideSorter;
97     typedef ::std::vector<rtl::Reference<AccessibleSlideSorterObject> > PageObjectList;
98     PageObjectList maPageObjects;
99     sal_Int32 mnFirstVisibleChild;
100     sal_Int32 mnLastVisibleChild;
101     bool mbListeningToDocument;
102     ::Window* mpWindow;
103     sal_Int32 mnFocusedIndex;
104     bool mbModelChangeLocked;
105     sal_uLong mnUpdateChildrenUserEventId;
106     sal_uLong mnSelectionChangeUserEventId;
107 
108     void UpdateChildren (void);
109 };
110 
111 
112 
113 
114 //===== AccessibleSlideSorterView =============================================
115 
116 AccessibleSlideSorterView::AccessibleSlideSorterView(
117     ::sd::slidesorter::SlideSorter& rSlideSorter,
118     const Reference<XAccessible>& rxParent,
119     ::Window* pContentWindow)
120     : AccessibleSlideSorterViewBase(MutexOwner::maMutex),
121       mpImpl(new Implementation(*this,rSlideSorter,pContentWindow)),
122       mrSlideSorter(rSlideSorter),
123       mxParent(rxParent),
124       mnClientId(0),
125       mpContentWindow(pContentWindow)
126 {
127 }
128 
129 
130 
131 
132 AccessibleSlideSorterView::~AccessibleSlideSorterView (void)
133 {
134     Destroyed ();
135 }
136 
137 
138 
139 
140 void AccessibleSlideSorterView::FireAccessibleEvent (
141     short nEventId,
142     const uno::Any& rOldValue,
143     const uno::Any& rNewValue )
144 {
145     if (mnClientId != 0)
146     {
147         AccessibleEventObject aEventObject;
148 
149         aEventObject.Source = Reference<XWeak>(this);
150         aEventObject.EventId = nEventId;
151         aEventObject.NewValue = rNewValue;
152 	    aEventObject.OldValue = rOldValue;
153 
154 		comphelper::AccessibleEventNotifier::addEvent (mnClientId, aEventObject);
155     }
156 }
157 
158 
159 
160 
161 void SAL_CALL AccessibleSlideSorterView::disposing (void)
162 {
163     if (mnClientId != 0)
164     {
165         comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
166         mnClientId = 0;
167     }
168     mpImpl.reset(NULL);
169 }
170 
171 
172 
173 
174 AccessibleSlideSorterObject* AccessibleSlideSorterView::GetAccessibleChildImplementation (
175     sal_Int32 nIndex)
176 {
177     AccessibleSlideSorterObject* pResult = NULL;
178     ::osl::MutexGuard aGuard (maMutex);
179 
180     if (nIndex>=0 && nIndex<mpImpl->GetVisibleChildCount())
181         pResult = mpImpl->GetVisibleChild(nIndex);
182 
183     return pResult;
184 }
185 
186 void AccessibleSlideSorterView::Destroyed (void)
187 {
188     ::osl::MutexGuard aGuard (maMutex);
189 
190     // Send a disposing to all listeners.
191 	if (mnClientId != 0)
192 	{
193         comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
194 		mnClientId = 0;
195 	}
196 }
197 
198 //=====  XAccessible  =========================================================
199 
200 Reference<XAccessibleContext > SAL_CALL
201     AccessibleSlideSorterView::getAccessibleContext (void)
202     throw (uno::RuntimeException)
203 {
204     ThrowIfDisposed ();
205     return this;
206 }
207 
208 //=====  XAccessibleContext  ==================================================
209 
210 sal_Int32 SAL_CALL AccessibleSlideSorterView::getAccessibleChildCount (void)
211     throw (RuntimeException)
212 {
213     ThrowIfDisposed();
214     ::osl::MutexGuard aGuard (maMutex);
215     return mpImpl->GetVisibleChildCount();
216 }
217 
218 Reference<XAccessible > SAL_CALL
219     AccessibleSlideSorterView::getAccessibleChild (sal_Int32 nIndex)
220     throw (lang::IndexOutOfBoundsException, RuntimeException)
221 {
222     ThrowIfDisposed();
223     ::osl::MutexGuard aGuard (maMutex);
224 
225     if (nIndex<0 || nIndex>=mpImpl->GetVisibleChildCount())
226         throw lang::IndexOutOfBoundsException();
227 
228     return  mpImpl->GetVisibleChild(nIndex);
229 }
230 
231 Reference<XAccessible > SAL_CALL AccessibleSlideSorterView::getAccessibleParent (void)
232     throw (uno::RuntimeException)
233 {
234     ThrowIfDisposed();
235     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
236     Reference<XAccessible> xParent;
237 
238     if (mpContentWindow != NULL)
239     {
240         ::Window* pParent = mpContentWindow->GetAccessibleParentWindow();
241         if (pParent != NULL)
242             xParent = pParent->GetAccessible();
243     }
244 
245     return xParent;
246 }
247 
248 sal_Int32 SAL_CALL AccessibleSlideSorterView::getAccessibleIndexInParent (void)
249     throw (uno::RuntimeException)
250 {
251     OSL_ASSERT(getAccessibleParent().is());
252     ThrowIfDisposed();
253     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
254     sal_Int32 nIndexInParent(-1);
255 
256 
257     Reference<XAccessibleContext> xParentContext (getAccessibleParent()->getAccessibleContext());
258     if (xParentContext.is())
259     {
260         sal_Int32 nChildCount (xParentContext->getAccessibleChildCount());
261         for (sal_Int32 i=0; i<nChildCount; ++i)
262             if (xParentContext->getAccessibleChild(i).get()
263                     == static_cast<XAccessible*>(this))
264             {
265                 nIndexInParent = i;
266                 break;
267             }
268     }
269 
270     return nIndexInParent;
271 }
272 
273 
274 
275 
276 sal_Int16 SAL_CALL AccessibleSlideSorterView::getAccessibleRole (void)
277     throw (uno::RuntimeException)
278 {
279     ThrowIfDisposed();
280     static sal_Int16 nRole = AccessibleRole::DOCUMENT;
281     return nRole;
282 }
283 
284 
285 
286 
287 ::rtl::OUString SAL_CALL AccessibleSlideSorterView::getAccessibleDescription (void)
288     throw (uno::RuntimeException)
289 {
290     ThrowIfDisposed();
291     ::vos::OGuard aGuard (Application::GetSolarMutex());
292 
293     return String(SdResId(SID_SD_A11Y_I_SLIDEVIEW_D));
294 }
295 
296 
297 
298 
299 ::rtl::OUString SAL_CALL AccessibleSlideSorterView::getAccessibleName (void)
300     throw (uno::RuntimeException)
301 {
302     ThrowIfDisposed();
303     ::vos::OGuard aGuard (Application::GetSolarMutex());
304 
305     return String(SdResId(SID_SD_A11Y_I_SLIDEVIEW_N));
306 }
307 
308 
309 
310 
311 Reference<XAccessibleRelationSet> SAL_CALL
312     AccessibleSlideSorterView::getAccessibleRelationSet (void)
313     throw (uno::RuntimeException)
314 {
315     return Reference<XAccessibleRelationSet>();
316 }
317 
318 
319 
320 
321 Reference<XAccessibleStateSet > SAL_CALL
322     AccessibleSlideSorterView::getAccessibleStateSet (void)
323     throw (uno::RuntimeException)
324 {
325     ThrowIfDisposed();
326     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
327     ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper();
328 
329     pStateSet->AddState(AccessibleStateType::FOCUSABLE);
330     pStateSet->AddState(AccessibleStateType::SELECTABLE);
331     pStateSet->AddState(AccessibleStateType::ENABLED);
332     pStateSet->AddState(AccessibleStateType::ACTIVE);
333     pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
334     pStateSet->AddState(AccessibleStateType::OPAQUE);
335     if (mpContentWindow!=NULL)
336     {
337         if (mpContentWindow->IsVisible())
338             pStateSet->AddState(AccessibleStateType::VISIBLE);
339         if (mpContentWindow->IsReallyVisible())
340             pStateSet->AddState(AccessibleStateType::SHOWING);
341     }
342 
343     return pStateSet;
344 }
345 
346 
347 
348 
349 lang::Locale SAL_CALL AccessibleSlideSorterView::getLocale (void)
350     throw (IllegalAccessibleComponentStateException,
351         RuntimeException)
352 {
353     ThrowIfDisposed ();
354     Reference<XAccessibleContext> xParentContext;
355     Reference<XAccessible> xParent (getAccessibleParent());
356     if (xParent.is())
357         xParentContext = xParent->getAccessibleContext();
358 
359     if (xParentContext.is())
360         return xParentContext->getLocale();
361     else
362         // Strange, no parent!  Anyway, return the default locale.
363         return Application::GetSettings().GetLocale();
364 }
365 
366 
367 
368 
369 void SAL_CALL AccessibleSlideSorterView::addEventListener(
370     const Reference<XAccessibleEventListener >& rxListener)
371     throw (RuntimeException)
372 {
373 	if (rxListener.is())
374     {
375         const osl::MutexGuard aGuard(maMutex);
376 
377         if (IsDisposed())
378         {
379             uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY);
380 		    rxListener->disposing (lang::EventObject (x));
381 	    }
382         else
383         {
384             if ( ! mnClientId)
385                 mnClientId = comphelper::AccessibleEventNotifier::registerClient();
386             comphelper::AccessibleEventNotifier::addEventListener(mnClientId, rxListener);
387         }
388     }
389 }
390 
391 
392 
393 
394 void SAL_CALL AccessibleSlideSorterView::removeEventListener(
395     const Reference<XAccessibleEventListener >& rxListener)
396     throw (RuntimeException)
397 {
398     ThrowIfDisposed();
399 	if (rxListener.is())
400 	{
401         const osl::MutexGuard aGuard(maMutex);
402 
403         if (mnClientId != 0)
404         {
405             sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener(
406                 mnClientId, rxListener );
407             if ( !nListenerCount )
408             {
409                 // no listeners anymore -> revoke ourself. This may lead to
410                 // the notifier thread dying (if we were the last client),
411                 // and at least to us not firing any events anymore, in case
412                 // somebody calls NotifyAccessibleEvent, again
413                 comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
414                 mnClientId = 0;
415             }
416         }
417 	}
418 }
419 
420 
421 
422 
423 //===== XAccessibleComponent ==================================================
424 
425 sal_Bool SAL_CALL AccessibleSlideSorterView::containsPoint (const awt::Point& aPoint)
426     throw (RuntimeException)
427 {
428     ThrowIfDisposed();
429     const awt::Rectangle aBBox (getBounds());
430     return (aPoint.X >= 0)
431         && (aPoint.X < aBBox.Width)
432         && (aPoint.Y >= 0)
433         && (aPoint.Y < aBBox.Height);
434 }
435 
436 
437 
438 
439 Reference<XAccessible> SAL_CALL
440     AccessibleSlideSorterView::getAccessibleAtPoint (const awt::Point& aPoint)
441     throw (RuntimeException)
442 {
443     ThrowIfDisposed();
444     Reference<XAccessible> xAccessible;
445     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
446 
447     const Point aTestPoint (aPoint.X, aPoint.Y);
448     ::sd::slidesorter::model::SharedPageDescriptor pHitDescriptor (
449         mrSlideSorter.GetController().GetPageAt(aTestPoint));
450     if (pHitDescriptor.get() != NULL)
451         xAccessible = mpImpl->GetAccessibleChild(
452             (pHitDescriptor->GetPage()->GetPageNum()-1)/2);
453 
454     return xAccessible;
455 }
456 
457 
458 
459 
460 awt::Rectangle SAL_CALL AccessibleSlideSorterView::getBounds (void)
461     throw (uno::RuntimeException)
462 {
463     ThrowIfDisposed();
464     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
465     awt::Rectangle aBBox;
466 
467     if (mpContentWindow != NULL)
468     {
469         const Point aPosition (mpContentWindow->GetPosPixel());
470         const Size aSize (mpContentWindow->GetOutputSizePixel());
471 
472         aBBox.X = aPosition.X();
473         aBBox.Y = aPosition.Y();
474         aBBox.Width = aSize.Width();
475         aBBox.Height = aSize.Height();
476     }
477 
478     return aBBox;
479 }
480 
481 
482 
483 
484 awt::Point SAL_CALL AccessibleSlideSorterView::getLocation (void)
485     throw (uno::RuntimeException)
486 {
487     ThrowIfDisposed();
488     awt::Point aLocation;
489 
490     if (mpContentWindow != NULL)
491     {
492         const Point aPosition (mpContentWindow->GetPosPixel());
493         aLocation.X = aPosition.X();
494         aLocation.Y = aPosition.Y();
495     }
496 
497     return aLocation;
498 }
499 
500 
501 
502 
503 /** Calculate the location on screen from the parent's location on screen
504     and our own relative location.
505 */
506 awt::Point SAL_CALL AccessibleSlideSorterView::getLocationOnScreen()
507     throw (uno::RuntimeException)
508 {
509     ThrowIfDisposed();
510     const vos::OGuard aSolarGuard( Application::GetSolarMutex() );
511     awt::Point aParentLocationOnScreen;
512 
513     Reference<XAccessible> xParent (getAccessibleParent());
514     if (xParent.is())
515     {
516         Reference<XAccessibleComponent> xParentComponent (
517             xParent->getAccessibleContext(), uno::UNO_QUERY);
518         if (xParentComponent.is())
519             aParentLocationOnScreen = xParentComponent->getLocationOnScreen();
520     }
521 
522     awt::Point aLocationOnScreen (getLocation());
523     aLocationOnScreen.X += aParentLocationOnScreen.X;
524     aLocationOnScreen.Y += aParentLocationOnScreen.Y;
525 
526     return aLocationOnScreen;
527 }
528 
529 
530 
531 
532 awt::Size SAL_CALL AccessibleSlideSorterView::getSize (void)
533     throw (uno::RuntimeException)
534 {
535     ThrowIfDisposed();
536     awt::Size aSize;
537 
538     if (mpContentWindow != NULL)
539     {
540         const Size aOutputSize (mpContentWindow->GetOutputSizePixel());
541         aSize.Width = aOutputSize.Width();
542         aSize.Height = aOutputSize.Height();
543     }
544 
545     return aSize;
546 }
547 
548 
549 
550 
551 void SAL_CALL AccessibleSlideSorterView::grabFocus (void)
552     throw (uno::RuntimeException)
553 {
554     ThrowIfDisposed();
555     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
556 
557     if (mpContentWindow)
558         mpContentWindow->GrabFocus();
559 }
560 
561 
562 
563 
564 sal_Int32 SAL_CALL AccessibleSlideSorterView::getForeground (void)
565     throw (RuntimeException)
566 {
567     ThrowIfDisposed();
568 	svtools::ColorConfig aColorConfig;
569     sal_uInt32 nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor;
570     return static_cast<sal_Int32>(nColor);
571 }
572 
573 
574 
575 
576 sal_Int32 SAL_CALL AccessibleSlideSorterView::getBackground (void)
577     throw (RuntimeException)
578 {
579     ThrowIfDisposed();
580     sal_uInt32 nColor = Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor();
581     return static_cast<sal_Int32>(nColor);
582 }
583 
584 
585 
586 
587 //===== XAccessibleSelection ==================================================
588 
589 void SAL_CALL AccessibleSlideSorterView::selectAccessibleChild (sal_Int32 nChildIndex)
590     throw (lang::IndexOutOfBoundsException,
591         RuntimeException)
592 {
593     ThrowIfDisposed();
594     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
595 
596     AccessibleSlideSorterObject* pChild = mpImpl->GetAccessibleChild(nChildIndex);
597     if (pChild != NULL)
598         mrSlideSorter.GetController().GetPageSelector().SelectPage(pChild->GetPageNumber());
599     else
600         throw lang::IndexOutOfBoundsException();
601 }
602 
603 
604 
605 
606 sal_Bool SAL_CALL AccessibleSlideSorterView::isAccessibleChildSelected (sal_Int32 nChildIndex)
607     throw (lang::IndexOutOfBoundsException,
608         RuntimeException)
609 {
610     ThrowIfDisposed();
611     sal_Bool bIsSelected = sal_False;
612     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
613 
614     AccessibleSlideSorterObject* pChild = mpImpl->GetAccessibleChild(nChildIndex);
615     if (pChild != NULL)
616         bIsSelected = mrSlideSorter.GetController().GetPageSelector().IsPageSelected(
617             pChild->GetPageNumber());
618     else
619         throw lang::IndexOutOfBoundsException();
620 
621     return bIsSelected;
622 }
623 
624 
625 
626 
627 void SAL_CALL AccessibleSlideSorterView::clearAccessibleSelection (void)
628     throw (uno::RuntimeException)
629 {
630     ThrowIfDisposed();
631     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
632 
633     mrSlideSorter.GetController().GetPageSelector().DeselectAllPages();
634 }
635 
636 
637 
638 
639 void SAL_CALL AccessibleSlideSorterView::selectAllAccessibleChildren (void)
640     throw (uno::RuntimeException)
641 {
642     ThrowIfDisposed();
643     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
644 
645     mrSlideSorter.GetController().GetPageSelector().SelectAllPages();
646 }
647 
648 
649 
650 
651 sal_Int32 SAL_CALL AccessibleSlideSorterView::getSelectedAccessibleChildCount (void)
652     throw (uno::RuntimeException)
653 {
654     ThrowIfDisposed ();
655     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
656     return mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount();
657 }
658 
659 
660 
661 
662 Reference<XAccessible > SAL_CALL
663     AccessibleSlideSorterView::getSelectedAccessibleChild (sal_Int32 nSelectedChildIndex )
664     throw (lang::IndexOutOfBoundsException, uno::RuntimeException)
665 {
666     ThrowIfDisposed ();
667     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
668     Reference<XAccessible> xChild;
669 
670     ::sd::slidesorter::controller::PageSelector& rSelector (
671         mrSlideSorter.GetController().GetPageSelector());
672     sal_Int32 nPageCount(rSelector.GetPageCount());
673     sal_Int32 nSelectedCount = 0;
674     for (sal_Int32 i=0; i<nPageCount; i++)
675         if (rSelector.IsPageSelected(i))
676         {
677             if (nSelectedCount == nSelectedChildIndex)
678             {
679                 xChild = mpImpl->GetAccessibleChild(i);
680                 break;
681             }
682             ++nSelectedCount;
683         }
684 
685 
686     if ( ! xChild.is() )
687         throw lang::IndexOutOfBoundsException();
688 
689     return xChild;
690 }
691 
692 
693 
694 
695 void SAL_CALL AccessibleSlideSorterView::deselectAccessibleChild (sal_Int32 nChildIndex)
696     throw (lang::IndexOutOfBoundsException,
697         RuntimeException)
698 {
699     ThrowIfDisposed();
700     const vos::OGuard aSolarGuard (Application::GetSolarMutex());
701 
702     AccessibleSlideSorterObject* pChild = mpImpl->GetAccessibleChild(nChildIndex);
703     if (pChild != NULL)
704         mrSlideSorter.GetController().GetPageSelector().DeselectPage(pChild->GetPageNumber());
705     else
706         throw lang::IndexOutOfBoundsException();
707 }
708 
709 
710 
711 
712 //=====  XServiceInfo  ========================================================
713 
714 ::rtl::OUString SAL_CALL
715    	AccessibleSlideSorterView::getImplementationName (void)
716     throw (::com::sun::star::uno::RuntimeException)
717 {
718 	return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleSlideSorterView"));
719 }
720 
721 
722 
723 
724 sal_Bool SAL_CALL
725  	AccessibleSlideSorterView::supportsService (const OUString& sServiceName)
726     throw (::com::sun::star::uno::RuntimeException)
727 {
728     ThrowIfDisposed ();
729 
730     //  Iterate over all supported service names and return true if on of them
731     //  matches the given name.
732     uno::Sequence< ::rtl::OUString> aSupportedServices (
733         getSupportedServiceNames ());
734     for (int i=0; i<aSupportedServices.getLength(); i++)
735         if (sServiceName == aSupportedServices[i])
736             return sal_True;
737     return sal_False;
738 }
739 
740 
741 
742 
743 uno::Sequence< ::rtl::OUString> SAL_CALL
744    	AccessibleSlideSorterView::getSupportedServiceNames (void)
745     throw (::com::sun::star::uno::RuntimeException)
746 {
747     ThrowIfDisposed ();
748 
749 	static const OUString sServiceNames[3] = {
750         OUString(RTL_CONSTASCII_USTRINGPARAM(
751             "com.sun.star.accessibility.Accessible")),
752         OUString(RTL_CONSTASCII_USTRINGPARAM(
753             "com.sun.star.accessibility.AccessibleContext")),
754         OUString(RTL_CONSTASCII_USTRINGPARAM(
755             "com.sun.star.drawing.AccessibleSlideSorterView"))
756     };
757 	return uno::Sequence<OUString> (sServiceNames, 3);
758 }
759 
760 
761 
762 
763 void AccessibleSlideSorterView::ThrowIfDisposed (void)
764     throw (lang::DisposedException)
765 {
766 	if (rBHelper.bDisposed || rBHelper.bInDispose)
767 	{
768         OSL_TRACE ("Calling disposed object. Throwing exception:");
769         throw lang::DisposedException (
770             OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")),
771             static_cast<uno::XWeak*>(this));
772     }
773 }
774 
775 
776 
777 sal_Bool AccessibleSlideSorterView::IsDisposed (void)
778 {
779 	return (rBHelper.bDisposed || rBHelper.bInDispose);
780 }
781 
782 
783 
784 
785 //===== AccessibleSlideSorterView::Implementation =============================
786 
787 AccessibleSlideSorterView::Implementation::Implementation (
788     AccessibleSlideSorterView& rAccessibleSlideSorter,
789     ::sd::slidesorter::SlideSorter& rSlideSorter,
790     ::Window* pWindow)
791     : mrAccessibleSlideSorter(rAccessibleSlideSorter),
792       mrSlideSorter(rSlideSorter),
793       maPageObjects(),
794       mnFirstVisibleChild(0),
795       mnLastVisibleChild(-1),
796       mbListeningToDocument(false),
797       mpWindow(pWindow),
798       mnFocusedIndex(-1),
799       mbModelChangeLocked(false),
800       mnUpdateChildrenUserEventId(0),
801       mnSelectionChangeUserEventId(0)
802 {
803     ConnectListeners();
804     UpdateChildren();
805 }
806 
807 
808 
809 
810 AccessibleSlideSorterView::Implementation::~Implementation (void)
811 {
812     if (mnUpdateChildrenUserEventId != 0)
813         Application::RemoveUserEvent(mnUpdateChildrenUserEventId);
814     if (mnSelectionChangeUserEventId != 0)
815         Application::RemoveUserEvent(mnSelectionChangeUserEventId);
816     ReleaseListeners();
817     Clear();
818 }
819 
820 
821 
822 
823 void AccessibleSlideSorterView::Implementation::RequestUpdateChildren (void)
824 {
825     if (mnUpdateChildrenUserEventId == 0)
826         mnUpdateChildrenUserEventId = Application::PostUserEvent(
827             LINK(this, AccessibleSlideSorterView::Implementation,
828             UpdateChildrenCallback));
829 }
830 
831 
832 
833 
834 void AccessibleSlideSorterView::Implementation::UpdateChildren (void)
835 {
836     if (mbModelChangeLocked)
837     {
838         // Do nothing right now.  When the flag is reset, this method is
839         // called again.
840         return;
841     }
842 
843     const Pair aRange (mrSlideSorter.GetView().GetVisiblePageRange());
844     mnFirstVisibleChild = aRange.A();
845     mnLastVisibleChild = aRange.B();
846 
847     // Release all children.
848     Clear();
849 
850     // Create new children for the modified visible range.
851     maPageObjects.resize(mrSlideSorter.GetModel().GetPageCount());
852     for (sal_Int32 nIndex(mnFirstVisibleChild); nIndex<=mnLastVisibleChild; ++nIndex)
853         GetAccessibleChild(nIndex);
854 }
855 
856 
857 
858 
859 void AccessibleSlideSorterView::Implementation::Clear (void)
860 {
861     PageObjectList::iterator iPageObject;
862     PageObjectList::iterator iEnd = maPageObjects.end();
863     for (iPageObject=maPageObjects.begin(); iPageObject!=iEnd; ++iPageObject)
864         if (*iPageObject != NULL)
865         {
866             mrAccessibleSlideSorter.FireAccessibleEvent(
867                 AccessibleEventId::CHILD,
868                 Any(Reference<XAccessible>(iPageObject->get())),
869                 Any());
870 
871             Reference<XComponent> xComponent (Reference<XWeak>(iPageObject->get()), UNO_QUERY);
872             if (xComponent.is())
873                 xComponent->dispose();
874             *iPageObject = NULL;
875         }
876     maPageObjects.clear();
877 }
878 
879 
880 
881 
882 sal_Int32 AccessibleSlideSorterView::Implementation::GetVisibleChildCount (void) const
883 {
884     if (mnFirstVisibleChild<=mnLastVisibleChild && mnFirstVisibleChild>=0)
885         return mnLastVisibleChild - mnFirstVisibleChild + 1;
886     else
887         return 0;
888 }
889 
890 
891 
892 
893 AccessibleSlideSorterObject* AccessibleSlideSorterView::Implementation::GetVisibleChild (
894     sal_Int32 nIndex)
895 {
896     assert(nIndex>=0 && nIndex<GetVisibleChildCount());
897 
898     return GetAccessibleChild(nIndex+mnFirstVisibleChild);
899 }
900 
901 
902 
903 
904 AccessibleSlideSorterObject* AccessibleSlideSorterView::Implementation::GetAccessibleChild (
905     sal_Int32 nIndex)
906 {
907     AccessibleSlideSorterObject* pChild = NULL;
908 
909     if (nIndex>=0 && (sal_uInt32)nIndex<maPageObjects.size())
910     {
911         if (maPageObjects[nIndex] == NULL)
912         {
913             ::sd::slidesorter::model::SharedPageDescriptor pDescriptor(
914                 mrSlideSorter.GetModel().GetPageDescriptor(nIndex));
915             if (pDescriptor.get() != NULL)
916             {
917                 maPageObjects[nIndex] = new AccessibleSlideSorterObject(
918                     &mrAccessibleSlideSorter,
919                     mrSlideSorter,
920                     (pDescriptor->GetPage()->GetPageNum()-1)/2);
921 
922                 mrAccessibleSlideSorter.FireAccessibleEvent(
923                     AccessibleEventId::CHILD,
924                     Any(),
925                     Any(Reference<XAccessible>(maPageObjects[nIndex].get())));
926             }
927 
928         }
929 
930         pChild = maPageObjects[nIndex].get();
931     }
932     else
933     {
934         OSL_ASSERT(nIndex>=0 && (sal_uInt32)nIndex<maPageObjects.size());
935     }
936 
937     return pChild;
938 }
939 
940 
941 
942 
943 void AccessibleSlideSorterView::Implementation::ConnectListeners (void)
944 {
945     StartListening (*mrSlideSorter.GetModel().GetDocument());
946     if (mrSlideSorter.GetViewShell() != NULL)
947         StartListening (*mrSlideSorter.GetViewShell());
948     mbListeningToDocument = true;
949 
950     if (mpWindow != NULL)
951         mpWindow->AddEventListener(
952             LINK(this,AccessibleSlideSorterView::Implementation,WindowEventListener));
953 
954     mrSlideSorter.GetController().GetSelectionManager()->AddSelectionChangeListener(
955         LINK(this,AccessibleSlideSorterView::Implementation,SelectionChangeListener));
956     mrSlideSorter.GetController().GetFocusManager().AddFocusChangeListener(
957         LINK(this,AccessibleSlideSorterView::Implementation,FocusChangeListener));
958     mrSlideSorter.GetView().AddVisibilityChangeListener(
959         LINK(this,AccessibleSlideSorterView::Implementation,UpdateChildrenCallback));
960 }
961 
962 
963 
964 
965 void AccessibleSlideSorterView::Implementation::ReleaseListeners (void)
966 {
967     mrSlideSorter.GetController().GetFocusManager().RemoveFocusChangeListener(
968         LINK(this,AccessibleSlideSorterView::Implementation,FocusChangeListener));
969     mrSlideSorter.GetController().GetSelectionManager()->RemoveSelectionChangeListener(
970         LINK(this,AccessibleSlideSorterView::Implementation,SelectionChangeListener));
971     mrSlideSorter.GetView().RemoveVisibilityChangeListener(
972         LINK(this,AccessibleSlideSorterView::Implementation,UpdateChildrenCallback));
973 
974     if (mpWindow != NULL)
975         mpWindow->RemoveEventListener(
976             LINK(this,AccessibleSlideSorterView::Implementation,WindowEventListener));
977 
978     if (mbListeningToDocument)
979     {
980         if (mrSlideSorter.GetViewShell() != NULL)
981             StartListening(*mrSlideSorter.GetViewShell());
982         EndListening (*mrSlideSorter.GetModel().GetDocument());
983         mbListeningToDocument = false;
984     }
985 }
986 
987 
988 
989 
990 void AccessibleSlideSorterView::Implementation::Notify (
991     SfxBroadcaster&,
992     const SfxHint& rHint)
993 {
994     if (rHint.ISA(SdrHint))
995     {
996         SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint));
997         switch (rSdrHint.GetKind())
998         {
999             case HINT_PAGEORDERCHG:
1000                 RequestUpdateChildren();
1001                 break;
1002             default:
1003                 break;
1004         }
1005     }
1006     else if (rHint.ISA(sd::ViewShellHint))
1007     {
1008         sd::ViewShellHint& rViewShellHint (*PTR_CAST(sd::ViewShellHint, &rHint));
1009         switch (rViewShellHint.GetHintId())
1010         {
1011             case sd::ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START:
1012                 mbModelChangeLocked = true;
1013                 break;
1014 
1015             case sd::ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END:
1016                 mbModelChangeLocked = false;
1017                 RequestUpdateChildren();
1018                 break;
1019             default:
1020                 break;
1021         }
1022     }
1023 }
1024 
1025 
1026 
1027 
1028 IMPL_LINK(AccessibleSlideSorterView::Implementation, WindowEventListener, VclWindowEvent*, pEvent)
1029 {
1030 	switch (pEvent->GetId())
1031     {
1032         case VCLEVENT_WINDOW_MOVE:
1033         case VCLEVENT_WINDOW_RESIZE:
1034             RequestUpdateChildren();
1035             break;
1036 
1037         case VCLEVENT_WINDOW_GETFOCUS:
1038         case VCLEVENT_WINDOW_LOSEFOCUS:
1039             mrAccessibleSlideSorter.FireAccessibleEvent(
1040                 AccessibleEventId::SELECTION_CHANGED,
1041                 Any(),
1042                 Any());
1043             break;
1044         default:
1045             break;
1046     }
1047     return 1;
1048 }
1049 
1050 
1051 
1052 
1053 IMPL_LINK(AccessibleSlideSorterView::Implementation, SelectionChangeListener, void*, EMPTYARG )
1054 {
1055     if (mnSelectionChangeUserEventId == 0)
1056         mnSelectionChangeUserEventId = Application::PostUserEvent(
1057             LINK(this, AccessibleSlideSorterView::Implementation, BroadcastSelectionChange));
1058     return 1;
1059 }
1060 
1061 
1062 
1063 
1064 IMPL_LINK(AccessibleSlideSorterView::Implementation, BroadcastSelectionChange, void*, EMPTYARG )
1065 {
1066     mnSelectionChangeUserEventId = 0;
1067     mrAccessibleSlideSorter.FireAccessibleEvent(
1068         AccessibleEventId::SELECTION_CHANGED,
1069         Any(),
1070         Any());
1071     return 1;
1072 }
1073 
1074 
1075 
1076 
1077 IMPL_LINK(AccessibleSlideSorterView::Implementation, FocusChangeListener, void*, EMPTYARG )
1078 {
1079     sal_Int32 nNewFocusedIndex (
1080         mrSlideSorter.GetController().GetFocusManager().GetFocusedPageIndex());
1081 
1082     if (nNewFocusedIndex != mnFocusedIndex)
1083     {
1084         if (mnFocusedIndex >= 0)
1085         {
1086             AccessibleSlideSorterObject* pObject = GetAccessibleChild(mnFocusedIndex);
1087             if (pObject != NULL)
1088                 pObject->FireAccessibleEvent(
1089                     AccessibleEventId::STATE_CHANGED,
1090                     Any(AccessibleStateType::FOCUSED),
1091                     Any());
1092         }
1093         if (nNewFocusedIndex >= 0)
1094         {
1095             AccessibleSlideSorterObject* pObject = GetAccessibleChild(nNewFocusedIndex);
1096             if (pObject != NULL)
1097                 pObject->FireAccessibleEvent(
1098                     AccessibleEventId::STATE_CHANGED,
1099                     Any(),
1100                     Any(AccessibleStateType::FOCUSED));
1101         }
1102         mnFocusedIndex = nNewFocusedIndex;
1103     }
1104     return 1;
1105 }
1106 
1107 
1108 
1109 
1110 IMPL_LINK(AccessibleSlideSorterView::Implementation, UpdateChildrenCallback, void*, EMPTYARG )
1111 {
1112     mnUpdateChildrenUserEventId = 0;
1113     UpdateChildren();
1114 
1115     return 1;
1116 }
1117 
1118 
1119 
1120 
1121 } // end of namespace ::accessibility
1122