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 OUString
GetStyleSheet(sal_Int32
/*nPara*/) const override
{ return OUString(); }
107 void SetStyleSheet(sal_Int32
/*nPara*/, const OUString
& /*rStyleName*/) override
{}
109 SfxItemState
GetItemState( const ESelection
& /*rSel*/, sal_uInt16
/*nWhich*/ ) const override
{ return SfxItemState::UNKNOWN
; }
110 SfxItemState
GetItemState( sal_Int32
/*nPara*/, sal_uInt16
/*nWhich*/ ) const override
{ return SfxItemState::UNKNOWN
; }
112 SfxItemPool
* GetPool() const override
{ return nullptr; }
114 void QuickInsertText( const OUString
& /*rText*/, const ESelection
& /*rSel*/ ) override
{}
115 void QuickInsertField( const SvxFieldItem
& /*rFld*/, const ESelection
& /*rSel*/ ) override
{}
116 void QuickSetAttribs( const SfxItemSet
& /*rSet*/, const ESelection
& /*rSel*/ ) override
{}
117 void QuickInsertLineBreak( const ESelection
& /*rSel*/ ) override
{}
119 const SfxItemSet
* GetEmptyItemSetPtr() override
{ return nullptr; }
121 void AppendParagraph() override
{}
122 sal_Int32
AppendTextPortion( sal_Int32
/*nPara*/, const OUString
& /*rText*/, const SfxItemSet
& /*rSet*/ ) override
{ return 0; }
125 void CopyText(const SvxTextForwarder
& ) override
{}
127 OUString
CalcFieldValue( const SvxFieldItem
& /*rField*/, sal_Int32
/*nPara*/, sal_Int32
/*nPos*/, std::optional
<Color
>& /*rpTxtColor*/, std::optional
<Color
>& /*rpFldColor*/, std::optional
<FontLineStyle
>& /*rpFldLineStyle*/ ) override
131 void FieldClicked( const SvxFieldItem
& ) override
{}
133 bool IsValid() const override
{ return true; }
135 LanguageType
GetLanguage( sal_Int32
, sal_Int32
) const override
{ return LANGUAGE_DONTKNOW
; }
136 std::vector
<EFieldInfo
> GetFieldInfo( sal_Int32
) const override
{ return {}; }
137 EBulletInfo
GetBulletInfo( sal_Int32
) const override
{ return EBulletInfo(); }
138 tools::Rectangle
GetCharBounds( sal_Int32
, sal_Int32
) const override
{ return tools::Rectangle(); }
139 tools::Rectangle
GetParaBounds( sal_Int32
) const override
{ return tools::Rectangle(); }
140 MapMode
GetMapMode() const override
{ return MapMode(); }
141 OutputDevice
* GetRefDevice() const override
{ return nullptr; }
142 bool GetIndexAtPoint( const Point
&, sal_Int32
&, sal_Int32
& ) const override
{ return false; }
143 bool GetWordIndices( sal_Int32
, sal_Int32
, sal_Int32
&, sal_Int32
& ) const override
{ return false; }
144 bool GetAttributeRun( sal_Int32
&, sal_Int32
&, sal_Int32
, sal_Int32
, bool ) const override
{ return false; }
145 sal_Int32
GetLineCount( sal_Int32 nPara
) const override
{ return nPara
== 0 ? 1 : 0; }
146 sal_Int32
GetLineLen( sal_Int32
, sal_Int32
) const override
{ return 0; }
147 void GetLineBoundaries( /*out*/sal_Int32
& rStart
, /*out*/sal_Int32
& rEnd
, sal_Int32
/*nParagraph*/, sal_Int32
/*nLine*/ ) const override
{ rStart
= rEnd
= 0; }
148 sal_Int32
GetLineNumberAtIndex( sal_Int32
/*nPara*/, sal_Int32
/*nIndex*/ ) const override
{ return 0; }
150 // the following two methods would, strictly speaking, require
151 // a switch to a real EditSource, too. Fortunately, the
152 // AccessibleEditableTextPara implementation currently always
153 // calls GetEditViewForwarder(true) before doing
154 // changes. Thus, we rely on this behaviour here (problem
155 // when that changes: via accessibility API, it would no
156 // longer be possible to enter text in previously empty
158 bool Delete( const ESelection
& ) override
{ return false; }
159 bool InsertText( const OUString
&, const ESelection
& ) override
{ return false; }
160 bool QuickFormatDoc( bool ) override
{ return true; }
161 bool SupportsOutlineDepth() const override
{ return false; }
162 sal_Int16
GetDepth( sal_Int32
) const override
{ return -1; }
163 bool SetDepth( sal_Int32
, sal_Int16
) override
{ return true; }
165 Point
LogicToPixel( const Point
& rPoint
, const MapMode
& /*rMapMode*/ ) const override
{ return rPoint
; }
166 Point
PixelToLogic( const Point
& rPoint
, const MapMode
& /*rMapMode*/ ) const override
{ return rPoint
; }
172 // Implementing AccessibleProxyEditSource_Impl
175 AccessibleProxyEditSource_Impl::AccessibleProxyEditSource_Impl( SdrObject
& rObj
,
177 const OutputDevice
& rViewWindow
) :
178 maEditSource( rObj
, nullptr, rView
, rViewWindow
)
182 SvxTextForwarder
* AccessibleProxyEditSource_Impl::GetTextForwarder()
184 return maEditSource
.GetTextForwarder();
187 SvxViewForwarder
* AccessibleProxyEditSource_Impl::GetViewForwarder()
189 return maEditSource
.GetViewForwarder();
192 SvxEditViewForwarder
* AccessibleProxyEditSource_Impl::GetEditViewForwarder( bool bCreate
)
194 return maEditSource
.GetEditViewForwarder( bCreate
);
197 std::unique_ptr
<SvxEditSource
> AccessibleProxyEditSource_Impl::Clone() const
199 return maEditSource
.Clone();
202 void AccessibleProxyEditSource_Impl::UpdateData()
204 maEditSource
.UpdateData();
207 SfxBroadcaster
& AccessibleProxyEditSource_Impl::GetBroadcaster() const
209 return maEditSource
.GetBroadcaster();
213 // Implementing AccessibleEmptyEditSource
216 AccessibleEmptyEditSource::AccessibleEmptyEditSource( SdrObject
& rObj
,
218 const OutputDevice
& rViewWindow
) :
219 mpEditSource( new AccessibleEmptyEditSource_Impl() ),
222 mrViewWindow(rViewWindow
),
223 mbEditSourceEmpty( true )
225 StartListening( mrObj
.getSdrModelFromSdrObject() );
228 AccessibleEmptyEditSource::~AccessibleEmptyEditSource()
230 if( !mbEditSourceEmpty
)
232 // deregister as listener
234 EndListening( mpEditSource
->GetBroadcaster() );
238 EndListening( mrObj
.getSdrModelFromSdrObject() );
242 SvxTextForwarder
* AccessibleEmptyEditSource::GetTextForwarder()
247 return mpEditSource
->GetTextForwarder();
250 SvxViewForwarder
* AccessibleEmptyEditSource::GetViewForwarder()
255 return mpEditSource
->GetViewForwarder();
258 void AccessibleEmptyEditSource::Switch2ProxyEditSource()
260 // deregister EmptyEditSource model listener
261 EndListening( mrObj
.getSdrModelFromSdrObject() );
263 ::std::unique_ptr
< SvxEditSource
> pProxySource( new AccessibleProxyEditSource_Impl(mrObj
, mrView
, mrViewWindow
) );
264 mpEditSource
.swap(pProxySource
);
266 // register as listener
267 StartListening( mpEditSource
->GetBroadcaster() );
269 // we've irrevocably a full EditSource now.
270 mbEditSourceEmpty
= false;
273 SvxEditViewForwarder
* AccessibleEmptyEditSource::GetEditViewForwarder( bool bCreate
)
278 // switch edit source, if not yet done
279 if( mbEditSourceEmpty
&& bCreate
)
280 Switch2ProxyEditSource();
282 return mpEditSource
->GetEditViewForwarder( bCreate
);
285 std::unique_ptr
<SvxEditSource
> AccessibleEmptyEditSource::Clone() const
290 return mpEditSource
->Clone();
293 void AccessibleEmptyEditSource::UpdateData()
296 mpEditSource
->UpdateData();
299 SfxBroadcaster
& AccessibleEmptyEditSource::GetBroadcaster() const
301 return *const_cast<AccessibleEmptyEditSource
*>(this);
304 void AccessibleEmptyEditSource::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
306 const SdrHint
* pSdrHint
= ( rHint
.GetId() == SfxHintId::ThisIsAnSdrHint
? static_cast<const SdrHint
*>(&rHint
) : nullptr );
308 if( pSdrHint
&& pSdrHint
->GetKind() == SdrHintKind::BeginEdit
&&
309 &mrObj
== pSdrHint
->GetObject() && mpEditSource
)
311 // switch edit source, if not yet done. This is necessary
312 // to become a full-fledged EditSource the first time a
313 // user start entering text in a previously empty object.
314 if( mbEditSourceEmpty
)
315 Switch2ProxyEditSource();
317 else if (pSdrHint
&& pSdrHint
->GetObject()!=nullptr)
319 // When the SdrObject just got a para outliner object then
320 // switch the edit source.
321 if (pSdrHint
->GetObject()->GetOutlinerParaObject() != nullptr)
322 Switch2ProxyEditSource();
329 } // end of namespace accessibility
332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */