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