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