1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
25 #include <svl/itemset.hxx>
26 #include <editeng/editdata.hxx>
27 #include <editeng/outliner.hxx>
28 #include <svx/svdmodel.hxx>
29 #include <svx/svdobj.hxx>
30 #include <svx/svdpool.hxx>
33 // Project-local header
36 #include "AccessibleEmptyEditSource.hxx"
37 #include <svx/unoshtxt.hxx>
39 namespace accessibility
43 /** This class simply wraps a SvxTextEditSource, forwarding all
44 methods except the GetBroadcaster() call
46 class AccessibleProxyEditSource_Impl
: public SvxEditSource
49 /** Construct AccessibleEmptyEditSource_Impl
53 Proxy broadcaster to allow seamless flipping of edit source implementations. ProxyEditSource and EmptyEditSource
55 AccessibleProxyEditSource_Impl( SdrObject
& rObj
,
57 const OutputDevice
& rViewWindow
);
59 // from the SvxEditSource interface
60 SvxTextForwarder
* GetTextForwarder() override
;
61 SvxViewForwarder
* GetViewForwarder() override
;
62 SvxEditViewForwarder
* GetEditViewForwarder( bool bCreate
= false ) override
;
64 std::unique_ptr
<SvxEditSource
> Clone() const override
;
66 void UpdateData() override
;
68 SfxBroadcaster
& GetBroadcaster() const override
;
71 SvxTextEditSource maEditSource
;
75 /** Dummy class, faking exactly one empty paragraph for EditEngine accessibility
77 class AccessibleEmptyEditSource_Impl
: public SvxEditSource
, public SvxViewForwarder
, public SvxTextForwarder
, public SfxBroadcaster
81 AccessibleEmptyEditSource_Impl() {}
84 SvxTextForwarder
* GetTextForwarder() override
{ return this; }
85 SvxViewForwarder
* GetViewForwarder() override
{ return this; }
86 std::unique_ptr
<SvxEditSource
> Clone() const override
{ return nullptr; }
87 void UpdateData() override
{}
88 SfxBroadcaster
& GetBroadcaster() const override
{ return *const_cast<AccessibleEmptyEditSource_Impl
*>(this); }
91 sal_Int32
GetParagraphCount() const override
{ return 1; }
92 sal_Int32
GetTextLen( sal_Int32
/*nParagraph*/ ) const override
{ return 0; }
93 OUString
GetText( const ESelection
& /*rSel*/ ) const override
{ return OUString(); }
94 SfxItemSet
GetAttribs( const ESelection
& /*rSel*/, EditEngineAttribs
/*nOnlyHardAttrib*/ = EditEngineAttribs::All
) const override
96 // AW: Very dangerous: The former implementation used a SfxItemPool created on the
97 // fly which of course was deleted again ASAP. Thus, the returned SfxItemSet was using
98 // a deleted Pool by design.
99 return SfxItemSet(SdrObject::GetGlobalDrawObjectItemPool());
101 SfxItemSet
GetParaAttribs( sal_Int32
/*nPara*/ ) const override
{ return GetAttribs(ESelection()); }
102 void SetParaAttribs( sal_Int32
/*nPara*/, const SfxItemSet
& /*rSet*/ ) override
{}
103 void RemoveAttribs( const ESelection
& /*rSelection*/ ) override
{}
104 void GetPortions( sal_Int32
/*nPara*/, std::vector
<sal_Int32
>& /*rList*/ ) const override
{}
106 SfxItemState
GetItemState( const ESelection
& /*rSel*/, sal_uInt16
/*nWhich*/ ) const override
{ return SfxItemState::UNKNOWN
; }
107 SfxItemState
GetItemState( sal_Int32
/*nPara*/, sal_uInt16
/*nWhich*/ ) const override
{ return SfxItemState::UNKNOWN
; }
109 SfxItemPool
* GetPool() const override
{ return nullptr; }
111 void QuickInsertText( const OUString
& /*rText*/, const ESelection
& /*rSel*/ ) override
{}
112 void QuickInsertField( const SvxFieldItem
& /*rFld*/, const ESelection
& /*rSel*/ ) override
{}
113 void QuickSetAttribs( const SfxItemSet
& /*rSet*/, const ESelection
& /*rSel*/ ) override
{}
114 void QuickInsertLineBreak( const ESelection
& /*rSel*/ ) override
{}
116 const SfxItemSet
* GetEmptyItemSetPtr() override
{ return nullptr; }
118 void AppendParagraph() override
{}
119 sal_Int32
AppendTextPortion( sal_Int32
/*nPara*/, const OUString
& /*rText*/, const SfxItemSet
& /*rSet*/ ) override
{ return 0; }
122 void CopyText(const SvxTextForwarder
& ) override
{}
124 OUString
CalcFieldValue( const SvxFieldItem
& /*rField*/, sal_Int32
/*nPara*/, sal_Int32
/*nPos*/, std::optional
<Color
>& /*rpTxtColor*/, std::optional
<Color
>& /*rpFldColor*/ ) override
128 void FieldClicked( const SvxFieldItem
& ) override
{}
130 bool IsValid() const override
{ return true; }
132 LanguageType
GetLanguage( sal_Int32
, sal_Int32
) const override
{ return LANGUAGE_DONTKNOW
; }
133 sal_Int32
GetFieldCount( sal_Int32
) const override
{ return 0; }
134 EFieldInfo
GetFieldInfo( sal_Int32
, sal_uInt16
) const override
{ return EFieldInfo(); }
135 EBulletInfo
GetBulletInfo( sal_Int32
) const override
{ return EBulletInfo(); }
136 tools::Rectangle
GetCharBounds( sal_Int32
, sal_Int32
) const override
{ return tools::Rectangle(); }
137 tools::Rectangle
GetParaBounds( sal_Int32
) const override
{ return tools::Rectangle(); }
138 MapMode
GetMapMode() const override
{ return MapMode(); }
139 OutputDevice
* GetRefDevice() const override
{ return nullptr; }
140 bool GetIndexAtPoint( const Point
&, sal_Int32
&, sal_Int32
& ) const override
{ return false; }
141 bool GetWordIndices( sal_Int32
, sal_Int32
, sal_Int32
&, sal_Int32
& ) const override
{ return false; }
142 bool GetAttributeRun( sal_Int32
&, sal_Int32
&, sal_Int32
, sal_Int32
, bool ) const override
{ return false; }
143 sal_Int32
GetLineCount( sal_Int32 nPara
) const override
{ return nPara
== 0 ? 1 : 0; }
144 sal_Int32
GetLineLen( sal_Int32
, sal_Int32
) const override
{ return 0; }
145 void GetLineBoundaries( /*out*/sal_Int32
& rStart
, /*out*/sal_Int32
& rEnd
, sal_Int32
/*nParagraph*/, sal_Int32
/*nLine*/ ) const override
{ rStart
= rEnd
= 0; }
146 sal_Int32
GetLineNumberAtIndex( sal_Int32
/*nPara*/, sal_Int32
/*nIndex*/ ) const override
{ return 0; }
148 // the following two methods would, strictly speaking, require
149 // a switch to a real EditSource, too. Fortunately, the
150 // AccessibleEditableTextPara implementation currently always
151 // calls GetEditViewForwarder(true) before doing
152 // changes. Thus, we rely on this behaviour here (problem
153 // when that changes: via accessibility API, it would no
154 // longer be possible to enter text in previously empty
156 bool Delete( const ESelection
& ) override
{ return false; }
157 bool InsertText( const OUString
&, const ESelection
& ) override
{ return false; }
158 bool QuickFormatDoc( bool ) override
{ return true; }
159 sal_Int16
GetDepth( sal_Int32
) const override
{ return -1; }
160 bool SetDepth( sal_Int32
, sal_Int16
) override
{ return true; }
162 Point
LogicToPixel( const Point
& rPoint
, const MapMode
& /*rMapMode*/ ) const override
{ return rPoint
; }
163 Point
PixelToLogic( const Point
& rPoint
, const MapMode
& /*rMapMode*/ ) const override
{ return rPoint
; }
169 // Implementing AccessibleProxyEditSource_Impl
172 AccessibleProxyEditSource_Impl::AccessibleProxyEditSource_Impl( SdrObject
& rObj
,
174 const OutputDevice
& rViewWindow
) :
175 maEditSource( rObj
, nullptr, rView
, rViewWindow
)
179 SvxTextForwarder
* AccessibleProxyEditSource_Impl::GetTextForwarder()
181 return maEditSource
.GetTextForwarder();
184 SvxViewForwarder
* AccessibleProxyEditSource_Impl::GetViewForwarder()
186 return maEditSource
.GetViewForwarder();
189 SvxEditViewForwarder
* AccessibleProxyEditSource_Impl::GetEditViewForwarder( bool bCreate
)
191 return maEditSource
.GetEditViewForwarder( bCreate
);
194 std::unique_ptr
<SvxEditSource
> AccessibleProxyEditSource_Impl::Clone() const
196 return maEditSource
.Clone();
199 void AccessibleProxyEditSource_Impl::UpdateData()
201 maEditSource
.UpdateData();
204 SfxBroadcaster
& AccessibleProxyEditSource_Impl::GetBroadcaster() const
206 return maEditSource
.GetBroadcaster();
210 // Implementing AccessibleEmptyEditSource
213 AccessibleEmptyEditSource::AccessibleEmptyEditSource( SdrObject
& rObj
,
215 const OutputDevice
& rViewWindow
) :
216 mpEditSource( new AccessibleEmptyEditSource_Impl() ),
219 mrViewWindow(rViewWindow
),
220 mbEditSourceEmpty( true )
222 StartListening( mrObj
.getSdrModelFromSdrObject() );
225 AccessibleEmptyEditSource::~AccessibleEmptyEditSource()
227 if( !mbEditSourceEmpty
)
229 // deregister as listener
231 EndListening( mpEditSource
->GetBroadcaster() );
235 EndListening( mrObj
.getSdrModelFromSdrObject() );
239 SvxTextForwarder
* AccessibleEmptyEditSource::GetTextForwarder()
244 return mpEditSource
->GetTextForwarder();
247 SvxViewForwarder
* AccessibleEmptyEditSource::GetViewForwarder()
252 return mpEditSource
->GetViewForwarder();
255 void AccessibleEmptyEditSource::Switch2ProxyEditSource()
257 // deregister EmptyEditSource model listener
258 EndListening( mrObj
.getSdrModelFromSdrObject() );
260 ::std::unique_ptr
< SvxEditSource
> pProxySource( new AccessibleProxyEditSource_Impl(mrObj
, mrView
, mrViewWindow
) );
261 mpEditSource
.swap(pProxySource
);
263 // register as listener
264 StartListening( mpEditSource
->GetBroadcaster() );
266 // we've irrevocably a full EditSource now.
267 mbEditSourceEmpty
= false;
270 SvxEditViewForwarder
* AccessibleEmptyEditSource::GetEditViewForwarder( bool bCreate
)
275 // switch edit source, if not yet done
276 if( mbEditSourceEmpty
&& bCreate
)
277 Switch2ProxyEditSource();
279 return mpEditSource
->GetEditViewForwarder( bCreate
);
282 std::unique_ptr
<SvxEditSource
> AccessibleEmptyEditSource::Clone() const
287 return mpEditSource
->Clone();
290 void AccessibleEmptyEditSource::UpdateData()
293 mpEditSource
->UpdateData();
296 SfxBroadcaster
& AccessibleEmptyEditSource::GetBroadcaster() const
298 return *const_cast<AccessibleEmptyEditSource
*>(this);
301 void AccessibleEmptyEditSource::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
303 const SdrHint
* pSdrHint
= ( rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
? static_cast<const SdrHint
*>(&rHint
) : nullptr );
305 if( pSdrHint
&& pSdrHint
->GetKind() == SdrHintKind::BeginEdit
&&
306 &mrObj
== pSdrHint
->GetObject() && mpEditSource
)
308 // switch edit source, if not yet done. This is necessary
309 // to become a full-fledged EditSource the first time a
310 // user start entering text in a previously empty object.
311 if( mbEditSourceEmpty
)
312 Switch2ProxyEditSource();
314 else if (pSdrHint
&& pSdrHint
->GetObject()!=nullptr)
316 // When the SdrObject just got a para outliner object then
317 // switch the edit source.
318 if (pSdrHint
->GetObject()->GetOutlinerParaObject() != nullptr)
319 Switch2ProxyEditSource();
326 } // end of namespace accessibility
329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */