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_svx.hxx"
30 
31 //------------------------------------------------------------------------
32 //
33 // Global header
34 //
35 //------------------------------------------------------------------------
36 #include <svl/itemset.hxx>
37 #include <editeng/editdata.hxx>
38 #include <editeng/outliner.hxx>
39 #include <svx/svdmodel.hxx>
40 #include <svx/svdobj.hxx>
41 #include <svx/svdpool.hxx>
42 
43 //------------------------------------------------------------------------
44 //
45 // Project-local header
46 //
47 //------------------------------------------------------------------------
48 
49 #include "AccessibleEmptyEditSource.hxx"
50 #include <svx/unoshtxt.hxx>
51 
52 namespace accessibility
53 {
54 
55     /** This class simply wraps a SvxTextEditSource, forwarding all
56         methods except the GetBroadcaster() call
57      */
58     class AccessibleProxyEditSource_Impl : public SvxEditSource
59     {
60     public:
61         /** Construct AccessibleEmptyEditSource_Impl
62 
63         	@param rBrdCast
64 
65             Proxy broadcaster to allow seamless flipping of edit source implementations. ProxyEditSource and EmptyEditSource
66          */
67         AccessibleProxyEditSource_Impl( SdrObject& 		rObj,
68                                         SdrView& 		rView,
69                                         const Window& 	rViewWindow );
70         ~AccessibleProxyEditSource_Impl();
71 
72         // from the SvxEditSource interface
73         SvxTextForwarder*		GetTextForwarder();
74         SvxViewForwarder*		GetViewForwarder();
75         SvxEditViewForwarder*	GetEditViewForwarder( sal_Bool bCreate = sal_False );
76 
77         SvxEditSource*			Clone() const;
78 
79         void					UpdateData();
80 
81         SfxBroadcaster&			GetBroadcaster() const;
82 
83     private:
84         SvxTextEditSource		maEditSource;
85 
86     };
87 
88     /** Dummy class, faking exactly one empty paragraph for EditEngine accessibility
89      */
90     class AccessibleEmptyEditSource_Impl : public SvxEditSource, public SvxViewForwarder, public SvxTextForwarder, public SfxBroadcaster
91     {
92     public:
93 
94         AccessibleEmptyEditSource_Impl() {}
95         ~AccessibleEmptyEditSource_Impl() {}
96 
97         // from the SfxListener interface
98         void					Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
99 
100         // SvxEditSource
101         SvxTextForwarder*		GetTextForwarder() { return this; }
102         SvxViewForwarder*		GetViewForwarder() { return this; }
103         SvxEditSource*			Clone() const { return NULL; }
104         void					UpdateData() {}
105         SfxBroadcaster&			GetBroadcaster() const { return *(const_cast<AccessibleEmptyEditSource_Impl*>(this)); }
106 
107         // SvxTextForwarder
108         sal_uInt16			GetParagraphCount() const { return 1; }
109         sal_uInt16			GetTextLen( sal_uInt16 /*nParagraph*/ ) const { return 0; }
110         String			GetText( const ESelection& /*rSel*/ ) const { return String(); }
111         SfxItemSet		GetAttribs( const ESelection& /*rSel*/, sal_Bool /*bOnlyHardAttrib*/ = 0 ) const
112         {
113             // AW: Very dangerous: The former implementation used a SfxItemPool created on the
114             // fly which of course was deleted again ASAP. Thus, the returned SfxItemSet was using
115             // a deleted Pool by design.
116             return SfxItemSet(SdrObject::GetGlobalDrawObjectItemPool());
117         }
118         SfxItemSet		GetParaAttribs( sal_uInt16 /*nPara*/ ) const { return GetAttribs(ESelection()); }
119         void			SetParaAttribs( sal_uInt16 /*nPara*/, const SfxItemSet& /*rSet*/ ) {}
120         void            RemoveAttribs( const ESelection& /*rSelection*/, sal_Bool /*bRemoveParaAttribs*/, sal_uInt16 /*nWhich*/ ){}
121         void			GetPortions( sal_uInt16 /*nPara*/, SvUShorts& /*rList*/ ) const {}
122 
123         sal_uInt16			GetItemState( const ESelection& /*rSel*/, sal_uInt16 /*nWhich*/ ) const { return 0; }
124         sal_uInt16			GetItemState( sal_uInt16 /*nPara*/, sal_uInt16 /*nWhich*/ ) const { return 0; }
125 
126         SfxItemPool* 	GetPool() const { return NULL; }
127 
128         void			QuickInsertText( const String& /*rText*/, const ESelection& /*rSel*/ ) {}
129         void			QuickInsertField( const SvxFieldItem& /*rFld*/, const ESelection& /*rSel*/ ) {}
130         void			QuickSetAttribs( const SfxItemSet& /*rSet*/, const ESelection& /*rSel*/ ) {}
131         void			QuickInsertLineBreak( const ESelection& /*rSel*/ ) {}
132 
133         const SfxItemSet * GetEmptyItemSetPtr() { return 0; }
134 
135         void        AppendParagraph() {}
136         xub_StrLen  AppendTextPortion( sal_uInt16 /*nPara*/, const String & /*rText*/, const SfxItemSet & /*rSet*/ ) { return 0; }
137 
138         //XTextCopy
139         void        CopyText(const SvxTextForwarder& ){}
140 
141         XubString		CalcFieldValue( const SvxFieldItem& /*rField*/, sal_uInt16 /*nPara*/, sal_uInt16 /*nPos*/, Color*& /*rpTxtColor*/, Color*& /*rpFldColor*/ )
142         {
143             return  XubString();
144         }
145 	    void            FieldClicked( const SvxFieldItem&, sal_uInt16, xub_StrLen ) {;}
146 
147         sal_Bool			IsValid() const { return sal_True; }
148 
149         void 			SetNotifyHdl( const Link& ) {}
150         LanguageType 	GetLanguage( sal_uInt16, sal_uInt16 ) const { return LANGUAGE_DONTKNOW; }
151         sal_uInt16			GetFieldCount( sal_uInt16 ) const { return 0; }
152         EFieldInfo		GetFieldInfo( sal_uInt16, sal_uInt16 ) const { return EFieldInfo(); }
153         EBulletInfo     GetBulletInfo( sal_uInt16 ) const { return EBulletInfo(); }
154         Rectangle		GetCharBounds( sal_uInt16, sal_uInt16 ) const { return Rectangle(); }
155         Rectangle		GetParaBounds( sal_uInt16 ) const { return Rectangle(); }
156         MapMode		 	GetMapMode() const { return MapMode(); }
157         OutputDevice*	GetRefDevice() const { return NULL; }
158         sal_Bool		GetIndexAtPoint( const Point&, sal_uInt16&, sal_uInt16& ) const { return sal_False; }
159         sal_Bool		GetWordIndices( sal_uInt16, sal_uInt16, sal_uInt16&, sal_uInt16& ) const { return sal_False; }
160         sal_Bool 		GetAttributeRun( sal_uInt16&, sal_uInt16&, sal_uInt16, sal_uInt16 ) const { return sal_False; }
161         sal_uInt16			GetLineCount( sal_uInt16 nPara ) const { return nPara == 0 ? 1 : 0; }
162         sal_uInt16			GetLineLen( sal_uInt16, sal_uInt16 ) const { return 0; }
163         void            GetLineBoundaries( /*out*/sal_uInt16 & rStart, /*out*/sal_uInt16 & rEnd, sal_uInt16 /*nParagraph*/, sal_uInt16 /*nLine*/ ) const  { rStart = rEnd = 0; }
164         sal_uInt16          GetLineNumberAtIndex( sal_uInt16 /*nPara*/, sal_uInt16 /*nIndex*/ ) const   { return 0; }
165 
166         // the following two methods would, strictly speaking, require
167         // a switch to a real EditSource, too. Fortunately, the
168         // AccessibleEditableTextPara implementation currently always
169         // calls GetEditViewForwarder(true) before doing
170         // changes. Thus, we rely on this behabviour here (problem
171         // when that changes: via accessibility API, it would no
172         // longer be possible to enter text in previously empty
173         // shapes).
174         sal_Bool		Delete( const ESelection& ) { return sal_False; }
175         sal_Bool		InsertText( const String&, const ESelection& ) { return sal_False; }
176         sal_Bool		QuickFormatDoc( sal_Bool ) { return sal_True; }
177         sal_Int16		GetDepth( sal_uInt16 ) const { return -1; }
178         sal_Bool		SetDepth( sal_uInt16, sal_Int16 ) { return sal_True; }
179 
180         Rectangle		GetVisArea() const { return Rectangle(); }
181         Point			LogicToPixel( const Point& rPoint, const MapMode& /*rMapMode*/ ) const { return rPoint; }
182         Point			PixelToLogic( const Point& rPoint, const MapMode& /*rMapMode*/ ) const { return rPoint; }
183 
184     };
185 
186     // -------------------------------------------------------------------------
187     // Implementing AccessibleProxyEditSource_Impl
188     // -------------------------------------------------------------------------
189 
190     AccessibleProxyEditSource_Impl::AccessibleProxyEditSource_Impl( SdrObject& 		rObj,
191                                                                     SdrView& 		rView,
192                                                                     const Window& 	rViewWindow ) :
193         maEditSource( rObj, 0, rView, rViewWindow )
194     {
195     }
196 
197     AccessibleProxyEditSource_Impl::~AccessibleProxyEditSource_Impl()
198     {
199     }
200 
201     SvxTextForwarder* AccessibleProxyEditSource_Impl::GetTextForwarder()
202     {
203         return maEditSource.GetTextForwarder();
204     }
205 
206     SvxViewForwarder* AccessibleProxyEditSource_Impl::GetViewForwarder()
207     {
208         return maEditSource.GetViewForwarder();
209     }
210 
211     SvxEditViewForwarder* AccessibleProxyEditSource_Impl::GetEditViewForwarder( sal_Bool bCreate )
212     {
213         return maEditSource.GetEditViewForwarder( bCreate );
214     }
215 
216     SvxEditSource* AccessibleProxyEditSource_Impl::Clone() const
217     {
218         return maEditSource.Clone();
219     }
220 
221     void AccessibleProxyEditSource_Impl::UpdateData()
222     {
223         maEditSource.UpdateData();
224     }
225 
226     SfxBroadcaster&	AccessibleProxyEditSource_Impl::GetBroadcaster() const
227     {
228         return maEditSource.GetBroadcaster();
229     }
230 
231 
232     // -------------------------------------------------------------------------
233     // Implementing AccessibleEmptyEditSource
234     // -------------------------------------------------------------------------
235 
236     AccessibleEmptyEditSource::AccessibleEmptyEditSource( SdrObject& 	rObj,
237                                                           SdrView& 		rView,
238                                                           const Window& rViewWindow ) :
239         mpEditSource( new AccessibleEmptyEditSource_Impl() ),
240         mrObj(rObj),
241         mrView(rView),
242         mrViewWindow(rViewWindow),
243         mbEditSourceEmpty( true )
244     {
245         if( mrObj.GetModel() )
246             StartListening( *mrObj.GetModel() );
247     }
248 
249     AccessibleEmptyEditSource::~AccessibleEmptyEditSource()
250     {
251         if( !mbEditSourceEmpty )
252         {
253             // deregister as listener
254             if( mpEditSource.get() )
255                 EndListening( mpEditSource->GetBroadcaster() );
256         }
257         else
258         {
259             if( mrObj.GetModel() )
260                 EndListening( *mrObj.GetModel() );
261         }
262     }
263 
264     SvxTextForwarder* AccessibleEmptyEditSource::GetTextForwarder()
265     {
266         if( !mpEditSource.get() )
267             return NULL;
268 
269         return mpEditSource->GetTextForwarder();
270     }
271 
272     SvxViewForwarder* AccessibleEmptyEditSource::GetViewForwarder()
273     {
274         if( !mpEditSource.get() )
275             return NULL;
276 
277         return mpEditSource->GetViewForwarder();
278     }
279 
280     void AccessibleEmptyEditSource::Switch2ProxyEditSource()
281     {
282         // deregister EmptyEditSource model listener
283         if( mrObj.GetModel() )
284             EndListening( *mrObj.GetModel() );
285 
286         ::std::auto_ptr< SvxEditSource > pProxySource( new AccessibleProxyEditSource_Impl(mrObj, mrView, mrViewWindow) );
287         ::std::auto_ptr< SvxEditSource > tmp = mpEditSource;
288         mpEditSource = pProxySource;
289         pProxySource = tmp;
290 
291         // register as listener
292         StartListening( mpEditSource->GetBroadcaster() );
293 
294         // we've irrevocably a full EditSource now.
295         mbEditSourceEmpty = false;
296     }
297 
298     SvxEditViewForwarder* AccessibleEmptyEditSource::GetEditViewForwarder( sal_Bool bCreate )
299     {
300         if( !mpEditSource.get() )
301             return NULL;
302 
303         // switch edit source, if not yet done
304         if( mbEditSourceEmpty && bCreate )
305             Switch2ProxyEditSource();
306 
307         return mpEditSource->GetEditViewForwarder( bCreate );
308     }
309 
310     SvxEditSource* AccessibleEmptyEditSource::Clone() const
311     {
312         if( !mpEditSource.get() )
313             return NULL;
314 
315         return mpEditSource->Clone();
316     }
317 
318     void AccessibleEmptyEditSource::UpdateData()
319     {
320         if( mpEditSource.get() )
321             mpEditSource->UpdateData();
322     }
323 
324     SfxBroadcaster&	AccessibleEmptyEditSource::GetBroadcaster() const
325     {
326         return *(const_cast<AccessibleEmptyEditSource*>(this));
327     }
328 
329     void AccessibleEmptyEditSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
330     {
331         const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint );
332 
333         if( pSdrHint && pSdrHint->GetKind() == HINT_BEGEDIT &&
334             &mrObj == pSdrHint->GetObject() && mpEditSource.get() )
335         {
336             // switch edit source, if not yet done. This is necessary
337             // to become a full-fledged EditSource the first time a
338             // user start entering text in a previously empty object.
339             if( mbEditSourceEmpty )
340                 Switch2ProxyEditSource();
341         }
342         else if (pSdrHint && pSdrHint->GetObject()!=NULL)
343         {
344             // When the SdrObject just got a para outliner object then
345             // switch the edit source.
346             if (pSdrHint->GetObject()->GetOutlinerParaObject() != NULL)
347                 Switch2ProxyEditSource();
348         }
349 
350         // forward messages
351         Broadcast( rHint );
352     }
353 
354 } // end of namespace accessibility
355 
356 //------------------------------------------------------------------------
357