summaryrefslogtreecommitdiffstats
path: root/svx/source/accessibility/AccessibleEmptyEditSource.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--svx/source/accessibility/AccessibleEmptyEditSource.cxx329
1 files changed, 329 insertions, 0 deletions
diff --git a/svx/source/accessibility/AccessibleEmptyEditSource.cxx b/svx/source/accessibility/AccessibleEmptyEditSource.cxx
new file mode 100644
index 000000000..e1426d239
--- /dev/null
+++ b/svx/source/accessibility/AccessibleEmptyEditSource.cxx
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+// Global header
+
+
+#include <memory>
+#include <svl/itemset.hxx>
+#include <editeng/editdata.hxx>
+#include <editeng/outliner.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpool.hxx>
+
+
+// Project-local header
+
+
+#include "AccessibleEmptyEditSource.hxx"
+#include <svx/unoshtxt.hxx>
+
+namespace accessibility
+{
+ namespace {
+
+ /** This class simply wraps a SvxTextEditSource, forwarding all
+ methods except the GetBroadcaster() call
+ */
+ class AccessibleProxyEditSource_Impl : public SvxEditSource
+ {
+ public:
+ /** Construct AccessibleEmptyEditSource_Impl
+
+ @param rBrdCast
+
+ Proxy broadcaster to allow seamless flipping of edit source implementations. ProxyEditSource and EmptyEditSource
+ */
+ AccessibleProxyEditSource_Impl( SdrObject& rObj,
+ SdrView& rView,
+ const OutputDevice& rViewWindow );
+
+ // from the SvxEditSource interface
+ SvxTextForwarder* GetTextForwarder() override;
+ SvxViewForwarder* GetViewForwarder() override;
+ SvxEditViewForwarder* GetEditViewForwarder( bool bCreate = false ) override;
+
+ std::unique_ptr<SvxEditSource> Clone() const override;
+
+ void UpdateData() override;
+
+ SfxBroadcaster& GetBroadcaster() const override;
+
+ private:
+ SvxTextEditSource maEditSource;
+
+ };
+
+ /** Dummy class, faking exactly one empty paragraph for EditEngine accessibility
+ */
+ class AccessibleEmptyEditSource_Impl : public SvxEditSource, public SvxViewForwarder, public SvxTextForwarder, public SfxBroadcaster
+ {
+ public:
+
+ AccessibleEmptyEditSource_Impl() {}
+
+ // SvxEditSource
+ SvxTextForwarder* GetTextForwarder() override { return this; }
+ SvxViewForwarder* GetViewForwarder() override { return this; }
+ std::unique_ptr<SvxEditSource> Clone() const override { return nullptr; }
+ void UpdateData() override {}
+ SfxBroadcaster& GetBroadcaster() const override { return *const_cast<AccessibleEmptyEditSource_Impl*>(this); }
+
+ // SvxTextForwarder
+ sal_Int32 GetParagraphCount() const override { return 1; }
+ sal_Int32 GetTextLen( sal_Int32 /*nParagraph*/ ) const override { return 0; }
+ OUString GetText( const ESelection& /*rSel*/ ) const override { return OUString(); }
+ SfxItemSet GetAttribs( const ESelection& /*rSel*/, EditEngineAttribs /*nOnlyHardAttrib*/ = EditEngineAttribs::All ) const override
+ {
+ // AW: Very dangerous: The former implementation used a SfxItemPool created on the
+ // fly which of course was deleted again ASAP. Thus, the returned SfxItemSet was using
+ // a deleted Pool by design.
+ return SfxItemSet(SdrObject::GetGlobalDrawObjectItemPool());
+ }
+ SfxItemSet GetParaAttribs( sal_Int32 /*nPara*/ ) const override { return GetAttribs(ESelection()); }
+ void SetParaAttribs( sal_Int32 /*nPara*/, const SfxItemSet& /*rSet*/ ) override {}
+ void RemoveAttribs( const ESelection& /*rSelection*/ ) override {}
+ void GetPortions( sal_Int32 /*nPara*/, std::vector<sal_Int32>& /*rList*/ ) const override {}
+
+ SfxItemState GetItemState( const ESelection& /*rSel*/, sal_uInt16 /*nWhich*/ ) const override { return SfxItemState::UNKNOWN; }
+ SfxItemState GetItemState( sal_Int32 /*nPara*/, sal_uInt16 /*nWhich*/ ) const override { return SfxItemState::UNKNOWN; }
+
+ SfxItemPool* GetPool() const override { return nullptr; }
+
+ void QuickInsertText( const OUString& /*rText*/, const ESelection& /*rSel*/ ) override {}
+ void QuickInsertField( const SvxFieldItem& /*rFld*/, const ESelection& /*rSel*/ ) override {}
+ void QuickSetAttribs( const SfxItemSet& /*rSet*/, const ESelection& /*rSel*/ ) override {}
+ void QuickInsertLineBreak( const ESelection& /*rSel*/ ) override {}
+
+ const SfxItemSet * GetEmptyItemSetPtr() override { return nullptr; }
+
+ void AppendParagraph() override {}
+ sal_Int32 AppendTextPortion( sal_Int32 /*nPara*/, const OUString & /*rText*/, const SfxItemSet & /*rSet*/ ) override { return 0; }
+
+ //XTextCopy
+ void CopyText(const SvxTextForwarder& ) override {}
+
+ OUString CalcFieldValue( const SvxFieldItem& /*rField*/, sal_Int32 /*nPara*/, sal_Int32 /*nPos*/, std::optional<Color>& /*rpTxtColor*/, std::optional<Color>& /*rpFldColor*/ ) override
+ {
+ return OUString();
+ }
+ void FieldClicked( const SvxFieldItem& ) override {}
+
+ bool IsValid() const override { return true; }
+
+ LanguageType GetLanguage( sal_Int32, sal_Int32 ) const override { return LANGUAGE_DONTKNOW; }
+ sal_Int32 GetFieldCount( sal_Int32 ) const override { return 0; }
+ EFieldInfo GetFieldInfo( sal_Int32, sal_uInt16 ) const override { return EFieldInfo(); }
+ EBulletInfo GetBulletInfo( sal_Int32 ) const override { return EBulletInfo(); }
+ tools::Rectangle GetCharBounds( sal_Int32, sal_Int32 ) const override { return tools::Rectangle(); }
+ tools::Rectangle GetParaBounds( sal_Int32 ) const override { return tools::Rectangle(); }
+ MapMode GetMapMode() const override { return MapMode(); }
+ OutputDevice* GetRefDevice() const override { return nullptr; }
+ bool GetIndexAtPoint( const Point&, sal_Int32&, sal_Int32& ) const override { return false; }
+ bool GetWordIndices( sal_Int32, sal_Int32, sal_Int32&, sal_Int32& ) const override { return false; }
+ bool GetAttributeRun( sal_Int32&, sal_Int32&, sal_Int32, sal_Int32, bool ) const override { return false; }
+ sal_Int32 GetLineCount( sal_Int32 nPara ) const override { return nPara == 0 ? 1 : 0; }
+ sal_Int32 GetLineLen( sal_Int32, sal_Int32 ) const override { return 0; }
+ void GetLineBoundaries( /*out*/sal_Int32 & rStart, /*out*/sal_Int32 & rEnd, sal_Int32 /*nParagraph*/, sal_Int32 /*nLine*/ ) const override { rStart = rEnd = 0; }
+ sal_Int32 GetLineNumberAtIndex( sal_Int32 /*nPara*/, sal_Int32 /*nIndex*/ ) const override { return 0; }
+
+ // the following two methods would, strictly speaking, require
+ // a switch to a real EditSource, too. Fortunately, the
+ // AccessibleEditableTextPara implementation currently always
+ // calls GetEditViewForwarder(true) before doing
+ // changes. Thus, we rely on this behaviour here (problem
+ // when that changes: via accessibility API, it would no
+ // longer be possible to enter text in previously empty
+ // shapes).
+ bool Delete( const ESelection& ) override { return false; }
+ bool InsertText( const OUString&, const ESelection& ) override { return false; }
+ bool QuickFormatDoc( bool ) override { return true; }
+ sal_Int16 GetDepth( sal_Int32 ) const override { return -1; }
+ bool SetDepth( sal_Int32, sal_Int16 ) override { return true; }
+
+ Point LogicToPixel( const Point& rPoint, const MapMode& /*rMapMode*/ ) const override { return rPoint; }
+ Point PixelToLogic( const Point& rPoint, const MapMode& /*rMapMode*/ ) const override { return rPoint; }
+
+ };
+
+ }
+
+ // Implementing AccessibleProxyEditSource_Impl
+
+
+ AccessibleProxyEditSource_Impl::AccessibleProxyEditSource_Impl( SdrObject& rObj,
+ SdrView& rView,
+ const OutputDevice& rViewWindow ) :
+ maEditSource( rObj, nullptr, rView, rViewWindow )
+ {
+ }
+
+ SvxTextForwarder* AccessibleProxyEditSource_Impl::GetTextForwarder()
+ {
+ return maEditSource.GetTextForwarder();
+ }
+
+ SvxViewForwarder* AccessibleProxyEditSource_Impl::GetViewForwarder()
+ {
+ return maEditSource.GetViewForwarder();
+ }
+
+ SvxEditViewForwarder* AccessibleProxyEditSource_Impl::GetEditViewForwarder( bool bCreate )
+ {
+ return maEditSource.GetEditViewForwarder( bCreate );
+ }
+
+ std::unique_ptr<SvxEditSource> AccessibleProxyEditSource_Impl::Clone() const
+ {
+ return maEditSource.Clone();
+ }
+
+ void AccessibleProxyEditSource_Impl::UpdateData()
+ {
+ maEditSource.UpdateData();
+ }
+
+ SfxBroadcaster& AccessibleProxyEditSource_Impl::GetBroadcaster() const
+ {
+ return maEditSource.GetBroadcaster();
+ }
+
+
+ // Implementing AccessibleEmptyEditSource
+
+
+ AccessibleEmptyEditSource::AccessibleEmptyEditSource( SdrObject& rObj,
+ SdrView& rView,
+ const OutputDevice& rViewWindow ) :
+ mpEditSource( new AccessibleEmptyEditSource_Impl() ),
+ mrObj(rObj),
+ mrView(rView),
+ mrViewWindow(rViewWindow),
+ mbEditSourceEmpty( true )
+ {
+ StartListening( mrObj.getSdrModelFromSdrObject() );
+ }
+
+ AccessibleEmptyEditSource::~AccessibleEmptyEditSource()
+ {
+ if( !mbEditSourceEmpty )
+ {
+ // deregister as listener
+ if (mpEditSource)
+ EndListening( mpEditSource->GetBroadcaster() );
+ }
+ else
+ {
+ EndListening( mrObj.getSdrModelFromSdrObject() );
+ }
+ }
+
+ SvxTextForwarder* AccessibleEmptyEditSource::GetTextForwarder()
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ return mpEditSource->GetTextForwarder();
+ }
+
+ SvxViewForwarder* AccessibleEmptyEditSource::GetViewForwarder()
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ return mpEditSource->GetViewForwarder();
+ }
+
+ void AccessibleEmptyEditSource::Switch2ProxyEditSource()
+ {
+ // deregister EmptyEditSource model listener
+ EndListening( mrObj.getSdrModelFromSdrObject() );
+
+ ::std::unique_ptr< SvxEditSource > pProxySource( new AccessibleProxyEditSource_Impl(mrObj, mrView, mrViewWindow) );
+ mpEditSource.swap(pProxySource);
+
+ // register as listener
+ StartListening( mpEditSource->GetBroadcaster() );
+
+ // we've irrevocably a full EditSource now.
+ mbEditSourceEmpty = false;
+ }
+
+ SvxEditViewForwarder* AccessibleEmptyEditSource::GetEditViewForwarder( bool bCreate )
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ // switch edit source, if not yet done
+ if( mbEditSourceEmpty && bCreate )
+ Switch2ProxyEditSource();
+
+ return mpEditSource->GetEditViewForwarder( bCreate );
+ }
+
+ std::unique_ptr<SvxEditSource> AccessibleEmptyEditSource::Clone() const
+ {
+ if (!mpEditSource)
+ return nullptr;
+
+ return mpEditSource->Clone();
+ }
+
+ void AccessibleEmptyEditSource::UpdateData()
+ {
+ if (mpEditSource)
+ mpEditSource->UpdateData();
+ }
+
+ SfxBroadcaster& AccessibleEmptyEditSource::GetBroadcaster() const
+ {
+ return *const_cast<AccessibleEmptyEditSource*>(this);
+ }
+
+ void AccessibleEmptyEditSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
+ {
+ const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast<const SdrHint*>(&rHint) : nullptr );
+
+ if( pSdrHint && pSdrHint->GetKind() == SdrHintKind::BeginEdit &&
+ &mrObj == pSdrHint->GetObject() && mpEditSource )
+ {
+ // switch edit source, if not yet done. This is necessary
+ // to become a full-fledged EditSource the first time a
+ // user start entering text in a previously empty object.
+ if( mbEditSourceEmpty )
+ Switch2ProxyEditSource();
+ }
+ else if (pSdrHint && pSdrHint->GetObject()!=nullptr)
+ {
+ // When the SdrObject just got a para outliner object then
+ // switch the edit source.
+ if (pSdrHint->GetObject()->GetOutlinerParaObject() != nullptr)
+ Switch2ProxyEditSource();
+ }
+
+ // forward messages
+ Broadcast( rHint );
+ }
+
+} // end of namespace accessibility
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */