summaryrefslogtreecommitdiffstats
path: root/forms/source/richtext
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /forms/source/richtext
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--forms/source/richtext/attributedispatcher.cxx115
-rw-r--r--forms/source/richtext/attributedispatcher.hxx79
-rw-r--r--forms/source/richtext/clipboarddispatcher.cxx191
-rw-r--r--forms/source/richtext/clipboarddispatcher.hxx91
-rw-r--r--forms/source/richtext/featuredispatcher.cxx138
-rw-r--r--forms/source/richtext/featuredispatcher.hxx89
-rw-r--r--forms/source/richtext/parametrizedattributedispatcher.cxx129
-rw-r--r--forms/source/richtext/parametrizedattributedispatcher.hxx61
-rw-r--r--forms/source/richtext/richtextcontrol.cxx652
-rw-r--r--forms/source/richtext/richtextcontrol.hxx128
-rw-r--r--forms/source/richtext/richtextengine.cxx138
-rw-r--r--forms/source/richtext/richtextengine.hxx71
-rw-r--r--forms/source/richtext/richtextimplcontrol.cxx654
-rw-r--r--forms/source/richtext/richtextimplcontrol.hxx184
-rw-r--r--forms/source/richtext/richtextmodel.cxx637
-rw-r--r--forms/source/richtext/richtextmodel.hxx186
-rw-r--r--forms/source/richtext/richtextunowrapper.cxx117
-rw-r--r--forms/source/richtext/richtextunowrapper.hxx81
-rw-r--r--forms/source/richtext/richtextvclcontrol.cxx353
-rw-r--r--forms/source/richtext/richtextvclcontrol.hxx122
-rw-r--r--forms/source/richtext/richtextviewport.cxx102
-rw-r--r--forms/source/richtext/richtextviewport.hxx64
-rw-r--r--forms/source/richtext/rtattributehandler.cxx441
-rw-r--r--forms/source/richtext/rtattributehandler.hxx163
-rw-r--r--forms/source/richtext/rtattributes.hxx130
-rw-r--r--forms/source/richtext/specialdispatchers.cxx171
-rw-r--r--forms/source/richtext/specialdispatchers.hxx91
-rw-r--r--forms/source/richtext/textattributelistener.hxx53
28 files changed, 5431 insertions, 0 deletions
diff --git a/forms/source/richtext/attributedispatcher.cxx b/forms/source/richtext/attributedispatcher.cxx
new file mode 100644
index 000000000..29dbbf616
--- /dev/null
+++ b/forms/source/richtext/attributedispatcher.cxx
@@ -0,0 +1,115 @@
+/* -*- 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 .
+ */
+
+#include "attributedispatcher.hxx"
+
+#include <editeng/editview.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::beans;
+
+ OAttributeDispatcher::OAttributeDispatcher( EditView& _rView, AttributeId _nAttributeId, const URL& _rURL,
+ IMultiAttributeDispatcher* _pMasterDispatcher )
+ :ORichTextFeatureDispatcher( _rView, _rURL )
+ ,m_pMasterDispatcher( _pMasterDispatcher )
+ ,m_nAttributeId( _nAttributeId )
+ {
+ OSL_ENSURE( m_pMasterDispatcher, "OAttributeDispatcher::OAttributeDispatcher: invalid master dispatcher!" );
+ }
+
+
+ OAttributeDispatcher::~OAttributeDispatcher( )
+ {
+ acquire();
+ dispose();
+ }
+
+
+ void OAttributeDispatcher::disposing( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
+ {
+ m_pMasterDispatcher = nullptr;
+ ORichTextFeatureDispatcher::disposing( _rClearBeforeNotify );
+ }
+
+
+ void OAttributeDispatcher::fillFeatureEventFromAttributeState( FeatureStateEvent& _rEvent, const AttributeState& _rState ) const
+ {
+ if ( _rState.eSimpleState == eChecked )
+ _rEvent.State <<= true;
+ else if ( _rState.eSimpleState == eUnchecked )
+ _rEvent.State <<= false;
+ }
+
+
+ FeatureStateEvent OAttributeDispatcher::buildStatusEvent() const
+ {
+ FeatureStateEvent aEvent( ORichTextFeatureDispatcher::buildStatusEvent() );
+ aEvent.IsEnabled = getEditView() && !getEditView()->IsReadOnly();
+
+ AttributeState aState;
+ if ( m_pMasterDispatcher )
+ aState = m_pMasterDispatcher->getState( m_nAttributeId );
+
+ fillFeatureEventFromAttributeState( aEvent, aState );
+
+ return aEvent;
+ }
+
+
+ void SAL_CALL OAttributeDispatcher::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArguments )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ checkDisposed();
+
+ OSL_ENSURE( _rURL.Complete == getFeatureURL().Complete, "OAttributeDispatcher::dispatch: invalid URL!" );
+ SAL_WARN_IF( _rArguments.hasElements(), "forms.richtext",
+ "OAttributeDispatcher::dispatch: found arguments, but can't handle arguments at all"
+ " (URL: " << _rURL.Complete << ")");
+
+ if ( m_pMasterDispatcher )
+ m_pMasterDispatcher->executeAttribute( m_nAttributeId, nullptr );
+ }
+
+
+ void OAttributeDispatcher::onAttributeStateChanged( AttributeId _nAttributeId )
+ {
+ OSL_ENSURE( _nAttributeId == m_nAttributeId, "OAttributeDispatcher::onAttributeStateChanged: wrong attribute!" );
+
+ FeatureStateEvent aEvent( buildStatusEvent() );
+ ::comphelper::OInterfaceIteratorHelper3 aIter( getStatusListeners() );
+ while ( aIter.hasMoreElements() )
+ doNotify( aIter.next(), aEvent );
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/attributedispatcher.hxx b/forms/source/richtext/attributedispatcher.hxx
new file mode 100644
index 000000000..9c6769b60
--- /dev/null
+++ b/forms/source/richtext/attributedispatcher.hxx
@@ -0,0 +1,79 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "featuredispatcher.hxx"
+#include "rtattributes.hxx"
+#include "textattributelistener.hxx"
+
+
+namespace frm
+{
+
+ class OAttributeDispatcher :public ORichTextFeatureDispatcher
+ ,public ITextAttributeListener
+ {
+ protected:
+ IMultiAttributeDispatcher* m_pMasterDispatcher;
+ AttributeId m_nAttributeId;
+
+ public:
+ /** ctor
+ @param _nAttributeId
+ the id of the attribute which this instance is responsible for
+ @param _rURL
+ the URL of the feature which this instance is responsible for
+ @param _pMasterDispatcher
+ the dispatcher which can execute the given attribute
+ @param _pConverter
+ an instance which is able to convert between SfxPoolItems and XDispatch-Parameters
+ If not <NULL/>, the parametrized version of IMultiAttributeDispatcher::executeAttribute
+ will be used.
+ */
+ OAttributeDispatcher(
+ EditView& _rView,
+ AttributeId _nAttributeId,
+ const css::util::URL& _rURL,
+ IMultiAttributeDispatcher* _pMasterDispatcher
+ );
+
+ protected:
+ virtual ~OAttributeDispatcher( ) override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // ITextAttributeListener
+ virtual void onAttributeStateChanged( AttributeId _nAttributeId ) override;
+
+ // ORichTextFeatureDispatcher
+ virtual void disposing( ::osl::ClearableMutexGuard& _rClearBeforeNotify ) override;
+
+ // ORichTextFeatureDispatcher
+ virtual css::frame::FeatureStateEvent buildStatusEvent() const override;
+
+ // own overridables
+ virtual void fillFeatureEventFromAttributeState( css::frame::FeatureStateEvent& _rEvent, const AttributeState& _rState ) const;
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/clipboarddispatcher.cxx b/forms/source/richtext/clipboarddispatcher.cxx
new file mode 100644
index 000000000..70313edb3
--- /dev/null
+++ b/forms/source/richtext/clipboarddispatcher.cxx
@@ -0,0 +1,191 @@
+/* -*- 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 .
+ */
+
+#include "clipboarddispatcher.hxx"
+#include <editeng/editview.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <svtools/cliplistener.hxx>
+#include <vcl/transfer.hxx>
+#include <osl/diagnose.h>
+
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::beans;
+
+
+ namespace
+ {
+ URL createClipboardURL( OClipboardDispatcher::ClipboardFunc _eFunc )
+ {
+ URL aURL;
+ switch ( _eFunc )
+ {
+ case OClipboardDispatcher::eCut:
+ aURL.Complete = ".uno:Cut";
+ break;
+ case OClipboardDispatcher::eCopy:
+ aURL.Complete = ".uno:Copy";
+ break;
+ case OClipboardDispatcher::ePaste:
+ aURL.Complete = ".uno:Paste";
+ break;
+ }
+ return aURL;
+ }
+ }
+
+ OClipboardDispatcher::OClipboardDispatcher( EditView& _rView, ClipboardFunc _eFunc )
+ :ORichTextFeatureDispatcher( _rView, createClipboardURL( _eFunc ) )
+ ,m_eFunc( _eFunc )
+ ,m_bLastKnownEnabled( true )
+ {
+ }
+
+
+ bool OClipboardDispatcher::implIsEnabled( ) const
+ {
+ bool bEnabled = false;
+ switch ( m_eFunc )
+ {
+ case eCut:
+ bEnabled = !getEditView()->IsReadOnly() && getEditView()->HasSelection();
+ break;
+
+ case eCopy:
+ bEnabled = getEditView()->HasSelection();
+ break;
+
+ case ePaste:
+ bEnabled = !getEditView()->IsReadOnly();
+ break;
+ }
+ return bEnabled;
+ }
+
+
+ FeatureStateEvent OClipboardDispatcher::buildStatusEvent() const
+ {
+ FeatureStateEvent aEvent( ORichTextFeatureDispatcher::buildStatusEvent() );
+ aEvent.IsEnabled = implIsEnabled();
+ return aEvent;
+ }
+
+
+ void OClipboardDispatcher::invalidateFeatureState_Broadcast()
+ {
+ bool bEnabled = implIsEnabled();
+ if ( m_bLastKnownEnabled == bEnabled )
+ // nothing changed -> no notification
+ return;
+ m_bLastKnownEnabled = bEnabled;
+
+ ORichTextFeatureDispatcher::invalidateFeatureState_Broadcast();
+ }
+
+
+ void SAL_CALL OClipboardDispatcher::dispatch( const URL& /*_rURL*/, const Sequence< PropertyValue >& /*Arguments*/ )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !getEditView() )
+ throw DisposedException();
+
+ switch ( m_eFunc )
+ {
+ case eCut:
+ getEditView()->Cut();
+ break;
+
+ case eCopy:
+ getEditView()->Copy();
+ break;
+
+ case ePaste:
+ getEditView()->Paste();
+ break;
+ }
+ }
+
+ OPasteClipboardDispatcher::OPasteClipboardDispatcher( EditView& _rView )
+ :OClipboardDispatcher( _rView, ePaste )
+ ,m_bPastePossible( false )
+ {
+ m_pClipListener = new TransferableClipboardListener( LINK( this, OPasteClipboardDispatcher, OnClipboardChanged ) );
+ m_pClipListener->AddListener( _rView.GetWindow() );
+
+ // initial state
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( _rView.GetWindow() ) );
+ m_bPastePossible = ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ||
+ aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) );
+ }
+
+
+ OPasteClipboardDispatcher::~OPasteClipboardDispatcher()
+ {
+ if ( !isDisposed() )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+
+ IMPL_LINK( OPasteClipboardDispatcher, OnClipboardChanged, TransferableDataHelper*, _pDataHelper, void )
+ {
+ OSL_ENSURE( _pDataHelper, "OPasteClipboardDispatcher::OnClipboardChanged: ooops!" );
+ m_bPastePossible = _pDataHelper->HasFormat( SotClipboardFormatId::STRING )
+ || _pDataHelper->HasFormat( SotClipboardFormatId::RTF )
+ || _pDataHelper->HasFormat( SotClipboardFormatId::RICHTEXT );
+
+ invalidate();
+ }
+
+
+ void OPasteClipboardDispatcher::disposing( ::osl::ClearableMutexGuard& _rClearBeforeNotify )
+ {
+ OSL_ENSURE( getEditView() && getEditView()->GetWindow(), "OPasteClipboardDispatcher::disposing: EditView should not (yet) be disfunctional here!" );
+ if (m_pClipListener.is())
+ {
+ if (getEditView() && getEditView()->GetWindow())
+ m_pClipListener->RemoveListener( getEditView()->GetWindow() );
+
+ m_pClipListener.clear();
+ }
+
+ OClipboardDispatcher::disposing( _rClearBeforeNotify );
+ }
+
+
+ bool OPasteClipboardDispatcher::implIsEnabled( ) const
+ {
+ return m_bPastePossible && OClipboardDispatcher::implIsEnabled();
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/clipboarddispatcher.hxx b/forms/source/richtext/clipboarddispatcher.hxx
new file mode 100644
index 000000000..47e561c67
--- /dev/null
+++ b/forms/source/richtext/clipboarddispatcher.hxx
@@ -0,0 +1,91 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "featuredispatcher.hxx"
+#include <tools/link.hxx>
+#include <rtl/ref.hxx>
+
+class TransferableClipboardListener;
+class TransferableDataHelper;
+
+namespace frm
+{
+
+ class OClipboardDispatcher : public ORichTextFeatureDispatcher
+ {
+ public:
+ enum ClipboardFunc
+ {
+ eCut,
+ eCopy,
+ ePaste
+ };
+
+ private:
+ ClipboardFunc m_eFunc;
+ bool m_bLastKnownEnabled;
+
+ public:
+ OClipboardDispatcher( EditView& _rView, ClipboardFunc _eFunc );
+
+ protected:
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // ORichTextFeatureDispatcher
+ virtual void invalidateFeatureState_Broadcast() override;
+ virtual css::frame::FeatureStateEvent
+ buildStatusEvent() const override;
+
+ protected:
+ /** determines whether our functionality is currently available
+ to be overridden for ePaste
+ */
+ virtual bool implIsEnabled( ) const;
+ };
+
+ class OPasteClipboardDispatcher : public OClipboardDispatcher
+ {
+ private:
+ rtl::Reference<TransferableClipboardListener> m_pClipListener;
+ bool m_bPastePossible;
+
+ public:
+ explicit OPasteClipboardDispatcher( EditView& _rView );
+
+ protected:
+ virtual ~OPasteClipboardDispatcher() override;
+
+ // OClipboardDispatcher
+ virtual bool implIsEnabled( ) const override;
+
+ // ORichTextFeatureDispatcher
+ virtual void disposing( ::osl::ClearableMutexGuard& _rClearBeforeNotify ) override;
+
+ private:
+ DECL_LINK( OnClipboardChanged, TransferableDataHelper*, void );
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/featuredispatcher.cxx b/forms/source/richtext/featuredispatcher.cxx
new file mode 100644
index 000000000..93f163d43
--- /dev/null
+++ b/forms/source/richtext/featuredispatcher.cxx
@@ -0,0 +1,138 @@
+/* -*- 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 .
+ */
+
+#include "featuredispatcher.hxx"
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+
+ ORichTextFeatureDispatcher::ORichTextFeatureDispatcher( EditView& _rView, const URL& _rURL )
+ :m_aFeatureURL( _rURL )
+ ,m_aStatusListeners( m_aMutex )
+ ,m_pEditView( &_rView )
+ ,m_bDisposed( false )
+ {
+ }
+
+
+ ORichTextFeatureDispatcher::~ORichTextFeatureDispatcher( )
+ {
+ if ( !m_bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+
+ void ORichTextFeatureDispatcher::dispose()
+ {
+ EventObject aEvent( *this );
+ m_aStatusListeners.disposeAndClear( aEvent );
+
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ m_bDisposed = true;
+ disposing( aGuard );
+ }
+
+
+ void ORichTextFeatureDispatcher::disposing( ::osl::ClearableMutexGuard& /*_rClearBeforeNotify*/ )
+ {
+ m_pEditView = nullptr;
+ }
+
+
+ void SAL_CALL ORichTextFeatureDispatcher::addStatusListener( const Reference< XStatusListener >& _rxControl, const URL& _rURL )
+ {
+ OSL_ENSURE( !m_bDisposed, "ORichTextFeatureDispatcher::addStatusListener: already disposed!" );
+ if ( m_bDisposed )
+ throw DisposedException();
+
+ OSL_ENSURE( _rURL.Complete == getFeatureURL().Complete, "ORichTextFeatureDispatcher::addStatusListener: invalid URL!" );
+ if ( _rURL.Complete == getFeatureURL().Complete )
+ if ( _rxControl.is() )
+ {
+ m_aStatusListeners.addInterface( _rxControl );
+ doNotify( _rxControl, buildStatusEvent() );
+ }
+ }
+
+
+ void SAL_CALL ORichTextFeatureDispatcher::removeStatusListener( const Reference< XStatusListener >& _rxControl, const URL& /*_rURL*/ )
+ {
+ m_aStatusListeners.removeInterface( _rxControl );
+ }
+
+
+ void ORichTextFeatureDispatcher::invalidate()
+ {
+ invalidateFeatureState_Broadcast();
+ }
+
+
+ FeatureStateEvent ORichTextFeatureDispatcher::buildStatusEvent() const
+ {
+ FeatureStateEvent aEvent;
+ aEvent.IsEnabled = false;
+ aEvent.Source = *const_cast< ORichTextFeatureDispatcher* >( this );
+ aEvent.FeatureURL = getFeatureURL();
+ aEvent.Requery = false;
+ return aEvent;
+ }
+
+
+ void ORichTextFeatureDispatcher::invalidateFeatureState_Broadcast()
+ {
+ FeatureStateEvent aEvent( buildStatusEvent() );
+ ::comphelper::OInterfaceIteratorHelper3 aIter( getStatusListeners() );
+ while ( aIter.hasMoreElements() )
+ doNotify( aIter.next(), aEvent );
+ }
+
+
+ void ORichTextFeatureDispatcher::doNotify( const Reference< XStatusListener >& _rxListener, const FeatureStateEvent& _rEvent )
+ {
+ OSL_PRECOND( _rxListener.is(), "ORichTextFeatureDispatcher::doNotify: invalid listener!" );
+ if ( _rxListener.is() )
+ {
+ try
+ {
+ _rxListener->statusChanged( _rEvent );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.richtext", "ORichTextFeatureDispatcher::doNotify" );
+ }
+ }
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/featuredispatcher.hxx b/forms/source/richtext/featuredispatcher.hxx
new file mode 100644
index 000000000..53be887a4
--- /dev/null
+++ b/forms/source/richtext/featuredispatcher.hxx
@@ -0,0 +1,89 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+class EditView;
+
+namespace frm
+{
+
+ typedef ::cppu::WeakImplHelper < css::frame::XDispatch
+ > ORichTextFeatureDispatcher_Base;
+
+ class ORichTextFeatureDispatcher :public ::cppu::BaseMutex
+ ,public ORichTextFeatureDispatcher_Base
+ {
+ private:
+ css::util::URL m_aFeatureURL;
+ ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener> m_aStatusListeners;
+ EditView* m_pEditView;
+ bool m_bDisposed;
+
+ protected:
+ EditView* getEditView() { return m_pEditView; }
+ const EditView* getEditView() const { return m_pEditView; }
+
+ protected:
+ const css::util::URL& getFeatureURL() const { return m_aFeatureURL; }
+ ::comphelper::OInterfaceContainerHelper3<css::frame::XStatusListener>& getStatusListeners() { return m_aStatusListeners; }
+ bool isDisposed() const { return m_bDisposed; }
+ void checkDisposed() const { if ( isDisposed() ) throw css::lang::DisposedException(); }
+
+ protected:
+ ORichTextFeatureDispatcher( EditView& _rView, const css::util::URL& _rURL );
+ virtual ~ORichTextFeatureDispatcher( ) override;
+
+ public:
+ /// clean up resources associated with this instance
+ void dispose();
+
+ // invalidate the feature, re-retrieve it's state, and broadcast changes, if necessary
+ void invalidate();
+
+ protected:
+ // overridables
+ virtual void disposing( ::osl::ClearableMutexGuard& _rClearBeforeNotify );
+ virtual void invalidateFeatureState_Broadcast();
+
+ // to be overridden, and filled with the info special do your derived class
+ virtual css::frame::FeatureStateEvent
+ buildStatusEvent() const;
+
+ static void doNotify(
+ const css::uno::Reference< css::frame::XStatusListener >& _rxListener,
+ const css::frame::FeatureStateEvent& _rEvent
+ );
+
+ // XDispatch
+ virtual void SAL_CALL addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& _rxControl, const css::util::URL& _rURL ) override;
+ virtual void SAL_CALL removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& _rxControl, const css::util::URL& _rURL ) override;
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/parametrizedattributedispatcher.cxx b/forms/source/richtext/parametrizedattributedispatcher.cxx
new file mode 100644
index 000000000..d6666e2b0
--- /dev/null
+++ b/forms/source/richtext/parametrizedattributedispatcher.cxx
@@ -0,0 +1,129 @@
+/* -*- 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 .
+ */
+
+#include "parametrizedattributedispatcher.hxx"
+#include <editeng/editids.hrc>
+#include <editeng/editview.hxx>
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <osl/diagnose.h>
+
+#include <sfx2/sfxuno.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::beans;
+
+ OParametrizedAttributeDispatcher::OParametrizedAttributeDispatcher( EditView& _rView, AttributeId _nAttributeId, const URL& _rURL, IMultiAttributeDispatcher* _pMasterDispatcher )
+ :OAttributeDispatcher( _rView, _nAttributeId, _rURL, _pMasterDispatcher )
+ {
+ }
+
+
+ OParametrizedAttributeDispatcher::~OParametrizedAttributeDispatcher()
+ {
+ acquire();
+ dispose();
+ }
+
+
+ namespace
+ {
+ SfxSlotId lcl_normalizeLatinScriptSlotId( SfxSlotId _nSlotId )
+ {
+ switch ( _nSlotId )
+ {
+ case SID_ATTR_CHAR_LATIN_FONT: return SID_ATTR_CHAR_FONT;
+ case SID_ATTR_CHAR_LATIN_LANGUAGE: return SID_ATTR_CHAR_LANGUAGE;
+ case SID_ATTR_CHAR_LATIN_POSTURE: return SID_ATTR_CHAR_POSTURE;
+ case SID_ATTR_CHAR_LATIN_WEIGHT: return SID_ATTR_CHAR_WEIGHT;
+ case SID_ATTR_CHAR_LATIN_FONTHEIGHT:return SID_ATTR_CHAR_FONTHEIGHT;
+ }
+ return _nSlotId;
+ }
+ }
+
+
+ void OParametrizedAttributeDispatcher::fillFeatureEventFromAttributeState( FeatureStateEvent& _rEvent, const AttributeState& _rState ) const
+ {
+ OSL_ENSURE( getEditView(), "OParametrizedAttributeDispatcher::notifyState: already disposed!" );
+ if ( !getEditView() )
+ return;
+
+ SfxItemSet aEmptySet(getEditView()->GetEmptyItemSet());
+ Sequence< PropertyValue > aUnoStateDescription;
+ if ( _rState.getItem() )
+ {
+ aEmptySet.Put( *_rState.getItem() );
+ SfxSlotId nSlotId = aEmptySet.GetPool()->GetSlotId( _rState.getItem()->Which() );
+ TransformItems( nSlotId, aEmptySet, aUnoStateDescription );
+ _rEvent.State <<= aUnoStateDescription;
+ }
+ else
+ OAttributeDispatcher::fillFeatureEventFromAttributeState( _rEvent, _rState );
+ }
+
+
+ const SfxPoolItem* OParametrizedAttributeDispatcher::convertDispatchArgsToItem( const Sequence< PropertyValue >& _rArguments )
+ {
+ // get the real slot id. This may differ from our attribute id: for instance, both
+ // SID_ATTR_CHAR_HEIGHT and SID_ATTR_CHAR_LATIN_HEIGHT are mapped to the same which id
+ SfxSlotId nSlotId = lcl_normalizeLatinScriptSlotId( static_cast<SfxSlotId>(m_nAttributeId) );
+
+ SfxAllItemSet aParameterSet( getEditView()->GetEmptyItemSet() );
+ TransformParameters( nSlotId, _rArguments, aParameterSet );
+
+ const SfxPoolItem* pArgument = nullptr;
+ if ( aParameterSet.Count() )
+ {
+ OSL_ENSURE( aParameterSet.Count() == 1, "OParametrizedAttributeDispatcher::convertDispatchArgsToItem: Arguments which form more than 1 item? How this?" );
+ WhichId nAttributeWhich = aParameterSet.GetPool()->GetWhich( nSlotId );
+ pArgument = aParameterSet.GetItem( nAttributeWhich );
+ OSL_ENSURE( pArgument, "OParametrizedAttributeDispatcher::convertDispatchArgsToItem: suspicious: there were arguments, but they're not for my slot!" );
+ }
+
+ return pArgument;
+ }
+
+
+ void SAL_CALL OParametrizedAttributeDispatcher::dispatch( const URL& _rURL, const Sequence< PropertyValue >& _rArguments )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_ENSURE( _rURL.Complete == getFeatureURL().Complete, "OParametrizedAttributeDispatcher::dispatch: invalid URL!" );
+ if ( m_pMasterDispatcher )
+ {
+ const SfxPoolItem* pConvertedArgument = convertDispatchArgsToItem( _rArguments );
+ m_pMasterDispatcher->executeAttribute( m_nAttributeId, pConvertedArgument );
+ }
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/parametrizedattributedispatcher.hxx b/forms/source/richtext/parametrizedattributedispatcher.hxx
new file mode 100644
index 000000000..698447316
--- /dev/null
+++ b/forms/source/richtext/parametrizedattributedispatcher.hxx
@@ -0,0 +1,61 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "attributedispatcher.hxx"
+
+class SfxPoolItem;
+
+namespace frm
+{
+
+ class OParametrizedAttributeDispatcher :public OAttributeDispatcher
+ {
+ public:
+ OParametrizedAttributeDispatcher(
+ EditView& _rView,
+ AttributeId _nAttributeId,
+ const css::util::URL& _rURL,
+ IMultiAttributeDispatcher* _pMasterDispatcher
+ );
+
+ protected:
+ virtual ~OParametrizedAttributeDispatcher() override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // OAttributeDispatcher
+ virtual void fillFeatureEventFromAttributeState( css::frame::FeatureStateEvent& _rEvent, const AttributeState& _rState ) const override;
+
+ protected:
+ // own overridables
+ /** convert the arguments as got in a XDispatch::dispatch call into an SfxPoolItem, which can
+ be used with a IMultiAttributeDispatcher::executeAttribute
+ */
+ virtual const SfxPoolItem* convertDispatchArgsToItem(
+ const css::uno::Sequence< css::beans::PropertyValue >& _rArguments );
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextcontrol.cxx b/forms/source/richtext/richtextcontrol.cxx
new file mode 100644
index 000000000..408199dac
--- /dev/null
+++ b/forms/source/richtext/richtextcontrol.cxx
@@ -0,0 +1,652 @@
+/* -*- 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 .
+ */
+
+#include "richtextcontrol.hxx"
+#include <frm_strings.hxx>
+#include <services.hxx>
+
+#include "richtextmodel.hxx"
+#include "richtextvclcontrol.hxx"
+#include "clipboarddispatcher.hxx"
+#include "parametrizedattributedispatcher.hxx"
+#include "specialdispatchers.hxx"
+
+#include <com/sun/star/awt/PosSize.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+
+#include <svx/svxids.hrc>
+#include <editeng/editview.hxx>
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/msg.hxx>
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::frame;
+
+ ORichTextControl::ORichTextControl()
+ {
+ }
+
+
+ ORichTextControl::~ORichTextControl()
+ {
+ }
+
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( ORichTextControl, UnoEditControl, ORichTextControl_Base )
+
+
+ Any SAL_CALL ORichTextControl::queryAggregation( const Type& _rType )
+ {
+ Any aReturn = UnoEditControl::queryAggregation( _rType );
+
+ if ( !aReturn.hasValue() )
+ aReturn = ORichTextControl_Base::queryInterface( _rType );
+
+ return aReturn;
+ }
+
+
+ namespace
+ {
+
+ void implAdjustTriStateFlag( const Reference< XPropertySet >& _rxProps, const OUString& _rPropertyName,
+ WinBits& _rAllBits, WinBits _nPositiveFlag, WinBits nNegativeFlag )
+ {
+ bool bFlagValue = false;
+ if ( _rxProps->getPropertyValue( _rPropertyName ) >>= bFlagValue )
+ _rAllBits |= ( bFlagValue ? _nPositiveFlag : nNegativeFlag );
+ }
+
+
+ void implAdjustTwoStateFlag( const Any& _rValue, WinBits& _rAllBits, WinBits _nFlag, bool _bInvert )
+ {
+ bool bFlagValue = false;
+ if ( _rValue >>= bFlagValue )
+ {
+ if ( _bInvert )
+ bFlagValue = !bFlagValue;
+ if ( bFlagValue )
+ _rAllBits |= _nFlag;
+ else
+ _rAllBits &= ~_nFlag;
+ }
+ }
+
+
+ void implAdjustTwoStateFlag( const Reference< XPropertySet >& _rxProps, const OUString& _rPropertyName,
+ WinBits& _rAllBits, WinBits _nFlag, bool _bInvert = false )
+ {
+ implAdjustTwoStateFlag( _rxProps->getPropertyValue( _rPropertyName ), _rAllBits, _nFlag, _bInvert );
+ }
+
+
+ void adjustTwoStateWinBit( vcl::Window* _pWindow, const Any& _rValue, WinBits _nFlag, bool _bInvert = false )
+ {
+ WinBits nBits = _pWindow->GetStyle();
+ implAdjustTwoStateFlag( _rValue, nBits, _nFlag, _bInvert );
+ _pWindow->SetStyle( nBits );
+ }
+
+
+ WinBits getWinBits( const Reference< XControlModel >& _rxModel )
+ {
+ WinBits nBits = 0;
+ try
+ {
+ Reference< XPropertySet > xProps( _rxModel, UNO_QUERY );
+ if ( xProps.is() )
+ {
+ sal_Int16 nBorder = 0;
+ xProps->getPropertyValue( PROPERTY_BORDER ) >>= nBorder;
+ if ( nBorder )
+ nBits |= WB_BORDER;
+
+ implAdjustTriStateFlag( xProps, PROPERTY_TABSTOP, nBits, WB_TABSTOP, WB_NOTABSTOP );
+ implAdjustTwoStateFlag( xProps, PROPERTY_HSCROLL, nBits, WB_HSCROLL );
+ implAdjustTwoStateFlag( xProps, PROPERTY_VSCROLL, nBits, WB_VSCROLL );
+ implAdjustTwoStateFlag( xProps, PROPERTY_HARDLINEBREAKS, nBits, WB_WORDBREAK, true );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("forms.richtext");
+ }
+ return nBits;
+ }
+ }
+
+
+ void SAL_CALL ORichTextControl::createPeer( const Reference< XToolkit >& _rToolkit, const Reference< XWindowPeer >& _rParentPeer )
+ {
+ bool bReallyActAsRichText = false;
+ try
+ {
+ Reference< XPropertySet > xModelProps( getModel(), UNO_QUERY_THROW );
+ xModelProps->getPropertyValue( PROPERTY_RICH_TEXT ) >>= bReallyActAsRichText;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("forms.richtext");
+ }
+
+ if ( !bReallyActAsRichText )
+ {
+ UnoEditControl::createPeer( _rToolkit, _rParentPeer );
+ return;
+ }
+
+ SolarMutexGuard aGuard;
+
+ if (getPeer().is())
+ return;
+
+ mbCreatingPeer = true;
+
+ // determine the VCL window for the parent
+ vcl::Window* pParentWin = nullptr;
+ if ( _rParentPeer.is() )
+ {
+ VCLXWindow* pParentXWin = comphelper::getFromUnoTunnel<VCLXWindow>( _rParentPeer );
+ if ( pParentXWin )
+ pParentWin = pParentXWin->GetWindow();
+ DBG_ASSERT( pParentWin, "ORichTextControl::createPeer: could not obtain the VCL-level parent window!" );
+ }
+
+ // create the peer
+ Reference< XControlModel > xModel( getModel() );
+ rtl::Reference<ORichTextPeer> pPeer = ORichTextPeer::Create( xModel, pParentWin, getWinBits( xModel ) );
+ DBG_ASSERT( pPeer, "ORichTextControl::createPeer: invalid peer returned!" );
+ if ( pPeer )
+ {
+ // announce the peer to the base class
+ setPeer( pPeer );
+
+ // initialize ourself (and thus the peer) with the model properties
+ updateFromModel();
+
+ Reference< XView > xPeerView( getPeer(), UNO_QUERY );
+ if ( xPeerView.is() )
+ {
+ xPeerView->setZoom( maComponentInfos.nZoomX, maComponentInfos.nZoomY );
+ xPeerView->setGraphics( mxGraphics );
+ }
+
+ // a lot of initial settings from our component infos
+ setPosSize( maComponentInfos.nX, maComponentInfos.nY, maComponentInfos.nWidth, maComponentInfos.nHeight, PosSize::POSSIZE );
+
+ pPeer->setVisible ( maComponentInfos.bVisible && !mbDesignMode );
+ pPeer->setEnable ( maComponentInfos.bEnable );
+ pPeer->setDesignMode( mbDesignMode );
+
+ peerCreated();
+ }
+
+ mbCreatingPeer = false;
+ }
+
+ OUString SAL_CALL ORichTextControl::getImplementationName()
+ {
+ return "com.sun.star.comp.form.ORichTextControl";
+ }
+
+ Sequence< OUString > SAL_CALL ORichTextControl::getSupportedServiceNames()
+ {
+ return { "com.sun.star.awt.UnoControl",
+ "com.sun.star.awt.UnoControlEdit",
+ FRM_SUN_CONTROL_RICHTEXTCONTROL };
+ }
+
+ Reference< XDispatch > SAL_CALL ORichTextControl::queryDispatch( const css::util::URL& _rURL, const OUString& _rTargetFrameName, sal_Int32 _nSearchFlags )
+ {
+ Reference< XDispatch > aReturn;
+ Reference< XDispatchProvider > xTypedPeer( getPeer(), UNO_QUERY );
+ if ( xTypedPeer.is() )
+ {
+ aReturn = xTypedPeer->queryDispatch( _rURL, _rTargetFrameName, _nSearchFlags );
+ }
+ return aReturn;
+ }
+
+ Sequence< Reference< XDispatch > > SAL_CALL ORichTextControl::queryDispatches( const Sequence< DispatchDescriptor >& _rRequests )
+ {
+ Reference<XDispatchProvider> xTypedPeer(getPeer(), UNO_QUERY);
+ if (xTypedPeer.is())
+ return xTypedPeer->queryDispatches(_rRequests);
+ return Sequence<Reference<XDispatch>>();
+ }
+
+ bool ORichTextControl::requiresNewPeer( const OUString& _rPropertyName ) const
+ {
+ return UnoControl::requiresNewPeer( _rPropertyName ) || _rPropertyName == PROPERTY_RICH_TEXT;
+ }
+
+ // ORichTextPeer
+ rtl::Reference<ORichTextPeer> ORichTextPeer::Create( const Reference< XControlModel >& _rxModel, vcl::Window* _pParentWindow, WinBits _nStyle )
+ {
+ DBG_TESTSOLARMUTEX();
+
+ // the EditEngine of the model
+ RichTextEngine* pEngine = ORichTextModel::getEditEngine( _rxModel );
+ OSL_ENSURE( pEngine, "ORichTextPeer::Create: could not obtaine the edit engine from the model!" );
+ if ( !pEngine )
+ return nullptr;
+
+ // the peer itself
+ rtl::Reference<ORichTextPeer> pPeer(new ORichTextPeer);
+
+ // the VCL control for the peer
+ VclPtrInstance<RichTextControl> pRichTextControl( pEngine, _pParentWindow, _nStyle, nullptr, pPeer.get() );
+
+ // some knittings
+ pRichTextControl->SetComponentInterface( pPeer );
+
+ // outta here
+ return pPeer;
+ }
+
+
+ ORichTextPeer::ORichTextPeer()
+ {
+ }
+
+
+ ORichTextPeer::~ORichTextPeer()
+ {
+ }
+
+
+ void ORichTextPeer::dispose( )
+ {
+ {
+ SolarMutexGuard aGuard;
+ VclPtr< RichTextControl > pRichTextControl = GetAs< RichTextControl >();
+
+ if ( pRichTextControl )
+ {
+ for (auto const& dispatcher : m_aDispatchers)
+ {
+ pRichTextControl->disableAttributeNotification(dispatcher.first);
+ dispatcher.second->dispose();
+ }
+ }
+
+ AttributeDispatchers().swap(m_aDispatchers);
+ }
+
+ VCLXWindow::dispose();
+ }
+
+
+ void SAL_CALL ORichTextPeer::draw( sal_Int32 _nX, sal_Int32 _nY )
+ {
+ SolarMutexGuard aGuard;
+
+ VclPtr< RichTextControl > pControl = GetAs< RichTextControl >();
+ if ( !pControl )
+ return;
+
+ OutputDevice* pTargetDevice = VCLUnoHelper::GetOutputDevice( getGraphics() );
+ OSL_ENSURE( pTargetDevice != nullptr, "ORichTextPeer::draw: no graphics -> no drawing!" );
+ if ( !pTargetDevice )
+ return;
+
+ const MapUnit eTargetUnit = pTargetDevice->GetMapMode().GetMapUnit();
+ ::Point aPos( _nX, _nY );
+ // the XView::draw API talks about pixels, always ...
+ if ( eTargetUnit != MapUnit::MapPixel )
+ aPos = pTargetDevice->PixelToLogic( aPos );
+
+ pControl->Draw( pTargetDevice, aPos, SystemTextColorFlags::NoControls );
+ }
+
+
+ void SAL_CALL ORichTextPeer::setProperty( const OUString& _rPropertyName, const Any& _rValue )
+ {
+ SolarMutexGuard g;
+
+ if ( !GetWindow() )
+ {
+ VCLXWindow::setProperty( _rPropertyName, _rValue );
+ return;
+ }
+
+ if ( _rPropertyName == PROPERTY_BACKGROUNDCOLOR )
+ {
+ VclPtr< RichTextControl > pControl = GetAs< RichTextControl >();
+ if ( !_rValue.hasValue() )
+ {
+ pControl->SetBackgroundColor( );
+ }
+ else
+ {
+ Color nColor = COL_TRANSPARENT;
+ _rValue >>= nColor;
+ pControl->SetBackgroundColor( nColor );
+ }
+ }
+ else if ( _rPropertyName == PROPERTY_HSCROLL )
+ {
+ adjustTwoStateWinBit( GetWindow(), _rValue, WB_HSCROLL );
+ }
+ else if ( _rPropertyName == PROPERTY_VSCROLL )
+ {
+ adjustTwoStateWinBit( GetWindow(), _rValue, WB_VSCROLL );
+ }
+ else if ( _rPropertyName == PROPERTY_HARDLINEBREAKS )
+ {
+ adjustTwoStateWinBit( GetWindow(), _rValue, WB_WORDBREAK, true );
+ }
+ else if ( _rPropertyName == PROPERTY_READONLY )
+ {
+ VclPtr< RichTextControl > pControl = GetAs< RichTextControl >();
+ bool bReadOnly( pControl->IsReadOnly() );
+ OSL_VERIFY( _rValue >>= bReadOnly );
+ pControl->SetReadOnly( bReadOnly );
+
+ // update the dispatchers
+ for (auto const& dispatcher : m_aDispatchers)
+ {
+ dispatcher.second->invalidate();
+ }
+ }
+ else if ( _rPropertyName == PROPERTY_HIDEINACTIVESELECTION )
+ {
+ VclPtr< RichTextControl > pRichTextControl = GetAs< RichTextControl >();
+ bool bHide = pRichTextControl->GetHideInactiveSelection();
+ OSL_VERIFY( _rValue >>= bHide );
+ pRichTextControl->SetHideInactiveSelection( bHide );
+ }
+ else
+ VCLXWindow::setProperty( _rPropertyName, _rValue );
+ }
+
+
+ IMPLEMENT_FORWARD_XINTERFACE2( ORichTextPeer, VCLXWindow, ORichTextPeer_Base )
+
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( ORichTextPeer, VCLXWindow, ORichTextPeer_Base )
+
+
+ namespace
+ {
+ SfxSlotId lcl_translateConflictingSlot( SfxSlotId _nIDFromPool )
+ {
+ // HACK HACK HACK
+ // unfortunately, some of our applications have some conflicting slots,
+ // i.e. slots which have the same UNO name as an existing other (common)
+ // slot.
+ // For instance, both the slots SID_SET_SUPER_SCRIPT (from SVX) and FN_SET_SUPER_SCRIPT
+ // (from SW) have the UNO name "SuperScript".
+ // Now, if the controls lives in a text document, and asks the SfxSlotPool for
+ // the id belonging to "SuperScript", it gets the FN_SET_SUPER_SCRIPT - which
+ // is completely unknown to the EditEngine.
+ // So, we need to translate such conflicting ids.
+
+ // Note that the real solution would be to fix the applications to
+ // *not* define conflicting slots. Alternatively, if SFX would provide a slot pool
+ // which is *static* (i.e. independent on the active application), then we
+ // would also never encounter such a conflict.
+ SfxSlotId nReturn( _nIDFromPool );
+ switch ( _nIDFromPool )
+ {
+ case 20411: /* FM_SET_SUPER_SCRIPT, originating in SW */
+ nReturn = SID_SET_SUPER_SCRIPT;
+ break;
+ case 20412: /* FN_SET_SUB_SCRIPT, originating in SW */
+ nReturn = SID_SET_SUB_SCRIPT;
+ break;
+ }
+ return nReturn;
+ }
+ }
+
+
+ ORichTextPeer::SingleAttributeDispatcher ORichTextPeer::implCreateDispatcher( SfxSlotId _nSlotId, const css::util::URL& _rURL )
+ {
+ VclPtr< RichTextControl > pRichTextControl = GetAs< RichTextControl >();
+ OSL_PRECOND( pRichTextControl, "ORichTextPeer::implCreateDispatcher: invalid window!" );
+ if ( !pRichTextControl )
+ return SingleAttributeDispatcher( nullptr );
+
+ rtl::Reference<ORichTextFeatureDispatcher> pDispatcher;
+ rtl::Reference<OAttributeDispatcher> pAttributeDispatcher;
+ switch ( _nSlotId )
+ {
+ case SID_CUT:
+ pDispatcher = new OClipboardDispatcher( pRichTextControl->getView(), OClipboardDispatcher::eCut );
+ break;
+
+ case SID_COPY:
+ pDispatcher = new OClipboardDispatcher( pRichTextControl->getView(), OClipboardDispatcher::eCopy );
+ break;
+
+ case SID_PASTE:
+ pDispatcher = new OPasteClipboardDispatcher( pRichTextControl->getView() );
+ break;
+
+ case SID_SELECTALL:
+ pDispatcher = new OSelectAllDispatcher( pRichTextControl->getView(), _rURL );
+ break;
+
+ case SID_ATTR_PARA_LEFT_TO_RIGHT:
+ case SID_ATTR_PARA_RIGHT_TO_LEFT:
+ pAttributeDispatcher = new OParagraphDirectionDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
+ break;
+
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ pDispatcher = new OTextDirectionDispatcher( pRichTextControl->getView(), _rURL );
+ break;
+
+ case SID_ATTR_PARA_HANGPUNCTUATION:
+ case SID_ATTR_PARA_FORBIDDEN_RULES:
+ case SID_ATTR_PARA_SCRIPTSPACE:
+ pAttributeDispatcher = new OAsianFontLayoutDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
+ break;
+
+ default:
+ {
+ const SfxItemPool& rPool = *pRichTextControl->getView().GetEmptyItemSet().GetPool();
+ bool bSupportedSlot = rPool.IsInRange( rPool.GetWhich( _nSlotId ) );
+
+ if ( !bSupportedSlot )
+ bSupportedSlot = RichTextControl::isMappableSlot( _nSlotId );
+
+ if ( bSupportedSlot )
+ { // it's really a slot which is supported by the EditEngine
+
+ bool bNeedParametrizedDispatcher = true;
+ if ( ( _nSlotId == SID_ATTR_CHAR_POSTURE )
+ || ( _nSlotId == SID_ATTR_CHAR_CJK_POSTURE )
+ || ( _nSlotId == SID_ATTR_CHAR_CTL_POSTURE )
+ || ( _nSlotId == SID_ATTR_CHAR_LATIN_POSTURE )
+ || ( _nSlotId == SID_ATTR_CHAR_WEIGHT )
+ || ( _nSlotId == SID_ATTR_CHAR_CJK_WEIGHT )
+ || ( _nSlotId == SID_ATTR_CHAR_CTL_WEIGHT )
+ || ( _nSlotId == SID_ATTR_CHAR_LATIN_WEIGHT )
+ || ( _nSlotId == SID_ATTR_CHAR_LANGUAGE )
+ || ( _nSlotId == SID_ATTR_CHAR_CJK_LANGUAGE )
+ || ( _nSlotId == SID_ATTR_CHAR_CTL_LANGUAGE )
+ || ( _nSlotId == SID_ATTR_CHAR_LATIN_LANGUAGE )
+ || ( _nSlotId == SID_ATTR_CHAR_CONTOUR )
+ || ( _nSlotId == SID_ATTR_CHAR_SHADOWED )
+ || ( _nSlotId == SID_ATTR_CHAR_WORDLINEMODE )
+ || ( _nSlotId == SID_ATTR_CHAR_COLOR )
+ || ( _nSlotId == SID_ATTR_CHAR_RELIEF )
+ || ( _nSlotId == SID_ATTR_CHAR_KERNING )
+ || ( _nSlotId == SID_ATTR_CHAR_AUTOKERN )
+ || ( _nSlotId == SID_ATTR_CHAR_SCALEWIDTH )
+ )
+ {
+ bNeedParametrizedDispatcher = true;
+ }
+ else
+ {
+ SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool();
+ const SfxSlot* pSlot = rSlotPool.GetSlot( _nSlotId );
+ const SfxType* pType = pSlot ? pSlot->GetType() : nullptr;
+ if ( pType )
+ {
+ bNeedParametrizedDispatcher = ( pType->nAttribs > 0 );
+ }
+ }
+
+ if ( bNeedParametrizedDispatcher )
+ {
+ pAttributeDispatcher = new OParametrizedAttributeDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
+ }
+ else
+ {
+ pAttributeDispatcher = new OAttributeDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
+ }
+ }
+ else
+ {
+ SAL_WARN("forms.richtext", "ORichTextPeer::implCreateDispatcher: not creating dispatcher (unsupported slot) for "
+ << _rURL.Complete);
+ }
+ }
+ break;
+ }
+
+ SingleAttributeDispatcher xDispatcher( pDispatcher );
+ if ( pAttributeDispatcher )
+ {
+ xDispatcher = SingleAttributeDispatcher( pAttributeDispatcher );
+ pRichTextControl->enableAttributeNotification( _nSlotId, pAttributeDispatcher.get() );
+ }
+
+ return xDispatcher;
+ }
+
+
+ namespace
+ {
+ SfxSlotId lcl_getSlotFromUnoName( SfxSlotPool const & _rSlotPool, const OUString& _rUnoSlotName )
+ {
+ const SfxSlot* pSlot = _rSlotPool.GetUnoSlot( _rUnoSlotName );
+ if ( pSlot )
+ {
+ // okay, there's a slot with the given UNO name
+ return lcl_translateConflictingSlot( pSlot->GetSlotId() );
+ }
+
+ // some hard-coded slots, which do not have a UNO name at SFX level, but which
+ // we nevertheless need to transport via UNO mechanisms, so we need a name
+ if ( _rUnoSlotName == "AllowHangingPunctuation" )
+ return SID_ATTR_PARA_HANGPUNCTUATION;
+ if ( _rUnoSlotName == "ApplyForbiddenCharacterRules" )
+ return SID_ATTR_PARA_FORBIDDEN_RULES;
+ if ( _rUnoSlotName == "UseScriptSpacing" )
+ return SID_ATTR_PARA_SCRIPTSPACE;
+
+ OSL_ENSURE( pSlot, "lcl_getSlotFromUnoName: unknown UNO slot name!" );
+ return 0;
+ }
+ }
+
+
+ Reference< XDispatch > SAL_CALL ORichTextPeer::queryDispatch( const css::util::URL& _rURL, const OUString& /*_rTargetFrameName*/, sal_Int32 /*_nSearchFlags*/ )
+ {
+ Reference< XDispatch > xReturn;
+ if ( !GetWindow() )
+ {
+ OSL_FAIL( "ORichTextPeer::queryDispatch: already disposed?" );
+ return xReturn;
+ }
+
+ // is it a UNO slot?
+ static constexpr std::u16string_view sUnoProtocolPrefix( u".uno:" );
+ if ( _rURL.Complete.startsWith( sUnoProtocolPrefix ) )
+ {
+ OUString sUnoSlotName = _rURL.Complete.copy( sUnoProtocolPrefix.size() );
+ SfxSlotId nSlotId = lcl_getSlotFromUnoName( SfxSlotPool::GetSlotPool(), sUnoSlotName );
+ if ( nSlotId > 0 )
+ {
+ // do we already have a dispatcher for this?
+ AttributeDispatchers::const_iterator aDispatcherPos = m_aDispatchers.find( nSlotId );
+ if ( aDispatcherPos == m_aDispatchers.end() )
+ {
+ SingleAttributeDispatcher pDispatcher = implCreateDispatcher( nSlotId, _rURL );
+ if ( pDispatcher.is() )
+ {
+ aDispatcherPos = m_aDispatchers.emplace( nSlotId, pDispatcher ).first;
+ }
+ }
+
+ if ( aDispatcherPos != m_aDispatchers.end() )
+ xReturn = aDispatcherPos->second.get();
+ }
+ }
+
+ return xReturn;
+ }
+
+
+ Sequence< Reference< XDispatch > > SAL_CALL ORichTextPeer::queryDispatches( const Sequence< DispatchDescriptor >& _rRequests )
+ {
+ Sequence< Reference< XDispatch > > aReturn( _rRequests.getLength() );
+ Reference< XDispatch >* pReturn = aReturn.getArray();
+
+ const DispatchDescriptor* pRequest = _rRequests.getConstArray();
+ const DispatchDescriptor* pRequestEnd = pRequest + _rRequests.getLength();
+ for ( ; pRequest != pRequestEnd; ++pRequest, ++pReturn )
+ {
+ *pReturn = queryDispatch( pRequest->FeatureURL, pRequest->FrameName, pRequest->SearchFlags );
+ }
+ return aReturn;
+ }
+
+
+ void ORichTextPeer::onSelectionChanged()
+ {
+ AttributeDispatchers::iterator aDispatcherPos = m_aDispatchers.find( SID_COPY );
+ if ( aDispatcherPos != m_aDispatchers.end() )
+ aDispatcherPos->second->invalidate();
+
+ aDispatcherPos = m_aDispatchers.find( SID_CUT );
+ if ( aDispatcherPos != m_aDispatchers.end() )
+ aDispatcherPos->second->invalidate();
+ }
+
+
+} // namespace frm
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_form_ORichTextControl_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new frm::ORichTextControl());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextcontrol.hxx b/forms/source/richtext/richtextcontrol.hxx
new file mode 100644
index 000000000..9cda83bb5
--- /dev/null
+++ b/forms/source/richtext/richtextcontrol.hxx
@@ -0,0 +1,128 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <toolkit/controls/unocontrols.hxx>
+#include <toolkit/awt/vclxwindow.hxx>
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <rtl/ref.hxx>
+#include <tools/wintypes.hxx>
+#include "rtattributes.hxx"
+#include "textattributelistener.hxx"
+
+#include <map>
+
+
+namespace frm
+{
+
+ class ORichTextFeatureDispatcher;
+
+ typedef ::cppu::ImplHelper1 < css::frame::XDispatchProvider
+ > ORichTextControl_Base;
+ class ORichTextControl :public UnoEditControl
+ ,public ORichTextControl_Base
+ {
+ public:
+ ORichTextControl();
+
+ protected:
+ virtual ~ORichTextControl() override;
+
+ // UNO
+ DECLARE_UNO3_AGG_DEFAULTS( ORichTextControl, UnoEditControl )
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+
+ // XControl
+ virtual void SAL_CALL createPeer( const css::uno::Reference< css::awt::XToolkit >& _rToolkit, const css::uno::Reference< css::awt::XWindowPeer >& _rParent ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& _rURL, const OUString& _rTargetFrameName, sal_Int32 _rSearchFlags ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& Requests ) override;
+
+ // UnoControl
+ virtual bool requiresNewPeer( const OUString& _rPropertyName ) const override;
+ };
+
+ typedef ::cppu::ImplHelper1 < css::frame::XDispatchProvider
+ > ORichTextPeer_Base;
+ class ORichTextPeer final :public VCLXWindow
+ ,public ORichTextPeer_Base
+ ,public ITextSelectionListener
+ {
+ private:
+ typedef rtl::Reference<ORichTextFeatureDispatcher> SingleAttributeDispatcher;
+ typedef ::std::map< SfxSlotId, SingleAttributeDispatcher > AttributeDispatchers;
+ AttributeDispatchers m_aDispatchers;
+
+ public:
+ /** factory method
+ */
+ static rtl::Reference<ORichTextPeer> Create(
+ const css::uno::Reference< css::awt::XControlModel >& _rxModel,
+ vcl::Window* _pParentWindow,
+ WinBits _nStyle
+ );
+
+ // XInterface
+ DECLARE_XINTERFACE( )
+
+ private:
+ ORichTextPeer();
+ virtual ~ORichTextPeer() override;
+
+ // XView
+ void SAL_CALL draw( sal_Int32 nX, sal_Int32 nY ) override;
+
+ // XVclWindowPeer
+ virtual void SAL_CALL setProperty( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override;
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER( )
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+
+ // XDispatchProvider
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& _rURL, const OUString& _rTargetFrameName, sal_Int32 _rSearchFlags ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& Requests ) override;
+
+ // ITextSelectionListener
+ virtual void onSelectionChanged() override;
+
+ private:
+ SingleAttributeDispatcher implCreateDispatcher( SfxSlotId _nSlotId, const css::util::URL& _rURL );
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextengine.cxx b/forms/source/richtext/richtextengine.cxx
new file mode 100644
index 000000000..14f50a6fc
--- /dev/null
+++ b/forms/source/richtext/richtextengine.cxx
@@ -0,0 +1,138 @@
+/* -*- 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 .
+ */
+
+#include "richtextengine.hxx"
+#include <svl/itempool.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/langitem.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/mapunit.hxx>
+#include <vcl/mapmod.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <unotools/lingucfg.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+#include <memory>
+
+namespace frm
+{
+ //= RichTextEngine
+
+
+ RichTextEngine* RichTextEngine::Create()
+ {
+ SolarMutexGuard g;
+
+ rtl::Reference<SfxItemPool> pPool = EditEngine::CreatePool();
+ pPool->FreezeIdRanges();
+
+ RichTextEngine* pReturn = new RichTextEngine( pPool.get() );
+ OutputDevice* pOutputDevice = pReturn->GetRefDevice();
+ const MapMode& aDeviceMapMode( pOutputDevice->GetMapMode() );
+
+ pReturn->SetStatusEventHdl( LINK( pReturn, RichTextEngine, EditEngineStatusChanged ) );
+
+ pPool->SetDefaultMetric(aDeviceMapMode.GetMapUnit());
+
+ // defaults
+ vcl::Font aFont = Application::GetSettings().GetStyleSettings().GetAppFont();
+ aFont.SetFamilyName( "Times New Roman" );
+ pPool->SetPoolDefaultItem( SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(), OUString(), aFont.GetPitch(), aFont.GetCharSet(), EE_CHAR_FONTINFO ) );
+
+ // 12 pt font size
+ MapMode aPointMapMode( MapUnit::MapPoint );
+ Size a12PointSize( OutputDevice::LogicToLogic( Size( 12, 0 ), aPointMapMode, aDeviceMapMode ) );
+ pPool->SetPoolDefaultItem( SvxFontHeightItem( a12PointSize.Width(), 100, EE_CHAR_FONTHEIGHT ) );
+
+ // font languages
+ SvtLinguOptions aLinguOpt;
+ pPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOpt.nDefaultLanguage, EE_CHAR_LANGUAGE ) );
+ pPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOpt.nDefaultLanguage_CJK, EE_CHAR_LANGUAGE_CJK ) );
+ pPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOpt.nDefaultLanguage_CTL, EE_CHAR_LANGUAGE_CTL ) );
+
+ return pReturn;
+ }
+
+
+ RichTextEngine* RichTextEngine::Clone()
+ {
+ RichTextEngine* pClone( nullptr );
+ {
+ SolarMutexGuard aGuard;
+ std::unique_ptr<EditTextObject> pMyText(CreateTextObject());
+ OSL_ENSURE( pMyText, "RichTextEngine::Clone: CreateTextObject returned nonsense!" );
+
+ pClone = Create();
+
+ if ( pMyText )
+ pClone->SetText( *pMyText );
+ }
+
+ return pClone;
+ }
+
+
+ RichTextEngine::RichTextEngine( SfxItemPool* _pPool )
+ :EditEngine( _pPool )
+ {
+ }
+
+
+ RichTextEngine::~RichTextEngine( )
+ {
+ }
+
+
+ void RichTextEngine::registerEngineStatusListener( IEngineStatusListener* _pListener )
+ {
+ OSL_ENSURE( _pListener, "RichTextEngine::registerEngineStatusListener: invalid listener!" );
+ if ( _pListener )
+ m_aStatusListeners.push_back( _pListener );
+ }
+
+
+ void RichTextEngine::revokeEngineStatusListener( IEngineStatusListener const * _pListener )
+ {
+ ::std::vector< IEngineStatusListener* >::iterator aPos = ::std::find(
+ m_aStatusListeners.begin(),
+ m_aStatusListeners.end(),
+ _pListener
+ );
+ OSL_ENSURE( aPos != m_aStatusListeners.end(), "RichTextEngine::revokeEngineStatusListener: listener not registered!" );
+ if ( aPos != m_aStatusListeners.end() )
+ m_aStatusListeners.erase( aPos );
+ }
+
+
+ IMPL_LINK( RichTextEngine, EditEngineStatusChanged, EditStatus&, _rStatus, void )
+ {
+ for (auto const& statusListener : m_aStatusListeners)
+ statusListener->EditEngineStatusChanged( _rStatus );
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextengine.hxx b/forms/source/richtext/richtextengine.hxx
new file mode 100644
index 000000000..c9413e6bd
--- /dev/null
+++ b/forms/source/richtext/richtextengine.hxx
@@ -0,0 +1,71 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <editeng/editeng.hxx>
+#include <tools/link.hxx>
+
+#include <vector>
+
+class SfxItemPool;
+class EditStatus;
+
+namespace frm
+{
+
+ class IEngineStatusListener
+ {
+ public:
+ virtual void EditEngineStatusChanged( const EditStatus& _rStatus ) = 0;
+
+ protected:
+ ~IEngineStatusListener() {}
+ };
+
+ class RichTextEngine final : public EditEngine
+ {
+ private:
+ ::std::vector< IEngineStatusListener* > m_aStatusListeners;
+
+ public:
+ static RichTextEngine* Create();
+ RichTextEngine* Clone();
+
+ virtual ~RichTextEngine( ) override;
+
+ // for multiplexing the StatusChanged events of the edit engine
+ void registerEngineStatusListener( IEngineStatusListener* _pListener );
+ void revokeEngineStatusListener( IEngineStatusListener const * _pListener );
+
+ private:
+ /** constructs a new RichTextEngine. The instances takes the ownership of the given SfxItemPool
+ */
+ explicit RichTextEngine( SfxItemPool* _pPool );
+
+ RichTextEngine( const RichTextEngine& ) = delete;
+ RichTextEngine& operator=( const RichTextEngine& ) = delete;
+
+ DECL_LINK( EditEngineStatusChanged, EditStatus&, void );
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextimplcontrol.cxx b/forms/source/richtext/richtextimplcontrol.cxx
new file mode 100644
index 000000000..c51a3a877
--- /dev/null
+++ b/forms/source/richtext/richtextimplcontrol.cxx
@@ -0,0 +1,654 @@
+/* -*- 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 .
+ */
+
+#include "richtextimplcontrol.hxx"
+#include "textattributelistener.hxx"
+#include "richtextengine.hxx"
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <i18nlangtag/languagetag.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/editview.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/scripttypeitem.hxx>
+
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <tools/mapunit.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/commandevent.hxx>
+
+#define EMPTY_PAPER_SIZE 0x7FFFFFFF
+
+
+namespace frm
+{
+
+ RichTextControlImpl::RichTextControlImpl( Control* _pAntiImpl, RichTextEngine* _pEngine, ITextAttributeListener* _pTextAttrListener, ITextSelectionListener* _pSelectionListener )
+ :m_pAntiImpl ( _pAntiImpl )
+ ,m_pViewport ( nullptr )
+ ,m_pHScroll ( nullptr )
+ ,m_pVScroll ( nullptr )
+ ,m_pScrollCorner ( nullptr )
+ ,m_pEngine ( _pEngine )
+ ,m_pTextAttrListener ( _pTextAttrListener )
+ ,m_pSelectionListener ( _pSelectionListener )
+ ,m_bHasEverBeenShown ( false )
+ {
+ OSL_ENSURE( m_pAntiImpl, "RichTextControlImpl::RichTextControlImpl: invalid window!" );
+ OSL_ENSURE( m_pEngine, "RichTextControlImpl::RichTextControlImpl: invalid edit engine! This will *definitely* crash!" );
+
+ m_pViewport = VclPtr<RichTextViewPort>::Create( m_pAntiImpl );
+ m_pViewport->setAttributeInvalidationHandler( LINK( this, RichTextControlImpl, OnInvalidateAllAttributes ) );
+ m_pViewport->Show();
+
+ // ensure that both the window and the reference device have the same map unit
+ MapMode aRefDeviceMapMode( m_pEngine->GetRefDevice()->GetMapMode() );
+ m_pAntiImpl->SetMapMode( aRefDeviceMapMode );
+ m_pViewport->SetMapMode( aRefDeviceMapMode );
+
+ m_pView.reset(new EditView( m_pEngine, m_pViewport ));
+ m_pEngine->InsertView( m_pView.get() );
+ m_pViewport->setView( *m_pView );
+
+ m_pEngine->registerEngineStatusListener( this );
+
+ {
+ EVControlBits nViewControlWord = m_pView->GetControlWord();
+ nViewControlWord |= EVControlBits::AUTOSCROLL;
+ m_pView->SetControlWord( nViewControlWord );
+ }
+
+ // ensure that it's initially scrolled to the upper left
+ m_pView->SetVisArea( tools::Rectangle( Point( ), m_pViewport->GetOutDev()->GetOutputSize() ) );
+
+ ensureScrollbars();
+
+ m_pAntiImpl->SetBackground( Wallpaper( m_pAntiImpl->GetSettings().GetStyleSettings().GetFieldColor() ) );
+ }
+
+
+ RichTextControlImpl::~RichTextControlImpl( )
+ {
+ m_pEngine->RemoveView( m_pView.get() );
+ m_pEngine->revokeEngineStatusListener( this );
+ m_pView.reset();
+ m_pViewport.disposeAndClear();
+ m_pHScroll.disposeAndClear();
+ m_pVScroll.disposeAndClear();
+ m_pScrollCorner.disposeAndClear();
+ }
+
+
+ void RichTextControlImpl::implUpdateAttribute( const AttributeHandlerPool::const_iterator& _pHandler )
+ {
+ if ( ( _pHandler->first == sal_uInt16(SID_ATTR_CHAR_WEIGHT) )
+ || ( _pHandler->first == sal_uInt16(SID_ATTR_CHAR_POSTURE) )
+ || ( _pHandler->first == sal_uInt16(SID_ATTR_CHAR_FONT) )
+ || ( _pHandler->first == sal_uInt16(SID_ATTR_CHAR_FONTHEIGHT) )
+ )
+ {
+ // these are attributes whose value depends on the current script type.
+ // I.e., in real, there are *three* items in the ItemSet: One for each script
+ // type (Latin, Asian, Complex). However, if we have an observer who is interested
+ // in the state of this attribute, we have to kind of *merge* the three attributes
+ // to only one.
+ // This is useful in case the observer is for instance a toolbox which contains only
+ // an, e.g., "bold" slot, and thus not interested in the particular script type of the
+ // current selection.
+ SvxScriptSetItem aNormalizedSet( static_cast<WhichId>(_pHandler->first), *m_pView->GetAttribs().GetPool() );
+ normalizeScriptDependentAttribute( aNormalizedSet );
+
+ implCheckUpdateCache( _pHandler->first, _pHandler->second->getState( aNormalizedSet.GetItemSet() ) );
+ }
+ else
+ implCheckUpdateCache( _pHandler->first, _pHandler->second->getState( m_pView->GetAttribs() ) );
+ }
+
+
+ void RichTextControlImpl::updateAttribute( AttributeId _nAttribute )
+ {
+ AttributeHandlerPool::const_iterator pHandler = m_aAttributeHandlers.find( _nAttribute );
+ if ( pHandler != m_aAttributeHandlers.end() )
+ implUpdateAttribute( pHandler );
+ }
+
+
+ void RichTextControlImpl::updateAllAttributes( )
+ {
+ for ( AttributeHandlerPool::const_iterator pHandler = m_aAttributeHandlers.begin();
+ pHandler != m_aAttributeHandlers.end();
+ ++pHandler
+ )
+ {
+ implUpdateAttribute( pHandler );
+ }
+
+ // notify changes of the selection, if necessary
+ if ( m_pSelectionListener && m_pView )
+ {
+ ESelection aCurrentSelection = m_pView->GetSelection();
+ if ( aCurrentSelection != m_aLastKnownSelection )
+ {
+ m_aLastKnownSelection = aCurrentSelection;
+ m_pSelectionListener->onSelectionChanged();
+ }
+ }
+ }
+
+
+ AttributeState RichTextControlImpl::getAttributeState( AttributeId _nAttributeId ) const
+ {
+ StateCache::const_iterator aCachedStatePos = m_aLastKnownStates.find( _nAttributeId );
+ if ( aCachedStatePos == m_aLastKnownStates.end() )
+ {
+ OSL_FAIL( "RichTextControlImpl::getAttributeState: Don't ask for the state of an attribute which I never encountered!" );
+ return AttributeState( eIndetermined );
+ }
+ return aCachedStatePos->second;
+ }
+
+
+ bool RichTextControlImpl::executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rAttribs, AttributeId _nAttribute, const SfxPoolItem* _pArgument, SvtScriptType _nForScriptType )
+ {
+ // let's see whether we have a handler for this attribute
+ AttributeHandlerPool::const_iterator aHandlerPos = m_aAttributeHandlers.find( _nAttribute );
+ if ( aHandlerPos != m_aAttributeHandlers.end() )
+ {
+ aHandlerPos->second->executeAttribute( _rCurrentAttribs, _rAttribs, _pArgument, _nForScriptType );
+ return true;
+ }
+ return false;
+ }
+
+
+ void RichTextControlImpl::enableAttributeNotification( AttributeId _nAttributeId, ITextAttributeListener* _pListener )
+ {
+ AttributeHandlerPool::const_iterator aHandlerPos = m_aAttributeHandlers.find( _nAttributeId );
+ if ( aHandlerPos == m_aAttributeHandlers.end() )
+ {
+ ::rtl::Reference< AttributeHandler > aHandler = AttributeHandlerFactory::getHandlerFor( _nAttributeId, *m_pEngine->GetEmptyItemSet().GetPool() );
+ OSL_ENSURE( aHandler.is(), "RichTextControlImpl::enableAttributeNotification: no handler available for this attribute!" );
+ if ( !aHandler.is() )
+ return;
+ SAL_WARN_IF( _nAttributeId != aHandler->getAttributeId(), "forms.richtext", "RichTextControlImpl::enableAttributeNotification: suspicious handler!" );
+
+ aHandlerPos = m_aAttributeHandlers.emplace( _nAttributeId , aHandler ).first;
+ }
+
+ // remember the listener
+ if ( _pListener )
+ m_aAttributeListeners.emplace( _nAttributeId, _pListener );
+
+ // update (and broadcast) the state of this attribute
+ updateAttribute( _nAttributeId );
+ }
+
+
+ void RichTextControlImpl::disableAttributeNotification( AttributeId _nAttributeId )
+ {
+ // forget the handler for this attribute
+ AttributeHandlerPool::iterator aHandlerPos = m_aAttributeHandlers.find( _nAttributeId );
+ if ( aHandlerPos != m_aAttributeHandlers.end() )
+ m_aAttributeHandlers.erase( aHandlerPos );
+
+ // as well as the listener
+ AttributeListenerPool::iterator aListenerPos = m_aAttributeListeners.find( _nAttributeId );
+ if ( aListenerPos != m_aAttributeListeners.end() )
+ m_aAttributeListeners.erase( aListenerPos );
+ }
+
+
+ void RichTextControlImpl::normalizeScriptDependentAttribute( SvxScriptSetItem& _rScriptSetItem )
+ {
+ _rScriptSetItem.GetItemSet().Put( m_pView->GetAttribs(), false );
+ const SfxPoolItem* pNormalizedItem = _rScriptSetItem.GetItemOfScript( getSelectedScriptType() );
+
+ WhichId nNormalizedWhichId = _rScriptSetItem.GetItemSet().GetPool()->GetWhich( _rScriptSetItem.Which() );
+ if ( pNormalizedItem )
+ {
+ _rScriptSetItem.GetItemSet().Put( pNormalizedItem->CloneSetWhich(nNormalizedWhichId) );
+ }
+ else
+ _rScriptSetItem.GetItemSet().InvalidateItem( nNormalizedWhichId );
+ }
+
+
+ void RichTextControlImpl::implCheckUpdateCache( AttributeId _nAttribute, const AttributeState& _rState )
+ {
+ StateCache::iterator aCachePos = m_aLastKnownStates.find( _nAttribute );
+ if ( aCachePos == m_aLastKnownStates.end() )
+ { // nothing known about this attribute, yet
+ m_aLastKnownStates.emplace( _nAttribute, _rState );
+ }
+ else
+ {
+ if ( aCachePos->second == _rState )
+ {
+ // nothing to do
+ return;
+ }
+ aCachePos->second = _rState;
+ }
+
+ // is there a dedicated listener for this particular attribute?
+ AttributeListenerPool::const_iterator aListenerPos = m_aAttributeListeners.find( _nAttribute );
+ if ( aListenerPos != m_aAttributeListeners.end( ) )
+ aListenerPos->second->onAttributeStateChanged( _nAttribute );
+
+ // call our global listener, if there is one
+ if ( m_pTextAttrListener )
+ m_pTextAttrListener->onAttributeStateChanged( _nAttribute );
+ }
+
+
+ SvtScriptType RichTextControlImpl::getSelectedScriptType() const
+ {
+ SvtScriptType nScript = m_pView->GetSelectedScriptType();
+ if ( nScript == SvtScriptType::NONE )
+ nScript = SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+ return nScript;
+ }
+
+
+ void RichTextControlImpl::EditEngineStatusChanged( const EditStatus& _rStatus )
+ {
+ EditStatusFlags nStatusWord( _rStatus.GetStatusWord() );
+ if ( ( nStatusWord & EditStatusFlags::TEXTWIDTHCHANGED )
+ || ( nStatusWord & EditStatusFlags::TextHeightChanged )
+ )
+ {
+ if ( ( nStatusWord & EditStatusFlags::TextHeightChanged ) && windowHasAutomaticLineBreak() )
+ m_pEngine->SetPaperSize( Size( m_pEngine->GetPaperSize().Width(), m_pEngine->GetTextHeight() ) );
+
+ updateScrollbars();
+ }
+
+ bool bHScroll = bool( nStatusWord & EditStatusFlags::HSCROLL );
+ bool bVScroll = bool( nStatusWord & EditStatusFlags::VSCROLL );
+
+ // In case of *no* automatic line breaks, we also need to check for the *range* here.
+ // Normally, we would do this only after an EditStatusFlags::TEXTWIDTHCHANGED. However, due to a bug
+ // in the EditEngine (I believe so) this is not fired when the engine does not have
+ // the AutoPaperSize bits set.
+ // So in order to be properly notified, we would need the AutoPaperSize. But, with
+ // AutoPaperSize, other things do not work anymore: Either, when we set a MaxAutoPaperSize,
+ // then the view does automatic soft line breaks at the paper end - which we definitely do
+ // want. Or, if we did not set a MaxAutoPaperSize, then the view does not automatically scroll
+ // anymore in horizontal direction.
+ // So this is some kind of lose-lose situation ... :(
+ if ( !windowHasAutomaticLineBreak() && bHScroll )
+ {
+ updateScrollbars();
+ return;
+ }
+
+ if ( bHScroll && m_pHScroll )
+ m_pHScroll->SetThumbPos( m_pView->GetVisArea().Left() );
+ if ( bVScroll && m_pVScroll )
+ m_pVScroll->SetThumbPos( m_pView->GetVisArea().Top() );
+ }
+
+
+ IMPL_LINK_NOARG( RichTextControlImpl, OnInvalidateAllAttributes, LinkParamNone*, void )
+ {
+ updateAllAttributes();
+ }
+
+
+ IMPL_LINK( RichTextControlImpl, OnHScroll, ScrollBar*, _pScrollbar, void )
+ {
+ m_pView->Scroll( -_pScrollbar->GetDelta(), 0, ScrollRangeCheck::PaperWidthTextSize );
+ }
+
+
+ IMPL_LINK( RichTextControlImpl, OnVScroll, ScrollBar*, _pScrollbar, void )
+ {
+ m_pView->Scroll( 0, -_pScrollbar->GetDelta(), ScrollRangeCheck::PaperWidthTextSize );
+ }
+
+
+ void RichTextControlImpl::ensureScrollbars()
+ {
+ bool bNeedVScroll = 0 != ( m_pAntiImpl->GetStyle() & WB_VSCROLL );
+ bool bNeedHScroll = 0 != ( m_pAntiImpl->GetStyle() & WB_HSCROLL );
+
+ if ( ( bNeedVScroll == hasVScrollBar() ) && ( bNeedHScroll == hasHScrollBar( ) ) )
+ // nothing to do
+ return;
+
+ // create or delete the scrollbars, as necessary
+ if ( !bNeedVScroll )
+ {
+ m_pVScroll.disposeAndClear();
+ }
+ else
+ {
+ m_pVScroll = VclPtr<ScrollBar>::Create( m_pAntiImpl, WB_VSCROLL | WB_DRAG | WB_REPEAT );
+ m_pVScroll->SetScrollHdl ( LINK( this, RichTextControlImpl, OnVScroll ) );
+ m_pVScroll->Show();
+ }
+
+ if ( !bNeedHScroll )
+ {
+ m_pHScroll.disposeAndClear();
+ }
+ else
+ {
+ m_pHScroll = VclPtr<ScrollBar>::Create( m_pAntiImpl, WB_HSCROLL | WB_DRAG | WB_REPEAT );
+ m_pHScroll->SetScrollHdl ( LINK( this, RichTextControlImpl, OnHScroll ) );
+ m_pHScroll->Show();
+ }
+
+ if ( m_pHScroll && m_pVScroll )
+ {
+ m_pScrollCorner.disposeAndClear();
+ m_pScrollCorner = VclPtr<ScrollBarBox>::Create( m_pAntiImpl );
+ m_pScrollCorner->Show();
+ }
+ else
+ {
+ m_pScrollCorner.disposeAndClear();
+ }
+
+ layoutWindow();
+ }
+
+
+ void RichTextControlImpl::ensureLineBreakSetting()
+ {
+ if ( !windowHasAutomaticLineBreak() )
+ m_pEngine->SetPaperSize( Size( EMPTY_PAPER_SIZE, EMPTY_PAPER_SIZE ) );
+
+ layoutWindow();
+ }
+
+
+ void RichTextControlImpl::layoutWindow()
+ {
+ if ( !m_bHasEverBeenShown )
+ // no need to do anything. Especially, no need to set the paper size on the
+ // EditEngine to anything...
+ return;
+
+ const StyleSettings& rStyleSettings = m_pAntiImpl->GetSettings().GetStyleSettings();
+
+ tools::Long nScrollBarWidth = m_pVScroll ? rStyleSettings.GetScrollBarSize() : 0;
+ tools::Long nScrollBarHeight = m_pHScroll ? rStyleSettings.GetScrollBarSize() : 0;
+
+ if ( m_pAntiImpl->IsZoom() )
+ {
+ nScrollBarWidth = m_pAntiImpl->CalcZoom( nScrollBarWidth );
+ nScrollBarHeight = m_pAntiImpl->CalcZoom( nScrollBarHeight );
+ }
+
+ // the overall size we can use
+ Size aPlaygroundSizePixel( m_pAntiImpl->GetOutputSizePixel() );
+
+ // the size of the viewport - note that the viewport does *not* occupy all the place
+ // which is left when subtracting the scrollbar width/height
+ Size aViewportPlaygroundPixel( aPlaygroundSizePixel );
+ aViewportPlaygroundPixel.setWidth( ::std::max( tools::Long( 10 ), tools::Long( aViewportPlaygroundPixel.Width() - nScrollBarWidth ) ) );
+ aViewportPlaygroundPixel.setHeight( ::std::max( tools::Long( 10 ), tools::Long( aViewportPlaygroundPixel.Height() - nScrollBarHeight ) ) );
+ Size aViewportPlaygroundLogic( m_pViewport->PixelToLogic( aViewportPlaygroundPixel ) );
+
+ const tools::Long nOffset = 2;
+ Size aViewportSizePixel( aViewportPlaygroundPixel.Width() - 2 * nOffset, aViewportPlaygroundPixel.Height() - 2 * nOffset );
+ Size aViewportSizeLogic( m_pViewport->PixelToLogic( aViewportSizePixel ) );
+
+ // position the viewport
+ m_pViewport->SetPosSizePixel( Point( nOffset, nOffset ), aViewportSizePixel );
+ // position the scrollbars
+ if ( m_pVScroll )
+ m_pVScroll->SetPosSizePixel( Point( aViewportPlaygroundPixel.Width(), 0 ), Size( nScrollBarWidth, aViewportPlaygroundPixel.Height() ) );
+ if ( m_pHScroll )
+ m_pHScroll->SetPosSizePixel( Point( 0, aViewportPlaygroundPixel.Height() ), Size( aViewportPlaygroundPixel.Width(), nScrollBarHeight ) );
+ if ( m_pScrollCorner )
+ m_pScrollCorner->SetPosSizePixel( Point( aViewportPlaygroundPixel.Width(), aViewportPlaygroundPixel.Height() ), Size( nScrollBarWidth, nScrollBarHeight ) );
+
+ // paper size
+ if ( windowHasAutomaticLineBreak() )
+ m_pEngine->SetPaperSize( Size( aViewportSizeLogic.Width(), m_pEngine->GetTextHeight() ) );
+
+ // output area of the view
+ m_pView->SetOutputArea( tools::Rectangle( Point( ), aViewportSizeLogic ) );
+ m_pView->SetVisArea( tools::Rectangle( Point( ), aViewportSizeLogic ) );
+
+ if ( m_pVScroll )
+ {
+ m_pVScroll->SetVisibleSize( aViewportPlaygroundLogic.Height() );
+
+ // the default height of a text line...
+ tools::Long nFontHeight = m_pEngine->GetStandardFont(0).GetFontSize().Height();
+ // ... is the scroll size for the vertical scrollbar
+ m_pVScroll->SetLineSize( nFontHeight );
+ // the viewport width, minus one line, is the page scroll size
+ m_pVScroll->SetPageSize( ::std::max( nFontHeight, aViewportPlaygroundLogic.Height() - nFontHeight ) );
+ }
+
+ // the font width
+ if ( m_pHScroll )
+ {
+ m_pHScroll->SetVisibleSize( aViewportPlaygroundLogic.Width() );
+
+ tools::Long nFontWidth = m_pEngine->GetStandardFont(0).GetFontSize().Width();
+ if ( !nFontWidth )
+ {
+ m_pViewport->GetOutDev()->Push( vcl::PushFlags::FONT );
+ m_pViewport->SetFont( m_pEngine->GetStandardFont(0) );
+ nFontWidth = m_pViewport->GetTextWidth( "x" );
+ m_pViewport->GetOutDev()->Pop();
+ }
+ // ... is the scroll size for the horizontal scrollbar
+ m_pHScroll->SetLineSize( 5 * nFontWidth );
+ // the viewport height, minus one character, is the page scroll size
+ m_pHScroll->SetPageSize( ::std::max( nFontWidth, aViewportPlaygroundLogic.Width() - nFontWidth ) );
+ }
+
+ // update range and position of the scrollbars
+ updateScrollbars();
+ }
+
+
+ void RichTextControlImpl::updateScrollbars()
+ {
+ if ( m_pVScroll )
+ {
+ tools::Long nOverallTextHeight = m_pEngine->GetTextHeight();
+ m_pVScroll->SetRange( Range( 0, nOverallTextHeight ) );
+ m_pVScroll->SetThumbPos( m_pView->GetVisArea().Top() );
+ }
+
+ if ( m_pHScroll )
+ {
+ Size aPaperSize( m_pEngine->GetPaperSize() );
+ tools::Long nOverallTextWidth = ( aPaperSize.Width() == EMPTY_PAPER_SIZE ) ? m_pEngine->CalcTextWidth() : aPaperSize.Width();
+ m_pHScroll->SetRange( Range( 0, nOverallTextWidth ) );
+ m_pHScroll->SetThumbPos( m_pView->GetVisArea().Left() );
+ }
+ }
+
+
+ void RichTextControlImpl::notifyInitShow()
+ {
+ if ( !m_bHasEverBeenShown )
+ {
+ m_bHasEverBeenShown = true;
+ layoutWindow();
+ }
+ }
+
+
+ void RichTextControlImpl::notifyStyleChanged()
+ {
+ ensureScrollbars();
+ ensureLineBreakSetting();
+ }
+
+
+ void RichTextControlImpl::notifyZoomChanged()
+ {
+ const Fraction& rZoom = m_pAntiImpl->GetZoom();
+
+ MapMode aMapMode( m_pAntiImpl->GetMapMode() );
+ aMapMode.SetScaleX( rZoom );
+ aMapMode.SetScaleY( rZoom );
+ m_pAntiImpl->SetMapMode( aMapMode );
+
+ m_pViewport->SetZoom( rZoom );
+ m_pViewport->SetMapMode( aMapMode );
+
+ layoutWindow();
+ }
+
+
+ bool RichTextControlImpl::windowHasAutomaticLineBreak()
+ {
+ return ( m_pAntiImpl->GetStyle() & WB_WORDBREAK ) != 0;
+ }
+
+
+ void RichTextControlImpl::SetReadOnly( bool _bReadOnly )
+ {
+ m_pView->SetReadOnly( _bReadOnly );
+ }
+
+
+ bool RichTextControlImpl::IsReadOnly() const
+ {
+ return m_pView->IsReadOnly( );
+ }
+
+
+ namespace
+ {
+ void lcl_inflate( tools::Rectangle& _rRect, tools::Long _nInflateX, tools::Long _nInflateY )
+ {
+ _rRect.AdjustLeft( -_nInflateX );
+ _rRect.AdjustRight(_nInflateX );
+ _rRect.AdjustTop( -_nInflateY );
+ _rRect.AdjustBottom(_nInflateY );
+ }
+ }
+
+ bool RichTextControlImpl::HandleCommand( const CommandEvent& _rEvent )
+ {
+ if ( ( _rEvent.GetCommand() == CommandEventId::Wheel )
+ || ( _rEvent.GetCommand() == CommandEventId::StartAutoScroll )
+ || ( _rEvent.GetCommand() == CommandEventId::AutoScroll )
+ )
+ {
+ m_pAntiImpl->HandleScrollCommand( _rEvent, m_pHScroll, m_pVScroll );
+ return true;
+ }
+ return false;
+ }
+
+
+ void RichTextControlImpl::Draw( OutputDevice* _pDev, const Point& _rPos, const Size& _rSize )
+ {
+ // need to normalize the map mode of the device - every paint operation on any device needs
+ // to use the same map mode
+ _pDev->Push( vcl::PushFlags::MAPMODE | vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR );
+
+ // enforce our "normalize map mode" on the device
+ MapMode aRefMapMode( m_pEngine->GetRefDevice()->GetMapMode() );
+ MapMode aOriginalMapMode( _pDev->GetMapMode() );
+ MapMode aNormalizedMapMode( aRefMapMode.GetMapUnit(), aRefMapMode.GetOrigin(), aOriginalMapMode.GetScaleX(), aOriginalMapMode.GetScaleY() );
+ _pDev->SetMapMode( aNormalizedMapMode );
+
+ // translate coordinates
+ Point aPos( _rPos );
+ Size aSize( _rSize );
+ if ( aOriginalMapMode.GetMapUnit() == MapUnit::MapPixel )
+ {
+ aPos = _pDev->PixelToLogic( _rPos, aNormalizedMapMode );
+ aSize = _pDev->PixelToLogic( _rSize, aNormalizedMapMode );
+ }
+ else
+ {
+ aPos = OutputDevice::LogicToLogic( _rPos, aOriginalMapMode, aNormalizedMapMode );
+ aSize = OutputDevice::LogicToLogic( _rSize, aOriginalMapMode, aNormalizedMapMode );
+ }
+
+ tools::Rectangle aPlayground( aPos, aSize );
+ Size aOnePixel( _pDev->PixelToLogic( Size( 1, 1 ) ) );
+ aPlayground.AdjustRight( -(aOnePixel.Width()) );
+ aPlayground.AdjustBottom( -(aOnePixel.Height()) );
+
+ // background
+ _pDev->SetLineColor();
+ _pDev->DrawRect( aPlayground );
+
+ // do we need to draw a border?
+ bool bBorder = ( m_pAntiImpl->GetStyle() & WB_BORDER );
+ if ( bBorder )
+ _pDev->SetLineColor( m_pAntiImpl->GetSettings().GetStyleSettings().GetMonoColor() );
+ else
+ _pDev->SetLineColor();
+ _pDev->SetFillColor( m_pAntiImpl->GetBackground().GetColor() );
+ _pDev->DrawRect( aPlayground );
+
+ if ( bBorder )
+ // don't draw the text over the border
+ lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() );
+
+ // leave a space of two pixels between the "surroundings" of the control
+ // and the content
+ lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() );
+ lcl_inflate( aPlayground, -aOnePixel.Width(), -aOnePixel.Height() );
+
+ // actually draw the content
+ m_pEngine->Draw(*_pDev, aPlayground, Point(), true);
+
+ _pDev->Pop();
+ }
+
+
+ void RichTextControlImpl::SetBackgroundColor( )
+ {
+ SetBackgroundColor( Application::GetSettings().GetStyleSettings().GetFieldColor() );
+ }
+
+
+ void RichTextControlImpl::SetBackgroundColor( const Color& _rColor )
+ {
+ Wallpaper aWallpaper( _rColor );
+ m_pAntiImpl->SetBackground( aWallpaper );
+ m_pViewport->SetBackground( aWallpaper );
+ }
+
+
+ void RichTextControlImpl::SetHideInactiveSelection( bool _bHide )
+ {
+ m_pViewport->SetHideInactiveSelection( _bHide );
+ }
+
+
+ bool RichTextControlImpl::GetHideInactiveSelection() const
+ {
+ return m_pViewport->GetHideInactiveSelection( );
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextimplcontrol.hxx b/forms/source/richtext/richtextimplcontrol.hxx
new file mode 100644
index 000000000..d4fef2f66
--- /dev/null
+++ b/forms/source/richtext/richtextimplcontrol.hxx
@@ -0,0 +1,184 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "rtattributehandler.hxx"
+#include "richtextviewport.hxx"
+#include "richtextengine.hxx"
+#include <vcl/scrbar.hxx>
+#include <editeng/editdata.hxx>
+
+#include <map>
+
+class EditView;
+class EditStatus;
+namespace vcl { class Window; }
+class SvxScriptSetItem;
+
+namespace frm
+{
+
+
+ class ITextAttributeListener;
+ class ITextSelectionListener;
+ class RichTextViewPort;
+
+ class RichTextControlImpl : public IEngineStatusListener
+ {
+ typedef ::std::map< AttributeId, AttributeState > StateCache;
+ typedef ::std::map< AttributeId, ::rtl::Reference< AttributeHandler > > AttributeHandlerPool;
+ typedef ::std::map< AttributeId, ITextAttributeListener* > AttributeListenerPool;
+
+ StateCache m_aLastKnownStates;
+ AttributeHandlerPool m_aAttributeHandlers;
+ AttributeListenerPool m_aAttributeListeners;
+
+ ESelection m_aLastKnownSelection;
+
+ VclPtr<Control> m_pAntiImpl;
+ VclPtr<RichTextViewPort> m_pViewport;
+ VclPtr<ScrollBar> m_pHScroll;
+ VclPtr<ScrollBar> m_pVScroll;
+ VclPtr<ScrollBarBox> m_pScrollCorner;
+ RichTextEngine* m_pEngine;
+ std::unique_ptr<EditView> m_pView;
+ ITextAttributeListener* m_pTextAttrListener;
+ ITextSelectionListener* m_pSelectionListener;
+ bool m_bHasEverBeenShown;
+
+ public:
+ struct GrantAccess { friend class RichTextControl; private: GrantAccess() { } };
+ EditView* getView( const GrantAccess& ) const { return m_pView.get(); }
+ RichTextEngine* getEngine( const GrantAccess& ) const { return m_pEngine; }
+ vcl::Window* getViewport( const GrantAccess& ) const { return m_pViewport; }
+
+ public:
+ RichTextControlImpl( Control* _pAntiImpl, RichTextEngine* _pEngine,
+ ITextAttributeListener* _pTextAttrListener, ITextSelectionListener* _pSelectionListener );
+ virtual ~RichTextControlImpl();
+
+ /** updates the cache with the state of all attribute values from the given set, notifies
+ the listener if the state changed
+ */
+ void updateAllAttributes( );
+
+ /** updates the cache with the state of the attribute given by which id, notifies
+ the listener if the state changed
+ */
+ void updateAttribute( AttributeId _nAttribute );
+
+ /// enables the callback for a particular attribute
+ void enableAttributeNotification( AttributeId _nAttributeId, ITextAttributeListener* _pListener );
+
+ /// disables the change notifications for a particular attribute
+ void disableAttributeNotification( AttributeId _nAttributeId );
+
+ /// executes a toggle of the given attribute
+ bool executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, AttributeId _nAttribute, const SfxPoolItem* _pArgument, SvtScriptType _nForScriptType );
+
+ /// retrieves the state of the given attribute from the cache
+ AttributeState getAttributeState( AttributeId _nAttributeId ) const;
+
+ /** normalizes the given item so that the state of script dependent attributes
+ is correct considering the current script type
+
+ There are some attributes which are script dependent, e.g. the CharPosture. This means
+ that in real, there are 3 attributes for this, one for every possible script type (latin,
+ asian, complex). However, to the out world, we behave as if there is only one attribute:
+ E.g., if the outer world asks for the state of the "CharPosture" attribute, we return
+ the state of either CharPostureLatin, CharPostureAsian, or CharPostureComplex, depending
+ on the script type of the current selection. (In real, it may be more complex since
+ the current selection may contain more than one script type.)
+
+ This method normalizes a script dependent attribute, so that it's state takes into account
+ the currently selected script type.
+ */
+ void normalizeScriptDependentAttribute( SvxScriptSetItem& _rScriptSetItem );
+
+ // gets the script type of the selection in our edit view (with fallback)
+ SvtScriptType getSelectedScriptType() const;
+
+ /** re-arranges the view and the scrollbars
+ */
+ void layoutWindow();
+
+ /** to be called when the style of our window changed
+ */
+ void notifyStyleChanged();
+
+ /** to be called when the zoom of our window changed
+ */
+ void notifyZoomChanged();
+
+ /** to be called when the StateChangedType::InitShow event arrives
+ */
+ void notifyInitShow();
+
+ // VCL "overrides"
+ void SetBackgroundColor( );
+ void SetBackgroundColor( const Color& _rColor );
+
+ void SetReadOnly( bool _bReadOnly );
+ bool IsReadOnly() const;
+
+ void SetHideInactiveSelection( bool _bHide );
+ bool GetHideInactiveSelection() const;
+
+ /// draws the control onto a given output device
+ void Draw( OutputDevice* _pDev, const Point& _rPos, const Size& _rSize );
+
+ /// handles command events arrived at the anti-impl control
+ bool HandleCommand( const CommandEvent& _rEvent );
+
+ private:
+ // updates the cache with the state provided by the given attribute handler
+ void implUpdateAttribute( const AttributeHandlerPool::const_iterator& _pHandler );
+
+ // updates the cache with the given state, and calls listeners (if necessary)
+ void implCheckUpdateCache( AttributeId _nAttribute, const AttributeState& _rState );
+
+ // updates range and position of our scrollbars
+ void updateScrollbars();
+
+ // determines whether automatic (soft) line breaks are ON
+ bool windowHasAutomaticLineBreak();
+
+ /// hides or shows our scrollbars, according to the current WinBits of the window
+ void ensureScrollbars();
+
+ /// ensures that our "automatic line break" setting matches the current WinBits of the window
+ void ensureLineBreakSetting();
+
+ bool hasVScrollBar( ) const { return m_pVScroll != nullptr; }
+ bool hasHScrollBar( ) const { return m_pHScroll != nullptr; }
+
+ // IEngineStatusListener overridables
+ virtual void EditEngineStatusChanged( const EditStatus& _rStatus ) override;
+
+ private:
+ DECL_LINK( OnInvalidateAllAttributes, LinkParamNone*, void );
+ DECL_LINK( OnHScroll, ScrollBar*, void );
+ DECL_LINK( OnVScroll, ScrollBar*, void );
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextmodel.cxx b/forms/source/richtext/richtextmodel.cxx
new file mode 100644
index 000000000..9f4266be1
--- /dev/null
+++ b/forms/source/richtext/richtextmodel.cxx
@@ -0,0 +1,637 @@
+/* -*- 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 .
+ */
+
+#include "richtextmodel.hxx"
+#include "richtextengine.hxx"
+#include "richtextunowrapper.hxx"
+
+#include <property.hxx>
+#include <services.hxx>
+
+#include <com/sun/star/awt/LineEndFormat.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+
+#include <comphelper/guarding.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <editeng/editstat.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+
+
+namespace frm
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::io;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::style;
+
+ namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+
+ ORichTextModel::ORichTextModel( const Reference< XComponentContext >& _rxFactory )
+ :OControlModel ( _rxFactory, OUString() )
+ ,FontControlModel ( true )
+ ,m_pEngine ( RichTextEngine::Create() )
+ ,m_bSettingEngineText( false )
+ ,m_aModifyListeners ( m_aMutex )
+ {
+ m_nClassId = FormComponentType::TEXTFIELD;
+
+ getPropertyDefaultByHandle( PROPERTY_ID_DEFAULTCONTROL ) >>= m_sDefaultControl;
+ getPropertyDefaultByHandle( PROPERTY_ID_BORDER ) >>= m_nBorder;
+ getPropertyDefaultByHandle( PROPERTY_ID_ENABLED ) >>= m_bEnabled;
+ getPropertyDefaultByHandle( PROPERTY_ID_ENABLEVISIBLE ) >>= m_bEnableVisible;
+ getPropertyDefaultByHandle( PROPERTY_ID_HARDLINEBREAKS ) >>= m_bHardLineBreaks;
+ getPropertyDefaultByHandle( PROPERTY_ID_HSCROLL ) >>= m_bHScroll;
+ getPropertyDefaultByHandle( PROPERTY_ID_VSCROLL ) >>= m_bVScroll;
+ getPropertyDefaultByHandle( PROPERTY_ID_READONLY ) >>= m_bReadonly;
+ getPropertyDefaultByHandle( PROPERTY_ID_PRINTABLE ) >>= m_bPrintable;
+ m_aAlign = getPropertyDefaultByHandle( PROPERTY_ID_ALIGN );
+ getPropertyDefaultByHandle( PROPERTY_ID_ECHO_CHAR ) >>= m_nEchoChar;
+ getPropertyDefaultByHandle( PROPERTY_ID_MAXTEXTLEN ) >>= m_nMaxTextLength;
+ getPropertyDefaultByHandle( PROPERTY_ID_MULTILINE ) >>= m_bMultiLine;
+ getPropertyDefaultByHandle( PROPERTY_ID_RICH_TEXT ) >>= m_bReallyActAsRichText;
+ getPropertyDefaultByHandle( PROPERTY_ID_HIDEINACTIVESELECTION ) >>= m_bHideInactiveSelection;
+ getPropertyDefaultByHandle( PROPERTY_ID_LINEEND_FORMAT ) >>= m_nLineEndFormat;
+ getPropertyDefaultByHandle( PROPERTY_ID_WRITING_MODE ) >>= m_nTextWritingMode;
+ getPropertyDefaultByHandle( PROPERTY_ID_CONTEXT_WRITING_MODE ) >>= m_nContextWritingMode;
+
+ implInit();
+ }
+
+
+ ORichTextModel::ORichTextModel( const ORichTextModel* _pOriginal, const Reference< XComponentContext >& _rxFactory )
+ :OControlModel ( _pOriginal, _rxFactory, false )
+ ,FontControlModel ( _pOriginal )
+ ,m_bSettingEngineText( false )
+ ,m_aModifyListeners ( m_aMutex )
+ {
+
+ m_aTabStop = _pOriginal->m_aTabStop;
+ m_aBackgroundColor = _pOriginal->m_aBackgroundColor;
+ m_aBorderColor = _pOriginal->m_aBorderColor;
+ m_aVerticalAlignment = _pOriginal->m_aVerticalAlignment;
+ m_sDefaultControl = _pOriginal->m_sDefaultControl;
+ m_sHelpText = _pOriginal->m_sHelpText;
+ m_sHelpURL = _pOriginal->m_sHelpURL;
+ m_nBorder = _pOriginal->m_nBorder;
+ m_bEnabled = _pOriginal->m_bEnabled;
+ m_bEnableVisible = _pOriginal->m_bEnableVisible;
+ m_bHardLineBreaks = _pOriginal->m_bHardLineBreaks;
+ m_bHScroll = _pOriginal->m_bHScroll;
+ m_bVScroll = _pOriginal->m_bVScroll;
+ m_bReadonly = _pOriginal->m_bReadonly;
+ m_bPrintable = _pOriginal->m_bPrintable;
+ m_bReallyActAsRichText = _pOriginal->m_bReallyActAsRichText;
+ m_bHideInactiveSelection = _pOriginal->m_bHideInactiveSelection;
+ m_nLineEndFormat = _pOriginal->m_nLineEndFormat;
+ m_nTextWritingMode = _pOriginal->m_nTextWritingMode;
+ m_nContextWritingMode = _pOriginal->m_nContextWritingMode;
+
+ m_aAlign = _pOriginal->m_aAlign;
+ m_nEchoChar = _pOriginal->m_nEchoChar;
+ m_nMaxTextLength = _pOriginal->m_nMaxTextLength;
+ m_bMultiLine = _pOriginal->m_bMultiLine;
+
+ m_pEngine.reset(_pOriginal->m_pEngine->Clone());
+ m_sLastKnownEngineText = m_pEngine->GetText();
+
+ implInit();
+ }
+
+
+ void ORichTextModel::implInit()
+ {
+ OSL_ENSURE(m_pEngine, "ORichTextModel::implInit: where's the engine?");
+ if (m_pEngine)
+ {
+ m_pEngine->SetModifyHdl( LINK( this, ORichTextModel, OnEngineContentModified ) );
+
+ EEControlBits nEngineControlWord = m_pEngine->GetControlWord();
+ nEngineControlWord = nEngineControlWord & ~EEControlBits::AUTOPAGESIZE;
+ m_pEngine->SetControlWord( nEngineControlWord );
+
+ rtl::Reference<VCLXDevice> pUnoRefDevice = new VCLXDevice;
+ {
+ SolarMutexGuard g;
+ pUnoRefDevice->SetOutputDevice( m_pEngine->GetRefDevice() );
+ }
+ m_xReferenceDevice = pUnoRefDevice;
+ }
+
+ implDoAggregation();
+ implRegisterProperties();
+ }
+
+
+ void ORichTextModel::implDoAggregation()
+ {
+ osl_atomic_increment( &m_refCount );
+
+ {
+ m_xAggregate = new ORichTextUnoWrapper( *m_pEngine, this );
+ setAggregation( m_xAggregate );
+ doSetDelegator();
+ }
+
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ void ORichTextModel::implRegisterProperties()
+ {
+ registerProperty( PROPERTY_DEFAULTCONTROL, PROPERTY_ID_DEFAULTCONTROL, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_sDefaultControl, cppu::UnoType<decltype(m_sDefaultControl)>::get() );
+ registerProperty( PROPERTY_HELPTEXT, PROPERTY_ID_HELPTEXT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_sHelpText, cppu::UnoType<decltype(m_sHelpText)>::get() );
+ registerProperty( PROPERTY_HELPURL, PROPERTY_ID_HELPURL, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_sHelpURL, cppu::UnoType<decltype(m_sHelpURL)>::get() );
+ registerProperty( PROPERTY_ENABLED, PROPERTY_ID_ENABLED, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bEnabled, cppu::UnoType<decltype(m_bEnabled)>::get() );
+ registerProperty( PROPERTY_ENABLEVISIBLE, PROPERTY_ID_ENABLEVISIBLE, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bEnableVisible, cppu::UnoType<decltype(m_bEnableVisible)>::get() );
+ registerProperty( PROPERTY_BORDER, PROPERTY_ID_BORDER, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_nBorder, cppu::UnoType<decltype(m_nBorder)>::get() );
+ registerProperty( PROPERTY_HARDLINEBREAKS, PROPERTY_ID_HARDLINEBREAKS, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bHardLineBreaks, cppu::UnoType<decltype(m_bHardLineBreaks)>::get() );
+ registerProperty( PROPERTY_HSCROLL, PROPERTY_ID_HSCROLL, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bHScroll, cppu::UnoType<decltype(m_bHScroll)>::get() );
+ registerProperty( PROPERTY_VSCROLL, PROPERTY_ID_VSCROLL, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bVScroll, cppu::UnoType<decltype(m_bVScroll)>::get() );
+ registerProperty( PROPERTY_READONLY, PROPERTY_ID_READONLY, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bReadonly, cppu::UnoType<decltype(m_bReadonly)>::get() );
+ registerProperty( PROPERTY_PRINTABLE, PROPERTY_ID_PRINTABLE, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bPrintable, cppu::UnoType<decltype(m_bPrintable)>::get() );
+ registerProperty( PROPERTY_REFERENCE_DEVICE, PROPERTY_ID_REFERENCE_DEVICE, PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT,
+ &m_xReferenceDevice, cppu::UnoType<decltype(m_xReferenceDevice)>::get() );
+ registerProperty( PROPERTY_RICH_TEXT, PROPERTY_ID_RICH_TEXT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bReallyActAsRichText, cppu::UnoType<decltype(m_bReallyActAsRichText)>::get() );
+ registerProperty( PROPERTY_HIDEINACTIVESELECTION, PROPERTY_ID_HIDEINACTIVESELECTION, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bHideInactiveSelection, cppu::UnoType<decltype(m_bHideInactiveSelection)>::get() );
+
+ registerMayBeVoidProperty( PROPERTY_TABSTOP, PROPERTY_ID_TABSTOP, PropertyAttribute::MAYBEVOID | PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_aTabStop, cppu::UnoType<sal_Bool>::get() );
+ registerMayBeVoidProperty( PROPERTY_BACKGROUNDCOLOR, PROPERTY_ID_BACKGROUNDCOLOR, PropertyAttribute::MAYBEVOID | PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_aBackgroundColor, cppu::UnoType<sal_Int32>::get() );
+ registerMayBeVoidProperty( PROPERTY_BORDERCOLOR, PROPERTY_ID_BORDERCOLOR, PropertyAttribute::MAYBEVOID | PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_aBorderColor, cppu::UnoType<sal_Int32>::get() );
+ registerMayBeVoidProperty( PROPERTY_VERTICAL_ALIGN, PROPERTY_ID_VERTICAL_ALIGN, PropertyAttribute::MAYBEVOID | PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_aVerticalAlignment, cppu::UnoType<VerticalAlignment>::get() );
+
+ // properties which exist only for compatibility with the css.swt.UnoControlEditModel,
+ // since we replace the default implementation for this service
+ registerProperty( PROPERTY_ECHO_CHAR, PROPERTY_ID_ECHO_CHAR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_nEchoChar, cppu::UnoType<decltype(m_nEchoChar)>::get() );
+ registerProperty( PROPERTY_MAXTEXTLEN, PROPERTY_ID_MAXTEXTLEN, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_nMaxTextLength, cppu::UnoType<decltype(m_nMaxTextLength)>::get() );
+ registerProperty( PROPERTY_MULTILINE, PROPERTY_ID_MULTILINE, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_bMultiLine, cppu::UnoType<decltype(m_bMultiLine)>::get() );
+ registerProperty( PROPERTY_TEXT, PROPERTY_ID_TEXT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_sLastKnownEngineText, cppu::UnoType<decltype(m_sLastKnownEngineText)>::get() );
+ registerProperty( PROPERTY_LINEEND_FORMAT, PROPERTY_ID_LINEEND_FORMAT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_nLineEndFormat, cppu::UnoType<decltype(m_nLineEndFormat)>::get() );
+ registerProperty( PROPERTY_WRITING_MODE, PROPERTY_ID_WRITING_MODE, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_nTextWritingMode, cppu::UnoType<decltype(m_nTextWritingMode)>::get() );
+
+ registerProperty( PROPERTY_CONTEXT_WRITING_MODE, PROPERTY_ID_CONTEXT_WRITING_MODE, PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT |
+ PropertyAttribute::TRANSIENT, &m_nContextWritingMode, cppu::UnoType<decltype(m_nContextWritingMode)>::get() );
+
+ registerMayBeVoidProperty( PROPERTY_ALIGN, PROPERTY_ID_ALIGN, PropertyAttribute::MAYBEVOID | PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ &m_aAlign, cppu::UnoType<sal_Int16>::get() );
+ }
+
+
+ ORichTextModel::~ORichTextModel( )
+ {
+ if ( !OComponentHelper::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+ if (m_pEngine)
+ {
+ SolarMutexGuard g;
+ m_pEngine.reset();
+ }
+ }
+
+
+ Any SAL_CALL ORichTextModel::queryAggregation( const Type& _rType )
+ {
+ Any aReturn = ORichTextModel_BASE::queryInterface( _rType );
+
+ if ( !aReturn.hasValue() )
+ aReturn = OControlModel::queryAggregation( _rType );
+
+ return aReturn;
+ }
+
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( ORichTextModel, OControlModel, ORichTextModel_BASE )
+
+ OUString SAL_CALL ORichTextModel::getImplementationName()
+ {
+ return "com.sun.star.comp.forms.ORichTextModel";
+ }
+
+ Sequence< OUString > SAL_CALL ORichTextModel::getSupportedServiceNames()
+ {
+ Sequence< OUString > aOwnNames {
+ FRM_SUN_COMPONENT_RICHTEXTCONTROL,
+ "com.sun.star.text.TextRange",
+ "com.sun.star.style.CharacterProperties",
+ "com.sun.star.style.ParagraphProperties",
+ "com.sun.star.style.CharacterPropertiesAsian",
+ "com.sun.star.style.CharacterPropertiesComplex",
+ "com.sun.star.style.ParagraphPropertiesAsian",
+ "com.sun.star.style.ParagraphPropertiesComplex" };
+
+ return ::comphelper::combineSequences(
+ getAggregateServiceNames(),
+ ::comphelper::concatSequences(
+ OControlModel::getSupportedServiceNames_Static(),
+ aOwnNames)
+ );
+ }
+
+ css::uno::Reference< css::util::XCloneable > SAL_CALL ORichTextModel::createClone()
+{
+ rtl::Reference<ORichTextModel> pClone = new ORichTextModel(this, getContext());
+ pClone->clonedFrom(this);
+ return pClone;
+}
+
+
+ void SAL_CALL ORichTextModel::disposing()
+ {
+ m_aModifyListeners.disposeAndClear( EventObject( *this ) );
+ OControlModel::disposing();
+ }
+
+
+ namespace
+ {
+ void lcl_removeProperty( Sequence< Property >& _rSeq, std::u16string_view _rPropertyName )
+ {
+ Property* pLoop = _rSeq.getArray();
+ Property* pEnd = _rSeq.getArray() + _rSeq.getLength();
+ while ( pLoop != pEnd )
+ {
+ if ( pLoop->Name == _rPropertyName )
+ {
+ ::std::copy( pLoop + 1, pEnd, pLoop );
+ _rSeq.realloc( _rSeq.getLength() - 1 );
+ break;
+ }
+ ++pLoop;
+ }
+ }
+ }
+
+ void ORichTextModel::describeFixedProperties( Sequence< Property >& _rProps ) const
+ {
+ OControlModel::describeFixedProperties( _rProps );
+ sal_Int32 nOldCount = _rProps.getLength();
+ _rProps.realloc( nOldCount + 1);
+ css::beans::Property* pProperties = _rProps.getArray() + nOldCount;
+ *pProperties++ = css::beans::Property(PROPERTY_TABINDEX, PROPERTY_ID_TABINDEX, cppu::UnoType<sal_Int16>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::MAYBEDEFAULT);
+ DBG_ASSERT( pProperties == _rProps.getArray() + _rProps.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
+
+ // properties which the OPropertyContainerHelper is responsible for
+ Sequence< Property > aContainedProperties;
+ describeProperties( aContainedProperties );
+
+ // properties which the FontControlModel is responsible for
+ Sequence< Property > aFontProperties;
+ describeFontRelatedProperties( aFontProperties );
+
+ _rProps = concatSequences( aContainedProperties, aFontProperties, _rProps );
+ }
+
+
+ void ORichTextModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const
+ {
+ OControlModel::describeAggregateProperties( _rAggregateProps );
+
+ // our aggregate (the SvxUnoText) declares a FontDescriptor property, as does
+ // our FormControlFont base class. We remove it from the base class' sequence
+ // here, and later on care for both instances being in sync
+ lcl_removeProperty( _rAggregateProps, PROPERTY_FONT );
+
+ // similar, the WritingMode property is declared in our aggregate, too, but we override
+ // it, since the aggregate does no proper PropertyState handling.
+ lcl_removeProperty( _rAggregateProps, PROPERTY_WRITING_MODE );
+ }
+
+
+ void SAL_CALL ORichTextModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ if ( isRegisteredProperty( _nHandle ) )
+ {
+ OPropertyContainerHelper::getFastPropertyValue( _rValue, _nHandle );
+ }
+ else if ( isFontRelatedProperty( _nHandle ) )
+ {
+ FontControlModel::getFastPropertyValue( _rValue, _nHandle );
+ }
+ else
+ {
+ OControlModel::getFastPropertyValue( _rValue, _nHandle );
+ }
+ }
+
+
+ sal_Bool SAL_CALL ORichTextModel::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue )
+ {
+ bool bModified = false;
+
+ if ( isRegisteredProperty( _nHandle ) )
+ {
+ bModified = OPropertyContainerHelper::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue );
+ }
+ else if ( isFontRelatedProperty( _nHandle ) )
+ {
+ bModified = FontControlModel::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue );
+ }
+ else
+ {
+ bModified = OControlModel::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue );
+ }
+
+ return bModified;
+ }
+
+
+ void SAL_CALL ORichTextModel::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
+ {
+ if ( isRegisteredProperty( _nHandle ) )
+ {
+ OPropertyContainerHelper::setFastPropertyValue( _nHandle, _rValue );
+
+ switch ( _nHandle )
+ {
+ case PROPERTY_ID_REFERENCE_DEVICE:
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ MapMode aOldMapMode = m_pEngine->GetRefDevice()->GetMapMode();
+ #endif
+
+ OutputDevice* pRefDevice = VCLUnoHelper::GetOutputDevice( m_xReferenceDevice );
+ OSL_ENSURE( pRefDevice, "ORichTextModel::setFastPropertyValue_NoBroadcast: empty reference device?" );
+ m_pEngine->SetRefDevice( pRefDevice );
+
+ #if OSL_DEBUG_LEVEL > 0
+ MapMode aNewMapMode = m_pEngine->GetRefDevice()->GetMapMode();
+ OSL_ENSURE( aNewMapMode.GetMapUnit() == aOldMapMode.GetMapUnit(),
+ "ORichTextModel::setFastPropertyValue_NoBroadcast: You should not tamper with the MapUnit of the ref device!" );
+ // if this assertion here is triggered, then we would need to adjust all
+ // items in all text portions in all paragraphs in the attributes of the EditEngine,
+ // as long as they are MapUnit-dependent. This holds at least for the FontSize.
+ #endif
+ }
+ break;
+
+ case PROPERTY_ID_TEXT:
+ {
+ MutexRelease aReleaseMutex( m_aMutex );
+ impl_smlock_setEngineText( m_sLastKnownEngineText );
+ }
+ break;
+ } // switch ( _nHandle )
+ }
+ else if ( isFontRelatedProperty( _nHandle ) )
+ {
+ FontControlModel::setFastPropertyValue_NoBroadcast_impl(
+ *this, &ORichTextModel::setDependentFastPropertyValue,
+ _nHandle, _rValue);
+ }
+ else
+ {
+ switch ( _nHandle )
+ {
+ case PROPERTY_ID_WRITING_MODE:
+ {
+ // forward to our aggregate, so the EditEngine knows about it
+ if ( m_xAggregateSet.is() )
+ m_xAggregateSet->setPropertyValue( "WritingMode", _rValue );
+ }
+ break;
+
+ default:
+ OControlModel::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
+ break;
+ }
+ }
+ }
+
+
+ Any ORichTextModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
+ {
+ Any aDefault;
+
+ switch ( _nHandle )
+ {
+ case PROPERTY_ID_WRITING_MODE:
+ case PROPERTY_ID_CONTEXT_WRITING_MODE:
+ aDefault <<= WritingMode2::CONTEXT;
+ break;
+
+ case PROPERTY_ID_LINEEND_FORMAT:
+ aDefault <<= sal_Int16(LineEndFormat::LINE_FEED);
+ break;
+
+ case PROPERTY_ID_ECHO_CHAR:
+ case PROPERTY_ID_ALIGN:
+ case PROPERTY_ID_MAXTEXTLEN:
+ aDefault <<= sal_Int16(0);
+ break;
+
+ case PROPERTY_ID_TABSTOP:
+ case PROPERTY_ID_BACKGROUNDCOLOR:
+ case PROPERTY_ID_BORDERCOLOR:
+ case PROPERTY_ID_VERTICAL_ALIGN:
+ /* void */
+ break;
+
+ case PROPERTY_ID_ENABLED:
+ case PROPERTY_ID_ENABLEVISIBLE:
+ case PROPERTY_ID_PRINTABLE:
+ case PROPERTY_ID_HIDEINACTIVESELECTION:
+ aDefault <<= true;
+ break;
+
+ case PROPERTY_ID_HARDLINEBREAKS:
+ case PROPERTY_ID_HSCROLL:
+ case PROPERTY_ID_VSCROLL:
+ case PROPERTY_ID_READONLY:
+ case PROPERTY_ID_MULTILINE:
+ case PROPERTY_ID_RICH_TEXT:
+ aDefault <<= false;
+ break;
+
+ case PROPERTY_ID_DEFAULTCONTROL:
+ aDefault <<= OUString(FRM_SUN_CONTROL_RICHTEXTCONTROL);
+ break;
+
+ case PROPERTY_ID_HELPTEXT:
+ case PROPERTY_ID_HELPURL:
+ case PROPERTY_ID_TEXT:
+ aDefault <<= OUString();
+ break;
+
+ case PROPERTY_ID_BORDER:
+ aDefault <<= sal_Int16(1);
+ break;
+
+ default:
+ if ( isFontRelatedProperty( _nHandle ) )
+ aDefault = FontControlModel::getPropertyDefaultByHandle( _nHandle );
+ else
+ aDefault = OControlModel::getPropertyDefaultByHandle( _nHandle );
+ }
+
+ return aDefault;
+ }
+
+
+ void ORichTextModel::impl_smlock_setEngineText( const OUString& _rText )
+ {
+ if (m_pEngine)
+ {
+ SolarMutexGuard aSolarGuard;
+ m_bSettingEngineText = true;
+ m_pEngine->SetText( _rText );
+ m_bSettingEngineText = false;
+ }
+ }
+
+
+ OUString SAL_CALL ORichTextModel::getServiceName()
+ {
+ return FRM_SUN_COMPONENT_RICHTEXTCONTROL;
+ }
+
+
+ RichTextEngine* ORichTextModel::getEditEngine( const Reference< XControlModel >& _rxModel )
+ {
+ RichTextEngine* pEngine = nullptr;
+
+ Reference< XUnoTunnel > xTunnel( _rxModel, UNO_QUERY );
+ OSL_ENSURE( xTunnel.is(), "ORichTextModel::getEditEngine: invalid model!" );
+ if ( xTunnel.is() )
+ {
+ try
+ {
+ pEngine = comphelper::getSomething_cast<RichTextEngine>(xTunnel->getSomething(getUnoTunnelId()));
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "forms.richtext", "ORichTextModel::getEditEngine" );
+ }
+ }
+ return pEngine;
+ }
+
+
+ const Sequence<sal_Int8> & ORichTextModel::getUnoTunnelId()
+ {
+ static const comphelper::UnoIdInit aId;
+ return aId.getSeq();
+ }
+
+
+ IMPL_LINK_NOARG( ORichTextModel, OnEngineContentModified, LinkParamNone*, void )
+ {
+ if ( !m_bSettingEngineText )
+ {
+ m_aModifyListeners.notifyEach( &XModifyListener::modified, EventObject( *this ) );
+
+ potentialTextChange();
+ // is this a good idea? It may become expensive in case of larger texts,
+ // and this method here is called for every single changed character ...
+ // On the other hand, the API *requires* us to notify changes in the "Text"
+ // property immediately ...
+ }
+ }
+
+
+ sal_Int64 SAL_CALL ORichTextModel::getSomething( const Sequence< sal_Int8 >& _rId )
+ {
+ if (comphelper::isUnoTunnelId<ORichTextModel>(_rId))
+ return comphelper::getSomething_cast(m_pEngine.get()); // Note returning a different type
+
+ Reference< XUnoTunnel > xAggTunnel;
+ if ( query_aggregation( m_xAggregate, xAggTunnel ) )
+ return xAggTunnel->getSomething( _rId );
+
+ return 0;
+ }
+
+
+ void SAL_CALL ORichTextModel::addModifyListener( const Reference< XModifyListener >& _rxListener )
+ {
+ m_aModifyListeners.addInterface( _rxListener );
+ }
+
+
+ void SAL_CALL ORichTextModel::removeModifyListener( const Reference< XModifyListener >& _rxListener )
+ {
+ m_aModifyListeners.removeInterface( _rxListener );
+ }
+
+
+ void ORichTextModel::potentialTextChange( )
+ {
+ OUString sCurrentEngineText;
+ if (m_pEngine)
+ sCurrentEngineText = m_pEngine->GetText();
+
+ if ( sCurrentEngineText != m_sLastKnownEngineText )
+ {
+ sal_Int32 nHandle = PROPERTY_ID_TEXT;
+ Any aOldValue; aOldValue <<= m_sLastKnownEngineText;
+ Any aNewValue; aNewValue <<= sCurrentEngineText;
+ fire( &nHandle, &aNewValue, &aOldValue, 1, false );
+
+ m_sLastKnownEngineText = sCurrentEngineText;
+ }
+ }
+
+
+} // namespace frm
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_forms_ORichTextModel_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new frm::ORichTextModel(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextmodel.hxx b/forms/source/richtext/richtextmodel.hxx
new file mode 100644
index 000000000..cf0bae7db
--- /dev/null
+++ b/forms/source/richtext/richtextmodel.hxx
@@ -0,0 +1,186 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <FormComponent.hxx>
+#include <formcontrolfont.hxx>
+#include "richtextunowrapper.hxx"
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/propertycontainerhelper.hxx>
+
+#include <com/sun/star/awt/XDevice.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <cppuhelper/implbase3.hxx>
+#include <tools/link.hxx>
+#include <memory>
+
+class EditEngine;
+
+namespace frm
+{
+
+
+ class RichTextEngine;
+
+ //= ORichTextModel
+
+ typedef ::cppu::ImplHelper3 < css::awt::XControlModel
+ , css::lang::XUnoTunnel
+ , css::util::XModifyBroadcaster
+ > ORichTextModel_BASE;
+
+ class ORichTextModel
+ :public OControlModel
+ ,public FontControlModel
+ ,public IEngineTextChangeListener
+ ,public ::comphelper::OPropertyContainerHelper
+ ,public ORichTextModel_BASE
+ {
+ public:
+ ORichTextModel(
+ const css::uno::Reference< css::uno::XComponentContext>& _rxFactory
+ );
+ ORichTextModel(
+ const ORichTextModel* _pOriginal,
+ const css::uno::Reference< css::uno::XComponentContext>& _rxFactory
+ );
+ virtual ~ORichTextModel() override;
+
+ private:
+ // <properties>
+ css::uno::Reference< css::awt::XDevice >
+ m_xReferenceDevice;
+ css::uno::Any m_aTabStop;
+ css::uno::Any m_aBackgroundColor;
+ css::uno::Any m_aBorderColor;
+ css::uno::Any m_aVerticalAlignment;
+ OUString m_sDefaultControl;
+ OUString m_sHelpText;
+ OUString m_sHelpURL;
+ OUString m_sLastKnownEngineText;
+ sal_Int16 m_nLineEndFormat;
+ sal_Int16 m_nTextWritingMode;
+ sal_Int16 m_nContextWritingMode;
+ sal_Int16 m_nBorder;
+ bool m_bEnabled;
+ bool m_bEnableVisible;
+ bool m_bHardLineBreaks;
+ bool m_bHScroll;
+ bool m_bVScroll;
+ bool m_bReadonly;
+ bool m_bPrintable;
+ bool m_bReallyActAsRichText; // despite the class name, the RichTextControl later on
+ // will create "ordinary" text peers depending on this property
+ bool m_bHideInactiveSelection;
+ // </properties>
+
+ // <properties_for_awt_edit_compatibility>
+ css::uno::Any m_aAlign;
+ sal_Int16 m_nEchoChar;
+ sal_Int16 m_nMaxTextLength;
+ bool m_bMultiLine;
+ // </properties_for_awt_edit_compatibility>
+
+ ::std::unique_ptr<RichTextEngine>
+ m_pEngine;
+ bool m_bSettingEngineText;
+
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener>
+ m_aModifyListeners;
+
+ public:
+ static RichTextEngine* getEditEngine( const css::uno::Reference< css::awt::XControlModel >& _rxModel );
+
+ // UNO
+ DECLARE_UNO3_AGG_DEFAULTS( ORichTextModel, OControlModel )
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& _rType ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual ::css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPersistObject
+ virtual OUString SAL_CALL getServiceName() override;
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XCloneable
+ virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override;
+
+ // XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence<sal_Int8> & getUnoTunnelId();
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XPropertySet and friends
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(css::uno::Any& rConvertedValue, css::uno::Any& rOldValue,
+ sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any& rValue) override;
+ virtual css::uno::Any getPropertyDefaultByHandle( sal_Int32 nHandle ) const override;
+
+ // OControlModel's property handling
+ virtual void describeFixedProperties(
+ css::uno::Sequence< css::beans::Property >& /* [out] */ _rProps
+ ) const override;
+ virtual void describeAggregateProperties(
+ css::uno::Sequence< css::beans::Property >& /* [out] */ _rAggregateProps
+ ) const override;
+
+ // prevent method hiding
+ using OControlModel::disposing;
+ using OControlModel::getFastPropertyValue;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // IEngineTextChangeListener
+ virtual void potentialTextChange( ) override;
+
+ private:
+ void implInit();
+ void implDoAggregation();
+ void implRegisterProperties();
+
+ /** propagates a new text to the EditEngine
+
+ This method needs to lock the global solar mutex, so our own mutex must not
+ be locked when calling.
+
+ @precond
+ our mutex is not locked
+ */
+ void impl_smlock_setEngineText( const OUString& _rText );
+
+ DECL_LINK( OnEngineContentModified, LinkParamNone*, void );
+
+ private:
+ ORichTextModel( const ORichTextModel& ) = delete;
+ ORichTextModel& operator=( const ORichTextModel& ) = delete;
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextunowrapper.cxx b/forms/source/richtext/richtextunowrapper.cxx
new file mode 100644
index 000000000..d9c426921
--- /dev/null
+++ b/forms/source/richtext/richtextunowrapper.cxx
@@ -0,0 +1,117 @@
+/* -*- 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 .
+ */
+
+#include "richtextunowrapper.hxx"
+
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <editeng/unofored.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/unoipset.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <editeng/unoprnms.hxx>
+
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+
+
+ namespace
+ {
+ const SvxItemPropertySet* getTextEnginePropertySet()
+ {
+ // property map for an outliner text
+ static const SfxItemPropertyMapEntry aTextEnginePropertyMap[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ { u"TextUserDefinedAttributes", EE_CHAR_XMLATTRIBS, cppu::UnoType<XNameContainer>::get(), 0, 0 },
+ { u"ParaUserDefinedAttributes", EE_PARA_XMLATTRIBS, cppu::UnoType<XNameContainer>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SvxItemPropertySet aTextEnginePropertySet( aTextEnginePropertyMap, SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aTextEnginePropertySet;
+ }
+ }
+
+ ORichTextUnoWrapper::ORichTextUnoWrapper( EditEngine& _rEngine, IEngineTextChangeListener* _pTextChangeListener )
+ :SvxUnoText( getTextEnginePropertySet() )
+ {
+ SetEditSource( new RichTextEditSource( _rEngine, _pTextChangeListener ) );
+ }
+
+
+ ORichTextUnoWrapper::~ORichTextUnoWrapper() noexcept
+ {
+ }
+
+ RichTextEditSource::RichTextEditSource( EditEngine& _rEngine, IEngineTextChangeListener* _pTextChangeListener )
+ :m_rEngine ( _rEngine )
+ ,m_pTextForwarder ( new SvxEditEngineForwarder( _rEngine ) )
+ ,m_pTextChangeListener ( _pTextChangeListener )
+ {
+ }
+
+
+ RichTextEditSource::~RichTextEditSource()
+ {
+ }
+
+
+ std::unique_ptr<SvxEditSource> RichTextEditSource::Clone() const
+ {
+ return std::unique_ptr<SvxEditSource>(new RichTextEditSource( m_rEngine, m_pTextChangeListener ));
+ }
+
+
+ SvxTextForwarder* RichTextEditSource::GetTextForwarder()
+ {
+ return m_pTextForwarder.get();
+ }
+
+
+ void RichTextEditSource::UpdateData()
+ {
+ // this means that the content of the EditEngine changed via the UNO API
+ // to reflect this in the views, we need to update them
+ sal_uInt16 viewCount = m_rEngine.GetViewCount();
+ for ( sal_uInt16 view = 0; view < viewCount; ++view )
+ {
+ EditView* pView = m_rEngine.GetView( view );
+ if ( pView )
+ pView->ForceLayoutCalculation();
+ }
+
+ if ( m_pTextChangeListener )
+ m_pTextChangeListener->potentialTextChange();
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextunowrapper.hxx b/forms/source/richtext/richtextunowrapper.hxx
new file mode 100644
index 000000000..0acb3c53d
--- /dev/null
+++ b/forms/source/richtext/richtextunowrapper.hxx
@@ -0,0 +1,81 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <editeng/unotext.hxx>
+#include <editeng/unoedsrc.hxx>
+
+
+namespace frm
+{
+
+ class IEngineTextChangeListener
+ {
+ public:
+ virtual void potentialTextChange( ) = 0;
+
+ protected:
+ ~IEngineTextChangeListener() {}
+ };
+
+ class ORichTextUnoWrapper : public SvxUnoText
+ {
+ public:
+ ORichTextUnoWrapper( EditEngine& _rEngine, IEngineTextChangeListener* _pTextChangeListener );
+
+ protected:
+ virtual ~ORichTextUnoWrapper() noexcept override;
+
+
+ private:
+ ORichTextUnoWrapper( const ORichTextUnoWrapper& ) = delete;
+ ORichTextUnoWrapper& operator=( const ORichTextUnoWrapper& ) = delete;
+ };
+
+ class RichTextEditSource : public SvxEditSource
+ {
+ private:
+ EditEngine& m_rEngine;
+ std::unique_ptr<SvxTextForwarder>
+ m_pTextForwarder;
+ IEngineTextChangeListener* m_pTextChangeListener;
+
+ public:
+ RichTextEditSource( EditEngine& _rEngine, IEngineTextChangeListener* _pTextChangeListener );
+
+ // SvxEditSource
+ virtual std::unique_ptr<SvxEditSource> Clone() const override;
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual void UpdateData() override;
+
+ protected:
+ virtual ~RichTextEditSource() override;
+
+ private:
+ RichTextEditSource( const RichTextEditSource& _rSource ) = delete;
+ RichTextEditSource& operator=( const RichTextEditSource& ) = delete;
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextvclcontrol.cxx b/forms/source/richtext/richtextvclcontrol.cxx
new file mode 100644
index 000000000..cb4d613e3
--- /dev/null
+++ b/forms/source/richtext/richtextvclcontrol.cxx
@@ -0,0 +1,353 @@
+/* -*- 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 .
+ */
+
+#include "richtextvclcontrol.hxx"
+#include "richtextimplcontrol.hxx"
+#include <svl/itemset.hxx>
+#if OSL_DEBUG_LEVEL > 0
+ #include <unotools/ucbstreamhelper.hxx>
+ #include <sfx2/filedlghelper.hxx>
+ #include <tools/urlobj.hxx>
+ #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#endif
+#include <editeng/editeng.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editids.hrc>
+#include <svx/svxids.hrc>
+#include <osl/diagnose.h>
+#include <vcl/event.hxx>
+
+namespace frm
+{
+
+ RichTextControl::RichTextControl( RichTextEngine* _pEngine, vcl::Window* _pParent, WinBits _nStyle,
+ ITextAttributeListener* _pTextAttribListener, ITextSelectionListener* _pSelectionListener )
+ :Control( _pParent, implInitStyle( _nStyle ) )
+ {
+ implInit( _pEngine, _pTextAttribListener, _pSelectionListener );
+ }
+
+
+ void RichTextControl::implInit( RichTextEngine* _pEngine, ITextAttributeListener* _pTextAttribListener, ITextSelectionListener* _pSelectionListener )
+ {
+ m_pImpl.reset( new RichTextControlImpl( this, _pEngine, _pTextAttribListener, _pSelectionListener ) );
+ SetCompoundControl( true );
+ }
+
+
+ RichTextControl::~RichTextControl( )
+ {
+ disposeOnce();
+ }
+
+ void RichTextControl::dispose()
+ {
+ m_pImpl.reset();
+ Control::dispose();
+ }
+
+
+ AttributeState RichTextControl::getState( AttributeId _nAttributeId ) const
+ {
+ return m_pImpl->getAttributeState( _nAttributeId );
+ }
+
+
+ void RichTextControl::executeAttribute( AttributeId _nAttributeId, const SfxPoolItem* _pArgument )
+ {
+ SfxItemSet aToApplyAttributes( getView().GetEmptyItemSet() );
+ if ( !m_pImpl->executeAttribute( getView().GetAttribs(), aToApplyAttributes, _nAttributeId, _pArgument, m_pImpl->getSelectedScriptType() ) )
+ {
+ OSL_FAIL( "RichTextControl::executeAttribute: cannot handle the given attribute!" );
+ return;
+ }
+
+ applyAttributes( aToApplyAttributes );
+ }
+
+
+ void RichTextControl::applyAttributes( const SfxItemSet& _rAttributesToApply )
+ {
+ // apply
+ if ( HasChildPathFocus() )
+ getView().HideCursor();
+
+ // TODO: guard?
+ bool bOldUpdateMode = getEngine().SetUpdateLayout( false );
+
+ getView().SetAttribs( _rAttributesToApply );
+
+ getEngine().SetUpdateLayout( bOldUpdateMode );
+ getView().Invalidate();
+
+ if ( HasChildPathFocus() )
+ getView().ShowCursor();
+
+ m_pImpl->updateAllAttributes();
+ // TODO: maybe we should have a list of attributes which need to be updated
+ // (the handler for the just executed attribute should know)
+ }
+
+
+ void RichTextControl::enableAttributeNotification( AttributeId _nAttributeId, ITextAttributeListener* _pListener )
+ {
+ m_pImpl->enableAttributeNotification( _nAttributeId, _pListener );
+ }
+
+
+ void RichTextControl::disableAttributeNotification( AttributeId _nAttributeId )
+ {
+ m_pImpl->disableAttributeNotification( _nAttributeId );
+ }
+
+
+ bool RichTextControl::isMappableSlot( SfxSlotId _nSlotId )
+ {
+ switch ( _nSlotId )
+ {
+ case SID_ATTR_PARA_ADJUST_LEFT:
+ case SID_ATTR_PARA_ADJUST_CENTER:
+ case SID_ATTR_PARA_ADJUST_RIGHT:
+ case SID_ATTR_PARA_ADJUST_BLOCK:
+ case SID_SET_SUPER_SCRIPT:
+ case SID_SET_SUB_SCRIPT:
+ case SID_ATTR_PARA_LINESPACE_10:
+ case SID_ATTR_PARA_LINESPACE_15:
+ case SID_ATTR_PARA_LINESPACE_20:
+ case SID_ATTR_PARA_LEFT_TO_RIGHT:
+ case SID_ATTR_PARA_RIGHT_TO_LEFT:
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ case SID_ATTR_CHAR_LATIN_FONT:
+ case SID_ATTR_CHAR_LATIN_FONTHEIGHT:
+ case SID_ATTR_CHAR_LATIN_LANGUAGE:
+ case SID_ATTR_CHAR_LATIN_POSTURE:
+ case SID_ATTR_CHAR_LATIN_WEIGHT:
+ return true;
+ }
+ return false;
+ }
+
+
+ void RichTextControl::Resize()
+ {
+ m_pImpl->layoutWindow();
+ Invalidate();
+ }
+
+
+ void RichTextControl::GetFocus()
+ {
+ m_pImpl->getViewport( RichTextControlImpl::GrantAccess() )->GrabFocus();
+ }
+
+
+ WinBits RichTextControl::implInitStyle( WinBits nStyle )
+ {
+ if ( !( nStyle & WB_NOTABSTOP ) )
+ nStyle |= WB_TABSTOP;
+ return nStyle;
+ }
+
+
+ void RichTextControl::StateChanged( StateChangedType _nStateChange )
+ {
+ if ( _nStateChange == StateChangedType::Style )
+ {
+ SetStyle( implInitStyle( GetStyle() ) );
+ m_pImpl->notifyStyleChanged();
+ }
+ else if ( _nStateChange == StateChangedType::Zoom )
+ {
+ m_pImpl->notifyZoomChanged();
+ }
+ else if ( _nStateChange == StateChangedType::InitShow )
+ {
+ m_pImpl->notifyInitShow();
+ }
+ Control::StateChanged( _nStateChange );
+ }
+
+
+ bool RichTextControl::PreNotify( NotifyEvent& _rNEvt )
+ {
+ if ( IsWindowOrChild( _rNEvt.GetWindow() ) )
+ {
+ if ( MouseNotifyEvent::KEYINPUT == _rNEvt.GetType() )
+ {
+ const ::KeyEvent* pKeyEvent = _rNEvt.GetKeyEvent();
+
+ sal_uInt16 nCode = pKeyEvent->GetKeyCode().GetCode();
+ bool bShift = pKeyEvent->GetKeyCode().IsShift();
+ bool bCtrl = pKeyEvent->GetKeyCode().IsMod1();
+ bool bAlt = pKeyEvent->GetKeyCode().IsMod2();
+ if ( ( KEY_TAB == nCode ) && bCtrl && !bAlt )
+ {
+ // Ctrl-Tab is used to step out of the control
+ // -> build a new key event without the Ctrl-key, and let the very base class handle it
+ vcl::KeyCode aNewCode( KEY_TAB, bShift, false, false, false );
+ ::KeyEvent aNewEvent( pKeyEvent->GetCharCode(), aNewCode );
+ Control::KeyInput( aNewEvent );
+ return true; // handled
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ if ( ( ( KEY_F12 == nCode )
+ || ( KEY_F11 == nCode )
+ )
+ && bCtrl
+ && bAlt
+ )
+ {
+ bool bLoad = KEY_F11 == nCode;
+ static struct
+ {
+ const char* pDescription;
+ const char* pExtension;
+ EETextFormat eFormat;
+ } const aExportFormats[] =
+ {
+ { "OASIS OpenDocument (*.xml)", "*.xml", EETextFormat::Xml },
+ { "HyperText Markup Language (*.html)", "*.html", EETextFormat::Html },
+ { "Rich Text format (*.rtf)", "*.rtf", EETextFormat::Rtf },
+ { "Text (*.txt)", "*.txt", EETextFormat::Text }
+ };
+
+ ::sfx2::FileDialogHelper aFP( bLoad ? css::ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE : css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, FileDialogFlags::NONE, GetFrameWeld() );
+
+ for (auto & aExportFormat : aExportFormats)
+ {
+ aFP.AddFilter(
+ OUString::createFromAscii( aExportFormat.pDescription ),
+ OUString::createFromAscii( aExportFormat.pExtension ) );
+ }
+ ErrCode nResult = aFP.Execute();
+ if ( nResult == ERRCODE_NONE )
+ {
+ OUString sFileName = aFP.GetPath();
+ std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream(
+ sFileName, ( bLoad ? StreamMode::READ : StreamMode::WRITE | StreamMode::TRUNC ) | StreamMode::SHARE_DENYALL
+ );
+ if ( pStream )
+ {
+ EETextFormat eFormat = EETextFormat::Xml;
+ OUString sFilter = aFP.GetCurrentFilter();
+ for (auto & aExportFormat : aExportFormats)
+ {
+ if ( sFilter.equalsAscii( aExportFormat.pDescription ) )
+ {
+ eFormat = aExportFormat.eFormat;
+ break;
+ }
+ }
+ if ( bLoad )
+ {
+ INetURLObject aURL( sFileName );
+ aURL.removeSegment();
+ getEngine().Read( *pStream, aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), eFormat );
+ }
+ else
+ {
+ getEngine().Write( *pStream, eFormat );
+ }
+ }
+ }
+ return true; // handled
+ }
+#endif
+ }
+ }
+ return Control::PreNotify( _rNEvt );
+ }
+
+
+ bool RichTextControl::EventNotify( NotifyEvent& _rNEvt )
+ {
+ bool bDone = false;
+ if ( _rNEvt.GetType() == MouseNotifyEvent::COMMAND )
+ {
+ const CommandEvent& rEvent = *_rNEvt.GetCommandEvent();
+ bDone = m_pImpl->HandleCommand( rEvent );
+ }
+ return bDone || Control::EventNotify(_rNEvt);
+ }
+
+ void RichTextControl::Draw( OutputDevice* _pDev, const Point& _rPos, SystemTextColorFlags /*_nFlags*/ )
+ {
+ m_pImpl->Draw( _pDev, _rPos, _pDev->PixelToLogic(GetSizePixel()) );
+ }
+
+ EditView& RichTextControl::getView()
+ {
+ return *m_pImpl->getView( RichTextControlImpl::GrantAccess() );
+ }
+
+
+ const EditView& RichTextControl::getView() const
+ {
+ return *m_pImpl->getView( RichTextControlImpl::GrantAccess() );
+ }
+
+
+ EditEngine& RichTextControl::getEngine() const
+ {
+ return *m_pImpl->getEngine( RichTextControlImpl::GrantAccess() );
+ }
+
+
+ void RichTextControl::SetReadOnly( bool _bReadOnly )
+ {
+ m_pImpl->SetReadOnly( _bReadOnly );
+ }
+
+
+ bool RichTextControl::IsReadOnly() const
+ {
+ return m_pImpl->IsReadOnly();
+ }
+
+
+ void RichTextControl::SetBackgroundColor( )
+ {
+ m_pImpl->SetBackgroundColor( );
+ }
+
+
+ void RichTextControl::SetBackgroundColor( const Color& _rColor )
+ {
+ m_pImpl->SetBackgroundColor( _rColor );
+ }
+
+
+ void RichTextControl::SetHideInactiveSelection( bool _bHide )
+ {
+ m_pImpl->SetHideInactiveSelection( _bHide );
+ }
+
+
+ bool RichTextControl::GetHideInactiveSelection() const
+ {
+ return m_pImpl->GetHideInactiveSelection( );
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextvclcontrol.hxx b/forms/source/richtext/richtextvclcontrol.hxx
new file mode 100644
index 000000000..92d0c047d
--- /dev/null
+++ b/forms/source/richtext/richtextvclcontrol.hxx
@@ -0,0 +1,122 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <vcl/ctrl.hxx>
+#include "rtattributes.hxx"
+#include "textattributelistener.hxx"
+#include <memory>
+
+class EditView;
+class EditEngine;
+class SfxItemSet;
+
+namespace frm
+{
+
+ class RichTextControlImpl;
+ class RichTextEngine;
+
+ class RichTextControl : public Control, public IMultiAttributeDispatcher
+ {
+ private:
+ std::unique_ptr<RichTextControlImpl> m_pImpl;
+
+ public:
+ RichTextControl(
+ RichTextEngine* _pEngine,
+ vcl::Window* _pParent,
+ WinBits _nStyle,
+ ITextAttributeListener* _pTextAttribListener,
+ ITextSelectionListener* _pSelectionListener
+ );
+
+ virtual ~RichTextControl( ) override;
+ virtual void dispose() override;
+
+ /* enables the change notifications for a particular attribute
+
+ If you want to be notified of any changes in the state of an attribute, you need to call enableAttributeNotification.
+
+ If you provide a dedicated listener for this attribute, this listener is called for every change in the state of
+ the attribute.
+
+ No matter whether you provide such a dedicated listener, the "global" listener which you specified
+ in the constructor of the control is also called for all changes in the attribute state.
+
+ If you previously already enabled the notification for this attribute, and specified a different listener,
+ then the previous listener will be replaced with the new listener, provided the latter is not <NULL/>.
+ */
+ void enableAttributeNotification( AttributeId _nAttributeId, ITextAttributeListener* _pListener );
+
+ /** disables the change notifications for a particular attribute
+
+ If there was a listener dedicated to this attribute, it will not be referenced and used anymore
+ after this method had been called
+ */
+ void disableAttributeNotification( AttributeId _nAttributeId );
+
+ /** determines whether a given slot can be mapped to an aspect of an attribute of the EditEngine
+
+ E.g. SID_ATTR_PARA_ADJUST_LEFT can, though it's not part of the EditEngine pool, be mapped
+ to the SID_ATTR_PARA_ADJUST slot, which in fact *is* usable with the EditEngine.
+ */
+ static bool isMappableSlot( SfxSlotId _nSlotId );
+
+ // IMultiAttributeDispatcher
+ virtual AttributeState getState( AttributeId _nAttributeId ) const override;
+ virtual void executeAttribute( AttributeId _nAttributeId, const SfxPoolItem* _pArgument ) override;
+
+ void SetBackgroundColor( );
+ void SetBackgroundColor( const Color& _rColor );
+
+ void SetReadOnly( bool _bReadOnly );
+ bool IsReadOnly() const;
+
+ void SetHideInactiveSelection( bool _bHide );
+ bool GetHideInactiveSelection() const;
+
+ const EditView& getView() const;
+ EditView& getView();
+
+ // Window overridables
+ virtual void Draw( OutputDevice* _pDev, const Point& _rPos, SystemTextColorFlags _nFlags ) override;
+
+ protected:
+ // Window overridables
+ virtual void Resize() override;
+ virtual void GetFocus() override;
+ virtual void StateChanged( StateChangedType nStateChange ) override;
+ virtual bool PreNotify( NotifyEvent& _rNEvt ) override;
+ virtual bool EventNotify( NotifyEvent& _rNEvt ) override;
+
+ private:
+ void applyAttributes( const SfxItemSet& _rAttributesToApply );
+ void implInit( RichTextEngine* _pEngine, ITextAttributeListener* _pTextAttribListener, ITextSelectionListener* _pSelectionListener );
+ static WinBits implInitStyle( WinBits nStyle );
+
+ private:
+ EditEngine& getEngine() const;
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextviewport.cxx b/forms/source/richtext/richtextviewport.cxx
new file mode 100644
index 000000000..b4fda6652
--- /dev/null
+++ b/forms/source/richtext/richtextviewport.cxx
@@ -0,0 +1,102 @@
+/* -*- 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 .
+ */
+
+#include "richtextviewport.hxx"
+#include <editeng/editview.hxx>
+
+namespace frm
+{
+ RichTextViewPort::RichTextViewPort( vcl::Window* _pParent )
+ : Control ( _pParent )
+ , m_pView(nullptr)
+ , m_bHideInactiveSelection( true )
+ {
+ }
+
+ void RichTextViewPort::setView( EditView& _rView )
+ {
+ m_pView = &_rView;
+ SetPointer( _rView.GetPointer() );
+ }
+
+ void RichTextViewPort::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect )
+ {
+ m_pView->Paint(_rRect, &rRenderContext);
+ }
+
+ void RichTextViewPort::GetFocus()
+ {
+ Control::GetFocus();
+ if (m_pView)
+ {
+ m_pView->SetSelectionMode( EESelectionMode::Std );
+ m_pView->ShowCursor();
+ }
+ }
+
+ void RichTextViewPort::LoseFocus()
+ {
+ if (m_pView)
+ {
+ m_pView->HideCursor();
+ m_pView->SetSelectionMode( m_bHideInactiveSelection ? EESelectionMode::Hidden : EESelectionMode::Std );
+ }
+ Control::LoseFocus();
+ }
+
+ void RichTextViewPort::KeyInput( const KeyEvent& _rKEvt )
+ {
+ if ( !m_pView->PostKeyEvent( _rKEvt ) )
+ Control::KeyInput( _rKEvt );
+ else
+ implInvalidateAttributes();
+ }
+
+ void RichTextViewPort::MouseMove( const MouseEvent& _rMEvt )
+ {
+ Control::MouseMove( _rMEvt );
+ m_pView->MouseMove( _rMEvt );
+ }
+
+ void RichTextViewPort::MouseButtonDown( const MouseEvent& _rMEvt )
+ {
+ Control::MouseButtonDown( _rMEvt );
+ m_pView->MouseButtonDown( _rMEvt );
+ GrabFocus();
+ }
+
+ void RichTextViewPort::MouseButtonUp( const MouseEvent& _rMEvt )
+ {
+ Control::MouseButtonUp( _rMEvt );
+ m_pView->MouseButtonUp( _rMEvt );
+ implInvalidateAttributes();
+ }
+
+ void RichTextViewPort::SetHideInactiveSelection( bool _bHide )
+ {
+ if ( m_bHideInactiveSelection == _bHide )
+ return;
+ m_bHideInactiveSelection = _bHide;
+ if ( !HasFocus() )
+ m_pView->SetSelectionMode( m_bHideInactiveSelection ? EESelectionMode::Hidden : EESelectionMode::Std );
+ }
+
+} // namespace frm
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/richtextviewport.hxx b/forms/source/richtext/richtextviewport.hxx
new file mode 100644
index 000000000..90df8cb0b
--- /dev/null
+++ b/forms/source/richtext/richtextviewport.hxx
@@ -0,0 +1,64 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <vcl/ctrl.hxx>
+
+class EditView;
+
+namespace frm
+{
+ class RichTextViewPort : public Control
+ {
+ private:
+ EditView* m_pView;
+ Link<LinkParamNone*,void> m_aInvalidationHandler;
+ bool m_bHideInactiveSelection;
+
+ public:
+ explicit RichTextViewPort( vcl::Window* _pParent );
+
+ void setView( EditView& _rView );
+
+ void setAttributeInvalidationHandler( const Link<LinkParamNone*,void>& _rHandler ) { m_aInvalidationHandler = _rHandler; }
+
+ void SetHideInactiveSelection( bool _bHide );
+ bool GetHideInactiveSelection() const { return m_bHideInactiveSelection; }
+
+ protected:
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+ virtual void KeyInput( const KeyEvent& _rKEvt ) override;
+ virtual void MouseMove( const MouseEvent& _rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& _rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& _rMEvt ) override;
+
+ private:
+ void implInvalidateAttributes() const
+ {
+ m_aInvalidationHandler.Call( nullptr );
+ }
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/rtattributehandler.cxx b/forms/source/richtext/rtattributehandler.cxx
new file mode 100644
index 000000000..582b451a8
--- /dev/null
+++ b/forms/source/richtext/rtattributehandler.cxx
@@ -0,0 +1,441 @@
+/* -*- 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 .
+ */
+
+#include "rtattributehandler.hxx"
+
+#include <osl/diagnose.h>
+#include <svx/svxids.hrc>
+#include <editeng/eeitem.hxx>
+#include <svl/itemset.hxx>
+#include <svl/itempool.hxx>
+#include <tools/mapunit.hxx>
+#include <vcl/mapmod.hxx>
+#include <vcl/outdev.hxx>
+
+#include <editeng/adjustitem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/scripttypeitem.hxx>
+
+
+namespace frm
+{
+
+
+ AttributeHandler::AttributeHandler( AttributeId _nAttributeId, WhichId _nWhichId )
+ :m_nAttribute( _nAttributeId )
+ ,m_nWhich ( _nWhichId )
+ {
+ }
+
+
+ AttributeHandler::~AttributeHandler()
+ {
+ }
+
+
+ AttributeId AttributeHandler::getAttributeId( ) const
+ {
+ return getAttribute();
+ }
+
+
+ AttributeCheckState AttributeHandler::implGetCheckState( const SfxPoolItem& /*_rItem*/ ) const
+ {
+ OSL_FAIL( "AttributeHandler::implGetCheckState: not to be called!" );
+ return eIndetermined;
+ }
+
+
+ void AttributeHandler::putItemForScript( SfxItemSet& _rAttribs, const SfxPoolItem& _rItem, SvtScriptType _nForScriptType ) const
+ {
+ SvxScriptSetItem aSetItem( static_cast<WhichId>(getAttributeId()), *_rAttribs.GetPool() );
+ aSetItem.PutItemForScriptType( _nForScriptType, _rItem );
+ _rAttribs.Put( aSetItem.GetItemSet(), false );
+ }
+
+
+ AttributeCheckState AttributeHandler::getCheckState( const SfxItemSet& _rAttribs ) const
+ {
+ AttributeCheckState eSimpleState( eIndetermined );
+ const SfxPoolItem* pItem = _rAttribs.GetItem( getWhich() );
+ if ( pItem )
+ eSimpleState = implGetCheckState( *pItem );
+ return eSimpleState;
+ }
+
+
+ AttributeState AttributeHandler::getState( const SfxItemSet& _rAttribs ) const
+ {
+ AttributeState aState( eIndetermined );
+ aState.eSimpleState = getCheckState( _rAttribs );
+ return aState;
+ }
+
+
+ //= AttributeHandlerFactory
+
+
+ namespace
+ {
+ WhichId lcl_implGetWhich( const SfxItemPool& _rPool, AttributeId _nAttributeId )
+ {
+ WhichId nWhich = 0;
+ switch ( _nAttributeId )
+ {
+ case SID_ATTR_CHAR_LATIN_FONTHEIGHT:nWhich = EE_CHAR_FONTHEIGHT;break;
+ case SID_ATTR_CHAR_LATIN_FONT: nWhich = EE_CHAR_FONTINFO; break;
+ case SID_ATTR_CHAR_LATIN_LANGUAGE: nWhich = EE_CHAR_LANGUAGE; break;
+ case SID_ATTR_CHAR_LATIN_POSTURE: nWhich = EE_CHAR_ITALIC; break;
+ case SID_ATTR_CHAR_LATIN_WEIGHT: nWhich = EE_CHAR_WEIGHT; break;
+
+ default:
+ nWhich = _rPool.GetWhich( static_cast<SfxSlotId>(_nAttributeId) );
+ }
+ return nWhich;
+ }
+ }
+
+ ::rtl::Reference< AttributeHandler > AttributeHandlerFactory::getHandlerFor( AttributeId _nAttributeId, const SfxItemPool& _rEditEnginePool )
+ {
+ ::rtl::Reference< AttributeHandler > pReturn;
+ switch ( _nAttributeId )
+ {
+ case SID_ATTR_PARA_ADJUST_LEFT :
+ case SID_ATTR_PARA_ADJUST_CENTER:
+ case SID_ATTR_PARA_ADJUST_RIGHT :
+ case SID_ATTR_PARA_ADJUST_BLOCK :
+ pReturn = new ParaAlignmentHandler( _nAttributeId );
+ break;
+
+ case SID_ATTR_PARA_LINESPACE_10:
+ case SID_ATTR_PARA_LINESPACE_15:
+ case SID_ATTR_PARA_LINESPACE_20:
+ pReturn = new LineSpacingHandler( _nAttributeId );
+ break;
+
+ case SID_SET_SUPER_SCRIPT:
+ case SID_SET_SUB_SCRIPT:
+ pReturn = new EscapementHandler( _nAttributeId );
+ break;
+
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ case SID_ATTR_CHAR_CTL_FONTHEIGHT:
+ case SID_ATTR_CHAR_CJK_FONTHEIGHT:
+ case SID_ATTR_CHAR_LATIN_FONTHEIGHT:
+ pReturn = new FontSizeHandler( _nAttributeId, lcl_implGetWhich( _rEditEnginePool, _nAttributeId ) );
+ break;
+
+ case SID_ATTR_PARA_LEFT_TO_RIGHT:
+ case SID_ATTR_PARA_RIGHT_TO_LEFT:
+ pReturn = new ParagraphDirectionHandler( _nAttributeId );
+ break;
+
+ case SID_ATTR_PARA_HANGPUNCTUATION:
+ case SID_ATTR_PARA_FORBIDDEN_RULES:
+ case SID_ATTR_PARA_SCRIPTSPACE:
+ pReturn = new BooleanHandler( _nAttributeId, lcl_implGetWhich( _rEditEnginePool, _nAttributeId ) );
+ break;
+
+ default:
+ pReturn = new SlotHandler( static_cast<SfxSlotId>(_nAttributeId), lcl_implGetWhich( _rEditEnginePool, _nAttributeId ) );
+ break;
+
+ }
+
+ return pReturn;
+ }
+
+ ParaAlignmentHandler::ParaAlignmentHandler( AttributeId _nAttributeId )
+ :AttributeHandler( _nAttributeId, EE_PARA_JUST )
+ ,m_eAdjust( SvxAdjust::Center )
+ {
+ switch ( getAttribute() )
+ {
+ case SID_ATTR_PARA_ADJUST_LEFT : m_eAdjust = SvxAdjust::Left; break;
+ case SID_ATTR_PARA_ADJUST_CENTER: m_eAdjust = SvxAdjust::Center; break;
+ case SID_ATTR_PARA_ADJUST_RIGHT : m_eAdjust = SvxAdjust::Right; break;
+ case SID_ATTR_PARA_ADJUST_BLOCK : m_eAdjust = SvxAdjust::Block; break;
+ default:
+ OSL_FAIL( "ParaAlignmentHandler::ParaAlignmentHandler: invalid slot!" );
+ break;
+ }
+ }
+
+
+ AttributeCheckState ParaAlignmentHandler::implGetCheckState( const SfxPoolItem& _rItem ) const
+ {
+ assert( dynamic_cast<const SvxAdjustItem*>( &_rItem) && "ParaAlignmentHandler::implGetCheckState: invalid pool item!" );
+ SvxAdjust eAdjust = static_cast< const SvxAdjustItem& >( _rItem ).GetAdjust();
+ return ( eAdjust == m_eAdjust ) ? eChecked : eUnchecked;
+ }
+
+
+ void ParaAlignmentHandler::executeAttribute( const SfxItemSet& /*_rCurrentAttribs*/, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType /*_nForScriptType*/ ) const
+ {
+ OSL_ENSURE( !_pAdditionalArg, "ParaAlignmentHandler::executeAttribute: this is a simple toggle attribute - no args possible!" );
+ _rNewAttribs.Put( SvxAdjustItem( m_eAdjust, getWhich() ) );
+ }
+
+ LineSpacingHandler::LineSpacingHandler( AttributeId _nAttributeId )
+ :AttributeHandler( _nAttributeId, EE_PARA_SBL )
+ ,m_nLineSpace( 100 )
+ {
+ switch ( getAttribute() )
+ {
+ case SID_ATTR_PARA_LINESPACE_10: m_nLineSpace = 100; break;
+ case SID_ATTR_PARA_LINESPACE_15: m_nLineSpace = 150; break;
+ case SID_ATTR_PARA_LINESPACE_20: m_nLineSpace = 200; break;
+ default:
+ OSL_FAIL( "LineSpacingHandler::LineSpacingHandler: invalid slot!" );
+ break;
+ }
+ }
+
+
+ AttributeCheckState LineSpacingHandler::implGetCheckState( const SfxPoolItem& _rItem ) const
+ {
+ assert( dynamic_cast<const SvxLineSpacingItem*>( &_rItem) && "LineSpacingHandler::implGetCheckState: invalid pool item!" );
+ sal_uInt16 nLineSpace = static_cast< const SvxLineSpacingItem& >( _rItem ).GetPropLineSpace();
+ return ( nLineSpace == m_nLineSpace ) ? eChecked : eUnchecked;
+ }
+
+
+ void LineSpacingHandler::executeAttribute( const SfxItemSet& /*_rCurrentAttribs*/, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType /*_nForScriptType*/ ) const
+ {
+ OSL_ENSURE( !_pAdditionalArg, "LineSpacingHandler::executeAttribute: this is a simple toggle attribute - no args possible!" );
+
+ SvxLineSpacingItem aLineSpacing( m_nLineSpace, getWhich() );
+ aLineSpacing.SetLineSpaceRule( SvxLineSpaceRule::Auto );
+ if ( 100 == m_nLineSpace )
+ aLineSpacing.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
+ else
+ aLineSpacing.SetPropLineSpace( m_nLineSpace );
+
+ _rNewAttribs.Put( aLineSpacing );
+ }
+
+ EscapementHandler::EscapementHandler( AttributeId _nAttributeId )
+ :AttributeHandler( _nAttributeId, EE_CHAR_ESCAPEMENT )
+ ,m_eEscapement( SvxEscapement::Off )
+ {
+ switch ( getAttribute() )
+ {
+ case SID_SET_SUPER_SCRIPT : m_eEscapement = SvxEscapement::Superscript; break;
+ case SID_SET_SUB_SCRIPT : m_eEscapement = SvxEscapement::Subscript; break;
+ default:
+ OSL_FAIL( "EscapementHandler::EscapementHandler: invalid slot!" );
+ break;
+ }
+ }
+
+
+ AttributeCheckState EscapementHandler::implGetCheckState( const SfxPoolItem& _rItem ) const
+ {
+ assert( dynamic_cast<const SvxEscapementItem*>( &_rItem) && "EscapementHandler::getState: invalid pool item!" );
+ SvxEscapement eEscapement = static_cast< const SvxEscapementItem& >( _rItem ).GetEscapement();
+ return ( eEscapement == m_eEscapement ) ? eChecked : eUnchecked;
+ }
+
+
+ void EscapementHandler::executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType /*_nForScriptType*/ ) const {
+ OSL_ENSURE( !_pAdditionalArg, "EscapementHandler::executeAttribute: this is a simple toggle attribute - no args possible!" );
+ // well, in theory we could allow an SvxEscapementItem here, but this is not needed
+
+ bool bIsChecked = getCheckState( _rCurrentAttribs ) == eChecked;
+ _rNewAttribs.Put( SvxEscapementItem( bIsChecked ? SvxEscapement::Off : m_eEscapement, getWhich() ) );
+ }
+
+ SlotHandler::SlotHandler( AttributeId _nAttributeId, WhichId _nWhichId )
+ :AttributeHandler( _nAttributeId, _nWhichId )
+ ,m_bScriptDependent( false )
+ {
+ m_bScriptDependent = ( sal_uInt16(SID_ATTR_CHAR_WEIGHT) == _nAttributeId )
+ || ( sal_uInt16(SID_ATTR_CHAR_POSTURE) == _nAttributeId )
+ || ( sal_uInt16(SID_ATTR_CHAR_FONT) == _nAttributeId );
+ }
+
+
+ AttributeState SlotHandler::getState( const SfxItemSet& _rAttribs ) const
+ {
+ AttributeState aState( eIndetermined );
+
+ const SfxPoolItem* pItem = _rAttribs.GetItem( getWhich() );
+ if ( pItem )
+ aState.setItem( pItem );
+
+ return aState;
+ }
+
+
+ void SlotHandler::executeAttribute( const SfxItemSet& /*_rCurrentAttribs*/, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const
+ {
+ if ( _pAdditionalArg )
+ {
+ std::unique_ptr<SfxPoolItem> pCorrectWich(_pAdditionalArg->CloneSetWhich(getWhich()));
+
+ if ( m_bScriptDependent )
+ putItemForScript( _rNewAttribs, *pCorrectWich, _nForScriptType );
+ else
+ _rNewAttribs.Put( std::move(pCorrectWich) );
+ }
+ else
+ OSL_FAIL( "SlotHandler::executeAttribute: need attributes to do something!" );
+ }
+
+ FontSizeHandler::FontSizeHandler( AttributeId _nAttributeId, WhichId _nWhichId )
+ :AttributeHandler( _nAttributeId, _nWhichId )
+ {
+ OSL_ENSURE( ( _nAttributeId == SID_ATTR_CHAR_FONTHEIGHT ) || ( _nAttributeId == SID_ATTR_CHAR_CTL_FONTHEIGHT )
+ || ( _nAttributeId == SID_ATTR_CHAR_CJK_FONTHEIGHT ) || ( _nAttributeId == SID_ATTR_CHAR_LATIN_FONTHEIGHT ),
+ "FontSizeHandler::FontSizeHandler: invalid attribute id!" );
+ }
+
+
+ AttributeState FontSizeHandler::getState( const SfxItemSet& _rAttribs ) const
+ {
+ AttributeState aState( eIndetermined );
+
+ const SfxPoolItem* pItem = _rAttribs.GetItem( getWhich() );
+ const SvxFontHeightItem* pFontHeightItem = dynamic_cast<const SvxFontHeightItem*>( pItem );
+ OSL_ENSURE( pFontHeightItem || !pItem, "FontSizeHandler::getState: invalid item!" );
+ if ( pFontHeightItem )
+ {
+ // by definition, the item should have the unit twip
+ sal_uLong nHeight = pFontHeightItem->GetHeight();
+ if ( _rAttribs.GetPool()->GetMetric( getWhich() ) != MapUnit::MapTwip )
+ {
+ nHeight = OutputDevice::LogicToLogic(
+ Size( 0, nHeight ),
+ MapMode( _rAttribs.GetPool()->GetMetric( getWhich() ) ),
+ MapMode( MapUnit::MapTwip )
+ ).Height();
+ }
+
+ SvxFontHeightItem* pNewItem = new SvxFontHeightItem( nHeight, 100, getWhich() );
+ pNewItem->SetProp( pFontHeightItem->GetProp(), pFontHeightItem->GetPropUnit() );
+ aState.setItem( pNewItem );
+ }
+
+ return aState;
+ }
+
+
+ void FontSizeHandler::executeAttribute( const SfxItemSet& /*_rCurrentAttribs*/, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const
+ {
+ const SvxFontHeightItem* pFontHeightItem = dynamic_cast<const SvxFontHeightItem*>( _pAdditionalArg );
+ OSL_ENSURE( pFontHeightItem, "FontSizeHandler::executeAttribute: need a FontHeightItem!" );
+
+ if ( !pFontHeightItem )
+ return;
+
+ sal_uLong nHeight = pFontHeightItem->GetHeight();
+ if ( _rNewAttribs.GetPool()->GetMetric( getWhich() ) != MapUnit::MapTwip )
+ {
+ nHeight = OutputDevice::LogicToLogic(
+ Size( 0, nHeight ),
+ MapMode( MapUnit::MapTwip ),
+ MapMode( _rNewAttribs.GetPool()->GetMetric( getWhich() ) )
+ ).Height();
+ }
+
+ SvxFontHeightItem aNewItem( nHeight, 100, getWhich() );
+ aNewItem.SetProp( pFontHeightItem->GetProp(), pFontHeightItem->GetPropUnit() );
+
+ if ( ( getAttributeId() == SID_ATTR_CHAR_FONTHEIGHT ) && _nForScriptType != SvtScriptType::NONE)
+ putItemForScript( _rNewAttribs, aNewItem, _nForScriptType );
+ else
+ _rNewAttribs.Put( aNewItem );
+ }
+
+ ParagraphDirectionHandler::ParagraphDirectionHandler( AttributeId _nAttributeId )
+ :AttributeHandler( _nAttributeId, EE_PARA_WRITINGDIR )
+ ,m_eParagraphDirection( SvxFrameDirection::Horizontal_LR_TB )
+ ,m_eDefaultAdjustment( SvxAdjust::Right )
+ ,m_eOppositeDefaultAdjustment( SvxAdjust::Left )
+ {
+ switch ( getAttributeId() )
+ {
+ case SID_ATTR_PARA_LEFT_TO_RIGHT: m_eParagraphDirection = SvxFrameDirection::Horizontal_LR_TB; m_eDefaultAdjustment = SvxAdjust::Left; break;
+ case SID_ATTR_PARA_RIGHT_TO_LEFT: m_eParagraphDirection = SvxFrameDirection::Horizontal_RL_TB; m_eDefaultAdjustment = SvxAdjust::Right; break;
+ default:
+ OSL_FAIL( "ParagraphDirectionHandler::ParagraphDirectionHandler: invalid attribute id!" );
+ }
+
+ if ( SvxAdjust::Right == m_eDefaultAdjustment )
+ m_eOppositeDefaultAdjustment = SvxAdjust::Left;
+ else
+ m_eOppositeDefaultAdjustment = SvxAdjust::Right;
+ }
+
+
+ AttributeCheckState ParagraphDirectionHandler::implGetCheckState( const SfxPoolItem& _rItem ) const
+ {
+ assert( dynamic_cast<const SvxFrameDirectionItem*>( &_rItem) && "ParagraphDirectionHandler::implGetCheckState: invalid pool item!" );
+ SvxFrameDirection eDirection = static_cast< const SvxFrameDirectionItem& >( _rItem ).GetValue();
+ return ( eDirection == m_eParagraphDirection ) ? eChecked : eUnchecked;
+ }
+
+
+ void ParagraphDirectionHandler::executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* /*_pAdditionalArg*/, SvtScriptType /*_nForScriptType*/ ) const
+ {
+ _rNewAttribs.Put( SvxFrameDirectionItem( m_eParagraphDirection, getWhich() ) );
+
+ // if the current adjustment of the was the default adjustment for the *previous* text direction,
+ // then we toggle the adjustment, too
+ SvxAdjust eCurrentAdjustment = SvxAdjust::Left;
+ if ( const SvxAdjustItem* pCurrentAdjustment = _rCurrentAttribs.GetItemIfSet( EE_PARA_JUST ) )
+ eCurrentAdjustment = pCurrentAdjustment->GetAdjust();
+
+ if ( eCurrentAdjustment == m_eOppositeDefaultAdjustment )
+ _rNewAttribs.Put( SvxAdjustItem( m_eDefaultAdjustment, EE_PARA_JUST ) );
+ }
+
+ BooleanHandler::BooleanHandler( AttributeId _nAttributeId, WhichId _nWhichId )
+ :AttributeHandler( _nAttributeId, _nWhichId )
+ {
+ }
+
+
+ AttributeCheckState BooleanHandler::implGetCheckState( const SfxPoolItem& _rItem ) const
+ {
+ OSL_ENSURE( dynamic_cast<const SfxBoolItem*>( &_rItem) != nullptr, "BooleanHandler::implGetCheckState: invalid item!" );
+ if ( auto pBoolItem = dynamic_cast<const SfxBoolItem*>( &_rItem) )
+ return pBoolItem->GetValue() ? eChecked : eUnchecked;
+
+ return eIndetermined;
+ }
+
+
+ void BooleanHandler::executeAttribute( const SfxItemSet& /*_rCurrentAttribs*/, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType /*_nForScriptType*/ ) const
+ {
+ OSL_ENSURE( dynamic_cast<const SfxBoolItem*>( _pAdditionalArg) != nullptr, "BooleanHandler::executeAttribute: invalid argument!" );
+ if ( _pAdditionalArg )
+ {
+ _rNewAttribs.Put( _pAdditionalArg->CloneSetWhich(getWhich()) );
+ }
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/rtattributehandler.hxx b/forms/source/richtext/rtattributehandler.hxx
new file mode 100644
index 000000000..0f2badd64
--- /dev/null
+++ b/forms/source/richtext/rtattributehandler.hxx
@@ -0,0 +1,163 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "rtattributes.hxx"
+#include <rtl/ref.hxx>
+#include <svl/languageoptions.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/frmdir.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+class SfxItemSet;
+class SfxPoolItem;
+class SfxItemPool;
+
+namespace frm
+{
+
+ class AttributeHandler : public salhelper::SimpleReferenceObject
+ {
+ private:
+ AttributeId m_nAttribute;
+ WhichId m_nWhich;
+
+ protected:
+ AttributeId getAttribute() const { return m_nAttribute; }
+ WhichId getWhich() const { return m_nWhich; }
+
+ public:
+ AttributeHandler( AttributeId _nAttributeId, WhichId _nWhichId );
+
+ AttributeId getAttributeId( ) const;
+ virtual AttributeState getState( const SfxItemSet& _rAttribs ) const;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const = 0;
+
+ protected:
+ /// helper method calling implGetCheckState
+ AttributeCheckState getCheckState( const SfxItemSet& _rAttribs ) const;
+
+ /// helper method putting an item into a set, respecting a script type
+ void putItemForScript( SfxItemSet& _rAttribs, const SfxPoolItem& _rItem, SvtScriptType _nForScriptType ) const;
+
+ // pseudo-abstract
+ virtual AttributeCheckState implGetCheckState( const SfxPoolItem& _rItem ) const;
+
+ protected:
+ virtual ~AttributeHandler() override;
+ };
+
+ namespace AttributeHandlerFactory
+ {
+ ::rtl::Reference< AttributeHandler > getHandlerFor( AttributeId _nAttributeId, const SfxItemPool& _rEditEnginePool );
+ }
+
+ class ParaAlignmentHandler : public AttributeHandler
+ {
+ private:
+ SvxAdjust m_eAdjust;
+
+ public:
+ explicit ParaAlignmentHandler( AttributeId _nAttributeId );
+
+ public:
+ virtual AttributeCheckState implGetCheckState( const SfxPoolItem& _rItem ) const override;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const override;
+ };
+
+ class LineSpacingHandler : public AttributeHandler
+ {
+ private:
+ sal_uInt16 m_nLineSpace;
+
+ public:
+ explicit LineSpacingHandler( AttributeId _nAttributeId );
+
+ public:
+ virtual AttributeCheckState implGetCheckState( const SfxPoolItem& _rItem ) const override;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const override;
+ };
+
+ class EscapementHandler : public AttributeHandler
+ {
+ private:
+ SvxEscapement m_eEscapement;
+
+ public:
+ explicit EscapementHandler( AttributeId _nAttributeId );
+
+ public:
+ virtual AttributeCheckState implGetCheckState( const SfxPoolItem& _rItem ) const override;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const override;
+ };
+
+ class SlotHandler : public AttributeHandler
+ {
+ private:
+ bool m_bScriptDependent;
+
+ public:
+ SlotHandler( AttributeId _nAttributeId, WhichId _nWhichId );
+
+ public:
+ virtual AttributeState getState( const SfxItemSet& _rAttribs ) const override;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const override;
+ };
+
+ class BooleanHandler : public AttributeHandler
+ {
+ public:
+ BooleanHandler( AttributeId _nAttributeId, WhichId _nWhichId );
+
+ public:
+ virtual AttributeCheckState implGetCheckState( const SfxPoolItem& _rItem ) const override;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const override;
+ };
+
+ class FontSizeHandler : public AttributeHandler
+ {
+ public:
+ FontSizeHandler( AttributeId _nAttributeId, WhichId _nWhichId );
+
+ public:
+ virtual AttributeState getState( const SfxItemSet& _rAttribs ) const override;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const override;
+ };
+
+ class ParagraphDirectionHandler : public AttributeHandler
+ {
+ private:
+ SvxFrameDirection m_eParagraphDirection;
+ SvxAdjust m_eDefaultAdjustment;
+ SvxAdjust m_eOppositeDefaultAdjustment;
+
+ public:
+ explicit ParagraphDirectionHandler( AttributeId _nAttributeId );
+
+ public:
+ virtual AttributeCheckState implGetCheckState( const SfxPoolItem& _rItem ) const override;
+ virtual void executeAttribute( const SfxItemSet& _rCurrentAttribs, SfxItemSet& _rNewAttribs, const SfxPoolItem* _pAdditionalArg, SvtScriptType _nForScriptType ) const override;
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/rtattributes.hxx b/forms/source/richtext/rtattributes.hxx
new file mode 100644
index 000000000..b60ac6518
--- /dev/null
+++ b/forms/source/richtext/rtattributes.hxx
@@ -0,0 +1,130 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <svl/poolitem.hxx>
+
+namespace frm
+{
+
+ /// the id of an attribute
+ typedef sal_Int32 AttributeId;
+ /// the "which id" of an item in an SfxItemSet
+ typedef sal_uInt16 WhichId;
+ /// a SFX slot id
+ typedef sal_uInt16 SfxSlotId;
+
+ enum AttributeCheckState
+ {
+ eChecked,
+ eUnchecked,
+ eIndetermined
+ };
+
+ struct AttributeState
+ {
+ private:
+ std::unique_ptr<SfxPoolItem> pItemHandleItem;
+
+ public:
+ AttributeCheckState eSimpleState;
+
+ inline AttributeState( );
+ inline explicit AttributeState( AttributeCheckState _eCheckState );
+ inline AttributeState( const AttributeState& _rSource );
+
+ inline AttributeState& operator=( const AttributeState& _rSource );
+
+ inline bool operator==( const AttributeState& _rRHS );
+
+ inline const SfxPoolItem* getItem() const;
+ inline void setItem( const SfxPoolItem* _pItem );
+ };
+
+ inline AttributeState::AttributeState( )
+ :eSimpleState( eIndetermined )
+ {
+ }
+
+ inline AttributeState::AttributeState( AttributeCheckState _eCheckState )
+ :eSimpleState( _eCheckState )
+ {
+ }
+
+ inline AttributeState::AttributeState( const AttributeState& _rSource )
+ :eSimpleState( eIndetermined )
+ {
+ operator=( _rSource );
+ }
+
+ inline AttributeState& AttributeState::operator=( const AttributeState& _rSource )
+ {
+ if ( &_rSource == this )
+ return *this;
+
+ eSimpleState = _rSource.eSimpleState;
+ setItem( _rSource.getItem() );
+ return *this;
+ }
+
+ inline const SfxPoolItem* AttributeState::getItem() const
+ {
+ return pItemHandleItem.get();
+ }
+
+ inline void AttributeState::setItem( const SfxPoolItem* _pItem )
+ {
+ if ( _pItem )
+ pItemHandleItem.reset(_pItem->Clone());
+ else
+ pItemHandleItem.reset();
+ }
+
+ inline bool AttributeState::operator==( const AttributeState& _rRHS )
+ {
+ if ( eSimpleState != _rRHS.eSimpleState )
+ return false;
+
+ if ( pItemHandleItem && !_rRHS.pItemHandleItem )
+ return false;
+
+ if ( !pItemHandleItem && _rRHS.pItemHandleItem )
+ return false;
+
+ if ( pItemHandleItem == _rRHS.pItemHandleItem )
+ return true;
+
+ return *pItemHandleItem == *_rRHS.pItemHandleItem;
+ }
+
+ class IMultiAttributeDispatcher
+ {
+ public:
+ virtual AttributeState getState( AttributeId _nAttributeId ) const = 0;
+ virtual void executeAttribute( AttributeId _nAttributeId, const SfxPoolItem* _pArgument ) = 0;
+
+ protected:
+ ~IMultiAttributeDispatcher() {}
+ };
+
+} // namespace frm
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/specialdispatchers.cxx b/forms/source/richtext/specialdispatchers.cxx
new file mode 100644
index 000000000..db7ef6807
--- /dev/null
+++ b/forms/source/richtext/specialdispatchers.cxx
@@ -0,0 +1,171 @@
+/* -*- 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 .
+ */
+
+#include "specialdispatchers.hxx"
+#include <editeng/editeng.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/editview.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <osl/diagnose.h>
+
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::beans;
+
+ OSelectAllDispatcher::OSelectAllDispatcher( EditView& _rView, const URL& _rURL )
+ :ORichTextFeatureDispatcher( _rView, _rURL )
+ {
+ }
+
+
+ OSelectAllDispatcher::~OSelectAllDispatcher( )
+ {
+ if ( !isDisposed() )
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+
+ void SAL_CALL OSelectAllDispatcher::dispatch( const URL& _rURL, const Sequence< PropertyValue >& /*_rArguments*/ )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_ENSURE( _rURL.Complete == getFeatureURL().Complete, "OSelectAllDispatcher::dispatch: invalid URL!" );
+
+ checkDisposed();
+
+ EditEngine* pEngine = getEditView() ? getEditView()->GetEditEngine() : nullptr;
+ OSL_ENSURE( pEngine, "OSelectAllDispatcher::dispatch: no edit engine - but not yet disposed?" );
+ if ( !pEngine )
+ return;
+
+ sal_Int32 nParagraphs = pEngine->GetParagraphCount();
+ if ( nParagraphs )
+ {
+ sal_Int32 nLastParaNumber = nParagraphs - 1;
+ sal_Int32 nParaLen = pEngine->GetTextLen( nLastParaNumber );
+ getEditView()->SetSelection( ESelection( 0, 0, nLastParaNumber, nParaLen ) );
+ }
+ }
+
+
+ FeatureStateEvent OSelectAllDispatcher::buildStatusEvent() const
+ {
+ FeatureStateEvent aEvent( ORichTextFeatureDispatcher::buildStatusEvent() );
+ aEvent.IsEnabled = true;
+ return aEvent;
+ }
+
+ OParagraphDirectionDispatcher::OParagraphDirectionDispatcher( EditView& _rView, AttributeId _nAttributeId, const URL& _rURL,
+ IMultiAttributeDispatcher* _pMasterDispatcher )
+ :OAttributeDispatcher( _rView, _nAttributeId, _rURL, _pMasterDispatcher )
+ {
+ }
+
+
+ FeatureStateEvent OParagraphDirectionDispatcher::buildStatusEvent() const
+ {
+ FeatureStateEvent aEvent( OAttributeDispatcher::buildStatusEvent() );
+
+ EditEngine* pEngine = getEditView() ? getEditView()->GetEditEngine() : nullptr;
+ OSL_ENSURE( pEngine, "OParagraphDirectionDispatcher::dispatch: no edit engine - but not yet disposed?" );
+ if ( pEngine && pEngine->IsEffectivelyVertical() )
+ aEvent.IsEnabled = false;
+
+ return aEvent;
+ }
+
+ OTextDirectionDispatcher::OTextDirectionDispatcher( EditView& _rView, const URL& _rURL )
+ :ORichTextFeatureDispatcher( _rView, _rURL )
+ {
+ }
+
+
+ void SAL_CALL OTextDirectionDispatcher::dispatch( const URL& _rURL, const Sequence< PropertyValue >& /*_rArguments*/ )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OSL_ENSURE( _rURL.Complete == getFeatureURL().Complete, "OTextDirectionDispatcher::dispatch: invalid URL!" );
+
+ checkDisposed();
+
+ EditEngine* pEngine = getEditView() ? getEditView()->GetEditEngine() : nullptr;
+ OSL_ENSURE( pEngine, "OTextDirectionDispatcher::dispatch: no edit engine - but not yet disposed?" );
+ if ( !pEngine )
+ return;
+
+ pEngine->SetVertical( !pEngine->IsEffectivelyVertical() );
+ }
+
+
+ FeatureStateEvent OTextDirectionDispatcher::buildStatusEvent() const
+ {
+ FeatureStateEvent aEvent( ORichTextFeatureDispatcher::buildStatusEvent() );
+
+ EditEngine* pEngine = getEditView() ? getEditView()->GetEditEngine() : nullptr;
+ OSL_ENSURE( pEngine, "OTextDirectionDispatcher::dispatch: no edit engine - but not yet disposed?" );
+
+ aEvent.IsEnabled = true;
+ aEvent.State <<= pEngine && pEngine->IsEffectivelyVertical();
+
+ return aEvent;
+ }
+
+ OAsianFontLayoutDispatcher::OAsianFontLayoutDispatcher( EditView& _rView, AttributeId _nAttributeId, const URL& _rURL, IMultiAttributeDispatcher* _pMasterDispatcher )
+ :OParametrizedAttributeDispatcher( _rView, _nAttributeId, _rURL, _pMasterDispatcher )
+ {
+ }
+
+
+ const SfxPoolItem* OAsianFontLayoutDispatcher::convertDispatchArgsToItem( const Sequence< PropertyValue >& _rArguments )
+ {
+ // look for the "Enable" parameter
+ const PropertyValue* pLookup = _rArguments.getConstArray();
+ const PropertyValue* pLookupEnd = _rArguments.getConstArray() + _rArguments.getLength();
+ while ( pLookup != pLookupEnd )
+ {
+ if ( pLookup->Name == "Enable" )
+ break;
+ ++pLookup;
+ }
+ if ( pLookup != pLookupEnd )
+ {
+ bool bEnable = true;
+ OSL_VERIFY( pLookup->Value >>= bEnable );
+ if ( m_nAttributeId == SID_ATTR_PARA_SCRIPTSPACE )
+ return new SvxScriptSpaceItem( bEnable, static_cast<WhichId>(m_nAttributeId) );
+ return new SfxBoolItem( static_cast<WhichId>(m_nAttributeId), bEnable );
+ }
+
+ OSL_FAIL( "OAsianFontLayoutDispatcher::convertDispatchArgsToItem: did not find the one and only argument!" );
+ return nullptr;
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/specialdispatchers.hxx b/forms/source/richtext/specialdispatchers.hxx
new file mode 100644
index 000000000..9b4bfa1b7
--- /dev/null
+++ b/forms/source/richtext/specialdispatchers.hxx
@@ -0,0 +1,91 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "parametrizedattributedispatcher.hxx"
+
+
+namespace frm
+{
+
+ class OSelectAllDispatcher : public ORichTextFeatureDispatcher
+ {
+ public:
+ OSelectAllDispatcher( EditView& _rView, const css::util::URL& _rURL );
+
+ protected:
+ virtual ~OSelectAllDispatcher() override;
+
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // ORichTextFeatureDispatcher
+ virtual css::frame::FeatureStateEvent buildStatusEvent() const override;
+ };
+
+ class OParagraphDirectionDispatcher : public OAttributeDispatcher
+ {
+ public:
+ OParagraphDirectionDispatcher(
+ EditView& _rView,
+ AttributeId _nAttributeId,
+ const css::util::URL& _rURL,
+ IMultiAttributeDispatcher* _pMasterDispatcher
+ );
+
+ protected:
+ // ORichTextFeatureDispatcher
+ virtual css::frame::FeatureStateEvent buildStatusEvent() const override;
+ };
+
+ class OTextDirectionDispatcher : public ORichTextFeatureDispatcher
+ {
+ public:
+ OTextDirectionDispatcher( EditView& _rView, const css::util::URL& _rURL );
+
+ protected:
+ // XDispatch
+ virtual void SAL_CALL dispatch( const css::util::URL& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // ORichTextFeatureDispatcher
+ virtual css::frame::FeatureStateEvent buildStatusEvent() const override;
+ };
+
+ class OAsianFontLayoutDispatcher : public OParametrizedAttributeDispatcher
+ {
+ public:
+ OAsianFontLayoutDispatcher(
+ EditView& _rView,
+ AttributeId _nAttributeId,
+ const css::util::URL& _rURL,
+ IMultiAttributeDispatcher* _pMasterDispatcher
+ );
+
+ protected:
+ // OParametrizedAttributeDispatcher
+ virtual const SfxPoolItem* convertDispatchArgsToItem(
+ const css::uno::Sequence< css::beans::PropertyValue >& _rArguments ) override;
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/forms/source/richtext/textattributelistener.hxx b/forms/source/richtext/textattributelistener.hxx
new file mode 100644
index 000000000..3025d7b5d
--- /dev/null
+++ b/forms/source/richtext/textattributelistener.hxx
@@ -0,0 +1,53 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "rtattributes.hxx"
+
+struct ESelection;
+
+namespace frm
+{
+
+ class ITextAttributeListener
+ {
+ public:
+ virtual void onAttributeStateChanged( AttributeId _nAttributeId ) = 0;
+
+ protected:
+ ~ITextAttributeListener() {}
+ };
+
+
+ //= ITextAttributeListener
+
+ class ITextSelectionListener
+ {
+ public:
+ virtual void onSelectionChanged() = 0;
+
+ protected:
+ ~ITextSelectionListener() {}
+ };
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */