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_chart2.hxx"
30 
31 #include "AccessibleChartView.hxx"
32 #include "chartview/ExplicitValueProvider.hxx"
33 #include "servicenames.hxx"
34 #include "macros.hxx"
35 #include "ObjectHierarchy.hxx"
36 #include "ObjectIdentifier.hxx"
37 #include "ResId.hxx"
38 #include "Strings.hrc"
39 #include "AccessibleViewForwarder.hxx"
40 
41 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
42 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
43 #include <com/sun/star/accessibility/AccessibleRole.hpp>
44 
45 #include <tools/string.hxx>
46 #include <vcl/window.hxx>
47 #include <toolkit/helper/vclunohelper.hxx>
48 // for SolarMutex
49 #include <vcl/svapp.hxx>
50 
51 // header for typedef MutexGuard
52 #include <osl/mutex.hxx>
53 
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::accessibility;
56 
57 using ::com::sun::star::uno::Sequence;
58 using ::com::sun::star::uno::Reference;
59 using ::com::sun::star::uno::WeakReference;
60 using ::com::sun::star::uno::Any;
61 using ::rtl::OUString;
62 using osl::MutexGuard;
63 
64 //.............................................................................
65 namespace chart
66 {
67 //.............................................................................
68 
69 AccessibleChartView::AccessibleChartView(
70     const Reference< uno::XComponentContext >& xContext, SdrView* pView ) :
71         impl::AccessibleChartView_Base(
72             AccessibleElementInfo(), // empty for now
73             true, // has children
74             true  // always transparent
75             ),
76         m_xContext( xContext ),
77         m_pSdrView( pView ),
78         m_pViewForwarder( NULL )
79 {
80     AddState( AccessibleStateType::OPAQUE );
81 }
82 
83 AccessibleChartView::~AccessibleChartView()
84 {
85     delete m_pViewForwarder;
86 }
87 
88 
89 awt::Rectangle AccessibleChartView::GetWindowPosSize() const
90 {
91     Reference< awt::XWindow > xWindow( GetInfo().m_xWindow );
92     if( ! xWindow.is())
93         return awt::Rectangle();
94 
95     // this should do, but it doesn't => HACK
96 //     return xWindow->getPosSize();
97 
98     awt::Rectangle aBBox( xWindow->getPosSize() );
99 
100     Window* pWindow( VCLUnoHelper::GetWindow( GetInfo().m_xWindow ));
101     if( pWindow )
102     {
103         // /-- solar
104         ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
105         Point aVCLPoint( pWindow->OutputToAbsoluteScreenPixel( Point( 0, 0 ) ));
106         aBBox.X = aVCLPoint.getX();
107         aBBox.Y = aVCLPoint.getY();
108         // \-- solar
109     }
110 
111     return aBBox;
112 }
113 
114 awt::Point AccessibleChartView::GetUpperLeftOnScreen() const
115 {
116     awt::Point aParentPosition;
117 
118     awt::Rectangle aBBox( GetWindowPosSize() );
119     aParentPosition.X = aBBox.X;
120     aParentPosition.Y = aBBox.Y;
121 
122     return aParentPosition;
123 }
124 
125 // ________ XAccessibleContext ________
126 OUString SAL_CALL AccessibleChartView::getAccessibleName()
127     throw (uno::RuntimeException)
128 {
129     return OUString( String( SchResId( STR_OBJECT_DIAGRAM )));
130 }
131 
132 OUString SAL_CALL AccessibleChartView::getAccessibleDescription()
133     throw (uno::RuntimeException)
134 {
135     return getAccessibleName();
136 }
137 
138 Reference< XAccessible > SAL_CALL AccessibleChartView::getAccessibleParent()
139     throw (uno::RuntimeException)
140 {
141     return Reference< XAccessible >( m_xParent );
142 }
143 
144 sal_Int32 SAL_CALL AccessibleChartView::getAccessibleIndexInParent()
145     throw (uno::RuntimeException)
146 {
147     // the document is always the only child of the window
148     return 0;
149 }
150 
151 sal_Int16 SAL_CALL AccessibleChartView::getAccessibleRole()
152     throw (uno::RuntimeException)
153 {
154     return AccessibleRole::DOCUMENT;
155 }
156 
157 // ________ XAccessibleComponent ________
158 awt::Rectangle SAL_CALL AccessibleChartView::getBounds()
159     throw (uno::RuntimeException)
160 {
161     awt::Rectangle aResult( GetWindowPosSize());
162     Reference< XAccessible > xParent( m_xParent );
163     if( xParent.is())
164     {
165         Reference< XAccessibleComponent > xContext( xParent->getAccessibleContext(), uno::UNO_QUERY );
166         if( xContext.is())
167         {
168             awt::Point aParentPosition = xContext->getLocationOnScreen();
169             aResult.X -= aParentPosition.X;
170             aResult.Y -= aParentPosition.Y;
171         }
172     }
173     return aResult;
174 }
175 
176 awt::Point SAL_CALL AccessibleChartView::getLocationOnScreen()
177     throw (uno::RuntimeException)
178 {
179     awt::Rectangle aBounds( getBounds());
180     awt::Point aResult;
181     Reference< XAccessible > xParent( m_xParent );
182     if( xParent.is())
183     {
184         Reference< XAccessibleComponent > xAccComp(
185             xParent->getAccessibleContext(), uno::UNO_QUERY );
186         aResult = xAccComp->getLocationOnScreen();
187         aResult.X += aBounds.X;
188         aResult.Y += aBounds.Y;
189     }
190     return aResult;
191 }
192 
193 //-----------------------------------------------------------------
194 // lang::XInitialization
195 //-----------------------------------------------------------------
196 
197 void SAL_CALL AccessibleChartView::initialize( const Sequence< Any >& rArguments )
198                 throw (uno::Exception, uno::RuntimeException)
199 {
200     //0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself
201     //1: frame::XModel representing the chart model - offers access to object data
202     //2: lang::XInterface representing the normal chart view - offers access to some extra object data
203 
204     //all arguments are only valid until next initialization
205     bool bChanged = false;
206     bool bOldInvalid = false;
207     bool bNewInvalid = false;
208 
209     Reference< view::XSelectionSupplier > xSelectionSupplier;
210     Reference< frame::XModel > xChartModel;
211     Reference< uno::XInterface > xChartView;
212     Reference< XAccessible > xParent;
213     Reference< awt::XWindow > xWindow;
214     {
215         MutexGuard aGuard( GetMutex());
216         xSelectionSupplier.set( m_xSelectionSupplier );
217         xChartModel.set( m_xChartModel );
218         xChartView.set( m_xChartView );
219         xParent.set( m_xParent );
220         xWindow.set( m_xWindow );
221     }
222 
223     if( !xSelectionSupplier.is() || !xChartModel.is() || !xChartView.is() )
224     {
225         bOldInvalid = true;
226     }
227 
228     if( rArguments.getLength() > 1 )
229     {
230         Reference< frame::XModel > xNewChartModel;
231         rArguments[1] >>= xNewChartModel;
232         if( xNewChartModel != xChartModel )
233         {
234             xChartModel = xNewChartModel;
235             bChanged = true;
236         }
237     }
238     else if( xChartModel.is() )
239     {
240         bChanged = true;
241         xChartModel = 0;
242     }
243 
244     if( rArguments.getLength() > 2 )
245     {
246         Reference< uno::XInterface > xNewChartView;
247         rArguments[2] >>= xNewChartView;
248         if( xNewChartView != xChartView )
249         {
250             xChartView = xNewChartView;
251             bChanged = true;
252         }
253     }
254     else if( xChartView.is() )
255     {
256         bChanged = true;
257         xChartView = 0;
258     }
259 
260     if( rArguments.getLength() > 3 )
261     {
262         Reference< XAccessible > xNewParent;
263         rArguments[3] >>= xNewParent;
264         if( xNewParent != xParent )
265         {
266             xParent = xNewParent;
267             bChanged = true;
268         }
269     }
270 
271     if( rArguments.getLength() > 4 )
272     {
273         Reference< awt::XWindow > xNewWindow;
274         rArguments[4] >>= xNewWindow;
275         if( xNewWindow != xWindow )
276         {
277             xWindow.set( xNewWindow );
278             bChanged = true;
279         }
280     }
281 
282     if( rArguments.getLength() > 0 && xChartModel.is() && xChartView.is() )
283     {
284         Reference< view::XSelectionSupplier > xNewSelectionSupplier;
285         rArguments[0] >>= xNewSelectionSupplier;
286         if(xSelectionSupplier!=xNewSelectionSupplier)
287         {
288             bChanged = true;
289             if(xSelectionSupplier.is())
290                 xSelectionSupplier->removeSelectionChangeListener(this);
291             if(xNewSelectionSupplier.is())
292                 xNewSelectionSupplier->addSelectionChangeListener(this);
293             xSelectionSupplier = xNewSelectionSupplier;
294         }
295     }
296     else if( xSelectionSupplier.is() )
297     {
298         bChanged = true;
299         xSelectionSupplier->removeSelectionChangeListener(this);
300         xSelectionSupplier = 0;
301     }
302 
303     if( !xSelectionSupplier.is() || !xChartModel.is() || !xChartView.is() )
304     {
305         if(xSelectionSupplier.is())
306             xSelectionSupplier->removeSelectionChangeListener(this);
307         xSelectionSupplier = 0;
308         xChartModel.clear();
309         xChartView.clear();
310         xParent.clear();
311         xWindow.clear();
312 
313         bNewInvalid = true;
314     }
315 
316     {
317         MutexGuard aGuard( GetMutex());
318         m_xSelectionSupplier = WeakReference< view::XSelectionSupplier >(xSelectionSupplier);
319         m_xChartModel = WeakReference< frame::XModel >(xChartModel);
320         m_xChartView = WeakReference< uno::XInterface >(xChartView);
321         m_xParent = WeakReference< XAccessible >(xParent);
322         m_xWindow = WeakReference< awt::XWindow >(xWindow);
323     }
324 
325     if( bOldInvalid && bNewInvalid )
326         bChanged = false;
327 
328     if( bChanged )
329     {
330         {
331             //before notification we prepare for creation of new context
332             //the old context will be deleted after notification than
333             MutexGuard aGuard( GetMutex());
334             Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY );
335             if( xChartDoc.is())
336                 m_spObjectHierarchy.reset( new ObjectHierarchy( xChartDoc, getExplicitValueProvider() ));
337             else
338                 m_spObjectHierarchy.reset();
339         }
340 
341         {
342             AccessibleElementInfo aAccInfo;
343             aAccInfo.m_aOID = ObjectIdentifier( C2U( "ROOT" ) );
344             aAccInfo.m_xChartDocument = uno::WeakReference< chart2::XChartDocument >(
345                 uno::Reference< chart2::XChartDocument >( m_xChartModel.get(), uno::UNO_QUERY ));
346             aAccInfo.m_xSelectionSupplier = m_xSelectionSupplier;
347             aAccInfo.m_xView = m_xChartView;
348             aAccInfo.m_xWindow = m_xWindow;
349             aAccInfo.m_pParent = 0;
350             aAccInfo.m_spObjectHierarchy = m_spObjectHierarchy;
351             aAccInfo.m_pSdrView = m_pSdrView;
352             Window* pWindow = VCLUnoHelper::GetWindow( m_xWindow );
353             if ( m_pViewForwarder )
354             {
355                 delete m_pViewForwarder;
356             }
357             m_pViewForwarder = new AccessibleViewForwarder( this, pWindow );
358             aAccInfo.m_pViewForwarder = m_pViewForwarder;
359             // broadcasts an INVALIDATE_ALL_CHILDREN event globally
360             SetInfo( aAccInfo );
361         }
362     }
363 }
364 
365 ExplicitValueProvider* AccessibleChartView::getExplicitValueProvider()
366 {
367     return ExplicitValueProvider::getExplicitValueProvider(m_xChartView);
368 }
369 
370 //-------------------------------------------------------------------------
371 // view::XSelectionChangeListener
372 //-------------------------------------------------------------------------
373 
374 void SAL_CALL AccessibleChartView::selectionChanged( const lang::EventObject& /*rEvent*/ )
375                 throw (uno::RuntimeException)
376 {
377     Reference< view::XSelectionSupplier > xSelectionSupplier;
378     {
379         MutexGuard aGuard( GetMutex());
380         xSelectionSupplier = Reference< view::XSelectionSupplier >(m_xSelectionSupplier);
381     }
382 
383     if( xSelectionSupplier.is() )
384     {
385         ObjectIdentifier aSelectedOID( xSelectionSupplier->getSelection() );
386         if ( m_aCurrentSelectionOID.isValid() )
387         {
388             NotifyEvent( LOST_SELECTION, m_aCurrentSelectionOID );
389         }
390         if( aSelectedOID.isValid() )
391         {
392             NotifyEvent( GOT_SELECTION, aSelectedOID );
393         }
394         m_aCurrentSelectionOID = aSelectedOID;
395     }
396 }
397 
398 //-------------------------------------------------------------------------
399 // lang::XComponent::dispose()
400 //-------------------------------------------------------------------------
401 void SAL_CALL AccessibleChartView::disposing()
402 {
403     AccessibleBase::disposing();
404 }
405 
406 //-------------------------------------------------------------------------
407 // XEventListener
408 //-------------------------------------------------------------------------
409 void SAL_CALL AccessibleChartView::disposing( const lang::EventObject& /*Source*/ )
410     throw (uno::RuntimeException)
411 {
412 }
413 
414 //.............................................................................
415 } //namespace chart
416 //.............................................................................
417