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_editeng.hxx"
30 
31 //------------------------------------------------------------------------
32 //
33 // Global header
34 //
35 //------------------------------------------------------------------------
36 #include <com/sun/star/uno/Any.hxx>
37 #include <com/sun/star/uno/Reference.hxx>
38 #include <cppuhelper/weakref.hxx>
39 #include <com/sun/star/accessibility/XAccessible.hpp>
40 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
41 
42 //------------------------------------------------------------------------
43 //
44 // Project-local header
45 //
46 //------------------------------------------------------------------------
47 
48 #include <editeng/unoedhlp.hxx>
49 #include <editeng/unopracc.hxx>
50 #include <editeng/unoedsrc.hxx>
51 #include "editeng/AccessibleParaManager.hxx"
52 #include "editeng/AccessibleEditableTextPara.hxx"
53 
54 
55 using namespace ::com::sun::star;
56 using namespace ::com::sun::star::accessibility;
57 
58 
59 
60 namespace accessibility
61 {
62     AccessibleParaManager::AccessibleParaManager() :
63         maChildren(1),
64         maEEOffset( 0, 0 ),
65         mnFocusedChild( -1 ),
66         mbActive( sal_False )
67     {
68     }
69 
70     AccessibleParaManager::~AccessibleParaManager()
71     {
72         // owner is responsible for possible child defuncs
73     }
74 
75     void AccessibleParaManager::SetAdditionalChildStates( const VectorOfStates& rChildStates )
76     {
77         maChildStates = rChildStates;
78     }
79 
80     const AccessibleParaManager::VectorOfStates& AccessibleParaManager::GetAdditionalChildStates() const
81     {
82         return maChildStates;
83     }
84 
85     void AccessibleParaManager::SetNum( sal_Int32 nNumParas )
86     {
87         if( (size_t)nNumParas < maChildren.size() )
88             Release( nNumParas, maChildren.size() );
89 
90         maChildren.resize( nNumParas );
91 
92         if( mnFocusedChild >= nNumParas )
93             mnFocusedChild = -1;
94     }
95 
96     sal_uInt32 AccessibleParaManager::GetNum() const
97     {
98         return maChildren.size();
99     }
100 
101     AccessibleParaManager::VectorOfChildren::iterator AccessibleParaManager::begin()
102     {
103         return maChildren.begin();
104     }
105 
106     AccessibleParaManager::VectorOfChildren::iterator AccessibleParaManager::end()
107     {
108         return maChildren.end();
109     }
110 
111     AccessibleParaManager::VectorOfChildren::const_iterator AccessibleParaManager::begin() const
112     {
113         return maChildren.begin();
114     }
115 
116     AccessibleParaManager::VectorOfChildren::const_iterator AccessibleParaManager::end() const
117     {
118         return maChildren.end();
119     }
120 
121     void AccessibleParaManager::Release( sal_uInt32 nPara )
122     {
123         DBG_ASSERT( maChildren.size() > nPara, "AccessibleParaManager::Release: invalid index" );
124 
125         if( maChildren.size() > nPara )
126         {
127             ShutdownPara( GetChild( nPara ) );
128 
129             // clear reference and rect
130             maChildren[ nPara ] = WeakChild();
131         }
132     }
133 
134     void AccessibleParaManager::FireEvent( sal_uInt32 nPara,
135                                            const sal_Int16 nEventId,
136                                            const uno::Any& rNewValue,
137                                            const uno::Any& rOldValue ) const
138     {
139         DBG_ASSERT( maChildren.size() > nPara, "AccessibleParaManager::FireEvent: invalid index" );
140 
141         if( maChildren.size() > nPara )
142         {
143             WeakPara::HardRefType maChild( GetChild( nPara ).first.get() );
144             if( maChild.is() )
145                 maChild->FireEvent( nEventId, rNewValue, rOldValue );
146         }
147     }
148 
149     sal_Bool AccessibleParaManager::IsReferencable( WeakPara::HardRefType aChild )
150     {
151         return aChild.is();
152     }
153 
154     sal_Bool AccessibleParaManager::IsReferencable( sal_uInt32 nChild ) const
155     {
156         DBG_ASSERT( maChildren.size() > nChild, "AccessibleParaManager::IsReferencable: invalid index" );
157 
158         if( maChildren.size() > nChild )
159         {
160             // retrieve hard reference from weak one
161             return IsReferencable( GetChild( nChild ).first.get() );
162         }
163         else
164         {
165             return sal_False;
166         }
167     }
168 
169     AccessibleParaManager::WeakChild AccessibleParaManager::GetChild( sal_uInt32 nParagraphIndex ) const
170     {
171         DBG_ASSERT( maChildren.size() > nParagraphIndex, "AccessibleParaManager::GetChild: invalid index" );
172 
173         if( maChildren.size() > nParagraphIndex )
174         {
175             return maChildren[ nParagraphIndex ];
176         }
177         else
178         {
179             return WeakChild();
180         }
181     }
182 
183     AccessibleParaManager::Child AccessibleParaManager::CreateChild( sal_Int32 								nChild,
184                                                                      const uno::Reference< XAccessible >& 	xFrontEnd,
185                                                                      SvxEditSourceAdapter& 					rEditSource,
186                                                                      sal_uInt32 							nParagraphIndex	)
187     {
188         DBG_ASSERT( maChildren.size() > nParagraphIndex, "AccessibleParaManager::CreateChild: invalid index" );
189 
190         if( maChildren.size() > nParagraphIndex )
191         {
192             // retrieve hard reference from weak one
193             WeakPara::HardRefType aChild( GetChild( nParagraphIndex ).first.get() );
194 
195             if( !IsReferencable( nParagraphIndex ) )
196             {
197                 // there is no hard reference available, create object then
198                 // --> OD 2006-01-11 #i27138#
199                 AccessibleEditableTextPara* pChild = new AccessibleEditableTextPara( xFrontEnd, this );
200                 // <--
201                 uno::Reference< XAccessible > xChild( static_cast< ::cppu::OWeakObject* > (pChild), uno::UNO_QUERY );
202 
203                 if( !xChild.is() )
204                     throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Child creation failed")), xFrontEnd);
205 
206                 aChild = WeakPara::HardRefType( xChild, pChild );
207 
208                 InitChild( *aChild, rEditSource, nChild, nParagraphIndex );
209 
210                 maChildren[ nParagraphIndex ] = WeakChild( aChild, pChild->getBounds() );
211             }
212 
213             return Child( aChild.getRef(), GetChild( nParagraphIndex ).second );
214         }
215         else
216         {
217             return Child();
218         }
219     }
220 
221     void AccessibleParaManager::SetEEOffset( const Point& rOffset )
222     {
223         maEEOffset = rOffset;
224 
225         MemFunAdapter< const Point& > aAdapter( &::accessibility::AccessibleEditableTextPara::SetEEOffset, rOffset );
226         ::std::for_each( begin(), end(), aAdapter );
227     }
228 
229     void AccessibleParaManager::SetActive( sal_Bool bActive )
230     {
231         mbActive = bActive;
232 
233         if( bActive )
234         {
235             SetState( AccessibleStateType::ACTIVE );
236             SetState( AccessibleStateType::EDITABLE );
237         }
238         else
239         {
240             UnSetState( AccessibleStateType::ACTIVE );
241             UnSetState( AccessibleStateType::EDITABLE );
242         }
243     }
244 
245     void AccessibleParaManager::SetFocus( sal_Int32 nChild )
246     {
247         if( mnFocusedChild != -1 )
248             UnSetState( mnFocusedChild, AccessibleStateType::FOCUSED );
249 
250         mnFocusedChild = nChild;
251 
252         if( mnFocusedChild != -1 )
253             SetState( mnFocusedChild, AccessibleStateType::FOCUSED );
254     }
255 
256     void AccessibleParaManager::InitChild( AccessibleEditableTextPara& 	rChild,
257                                            SvxEditSourceAdapter& 		rEditSource,
258                                            sal_Int32 					nChild,
259                                            sal_uInt32 					nParagraphIndex ) const
260     {
261         rChild.SetEditSource( &rEditSource );
262         rChild.SetIndexInParent( nChild );
263         rChild.SetParagraphIndex( nParagraphIndex );
264 
265         rChild.SetEEOffset( maEEOffset );
266 
267         if( mbActive )
268         {
269             rChild.SetState( AccessibleStateType::ACTIVE );
270             rChild.SetState( AccessibleStateType::EDITABLE );
271         }
272 
273         if( mnFocusedChild == static_cast<sal_Int32>(nParagraphIndex) )
274             rChild.SetState( AccessibleStateType::FOCUSED );
275 
276         // add states passed from outside
277         for( VectorOfStates::const_iterator aIt = maChildStates.begin(), aEnd = maChildStates.end(); aIt != aEnd; ++aIt )
278             rChild.SetState( *aIt );
279     }
280 
281     void AccessibleParaManager::SetState( sal_Int32 nChild, const sal_Int16 nStateId )
282     {
283         MemFunAdapter< const sal_Int16 > aFunc( &AccessibleEditableTextPara::SetState,
284                                                 nStateId );
285         aFunc( GetChild(nChild) );
286     }
287 
288     void AccessibleParaManager::SetState( const sal_Int16 nStateId )
289     {
290         ::std::for_each( begin(), end(),
291                          MemFunAdapter< const sal_Int16 >( &AccessibleEditableTextPara::SetState,
292                                                            nStateId ) );
293     }
294 
295     void AccessibleParaManager::UnSetState( sal_Int32 nChild, const sal_Int16 nStateId )
296     {
297         MemFunAdapter< const sal_Int16 > aFunc( &AccessibleEditableTextPara::UnSetState,
298                                                 nStateId );
299         aFunc( GetChild(nChild) );
300     }
301 
302     void AccessibleParaManager::UnSetState( const sal_Int16 nStateId )
303     {
304         ::std::for_each( begin(), end(),
305                          MemFunAdapter< const sal_Int16 >( &AccessibleEditableTextPara::UnSetState,
306                                                            nStateId ) );
307     }
308 
309     void AccessibleParaManager::SetEditSource( SvxEditSourceAdapter* pEditSource )
310     {
311         MemFunAdapter< SvxEditSourceAdapter* > aAdapter( &::accessibility::AccessibleEditableTextPara::SetEditSource, pEditSource );
312         ::std::for_each( begin(), end(), aAdapter );
313     }
314 
315     // not generic yet, no arguments...
316     class AccessibleParaManager_DisposeChildren : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
317     {
318     public:
319         AccessibleParaManager_DisposeChildren() {}
320         void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
321         {
322             rPara.Dispose();
323         }
324     };
325 
326     void AccessibleParaManager::Dispose()
327     {
328         AccessibleParaManager_DisposeChildren aFunctor;
329 
330         ::std::for_each( begin(), end(),
331                          WeakChildAdapter< AccessibleParaManager_DisposeChildren > (aFunctor) );
332     }
333 
334     // not generic yet, too many method arguments...
335     class StateChangeEvent : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void >
336     {
337     public:
338         typedef void return_type;
339         StateChangeEvent( const sal_Int16 nEventId,
340                           const uno::Any& rNewValue,
341                           const uno::Any& rOldValue ) :
342             mnEventId( nEventId ),
343             mrNewValue( rNewValue ),
344             mrOldValue( rOldValue ) {}
345         void operator()( ::accessibility::AccessibleEditableTextPara& rPara )
346         {
347             rPara.FireEvent( mnEventId, mrNewValue, mrOldValue );
348         }
349 
350     private:
351         const sal_Int16 mnEventId;
352         const uno::Any& mrNewValue;
353         const uno::Any& mrOldValue;
354     };
355 
356     void AccessibleParaManager::FireEvent( sal_uInt32 nStartPara,
357                                            sal_uInt32 nEndPara,
358                                            const sal_Int16 nEventId,
359                                            const uno::Any& rNewValue,
360                                            const uno::Any& rOldValue ) const
361     {
362         DBG_ASSERT( maChildren.size() > nStartPara &&
363                     maChildren.size() >= nEndPara , "AccessibleParaManager::FireEvent: invalid index" );
364 
365         if( maChildren.size() > nStartPara &&
366             maChildren.size() >= nEndPara )
367         {
368             VectorOfChildren::const_iterator front = maChildren.begin();
369             VectorOfChildren::const_iterator back = front;
370 
371             ::std::advance( front, nStartPara );
372             ::std::advance( back, nEndPara );
373 
374             StateChangeEvent aFunctor( nEventId, rNewValue, rOldValue );
375 
376             ::std::for_each( front, back, AccessibleParaManager::WeakChildAdapter< StateChangeEvent >( aFunctor ) );
377         }
378     }
379 
380     class ReleaseChild : public ::std::unary_function< const AccessibleParaManager::WeakChild&, AccessibleParaManager::WeakChild >
381     {
382     public:
383         AccessibleParaManager::WeakChild operator()( const AccessibleParaManager::WeakChild& rPara )
384         {
385             AccessibleParaManager::ShutdownPara( rPara );
386 
387             // clear reference
388             return AccessibleParaManager::WeakChild();
389         }
390     };
391 
392     void AccessibleParaManager::Release( sal_uInt32 nStartPara, sal_uInt32 nEndPara )
393     {
394         DBG_ASSERT( maChildren.size() > nStartPara &&
395                     maChildren.size() >= nEndPara, "AccessibleParaManager::Release: invalid index" );
396 
397         if( maChildren.size() > nStartPara &&
398             maChildren.size() >= nEndPara )
399         {
400             VectorOfChildren::iterator front = maChildren.begin();
401             VectorOfChildren::iterator back = front;
402 
403             ::std::advance( front, nStartPara );
404             ::std::advance( back, nEndPara );
405 
406             ::std::transform( front, back, front, ReleaseChild() );
407         }
408     }
409 
410     void AccessibleParaManager::ShutdownPara( const WeakChild& rChild )
411     {
412         WeakPara::HardRefType aChild( rChild.first.get() );
413 
414         if( IsReferencable( aChild ) )
415             aChild->SetEditSource( NULL );
416     }
417 
418 }
419 
420 //------------------------------------------------------------------------
421